Kivy 标签代码从 kivy 语言到 python
Kivy label code from kivy language to python
我有以下使用 kivy gui 框架创建的简单应用程序。这不是最简单的,因为 label_1
有背景色,而且它的大小是根据标签的文本修改的。这是我第一次接触 kivy。不幸的是,kivy 文档和大多数可通过 google 访问的示例大量使用 kivy 语言。我的问题是:如何在没有 kivy 语言的情况下仅使用 python 3 获得相同的结果?
代码:
from kivy.config import Config
from kivy.core.window import Window
from kivy.app import App
from kivy.lang import Builder
MainScreen = Builder.load_string('''
BoxLayout:
orientation: 'vertical'
Label:
text: 'label_1'
font_size: 18
color: (0, 0, 0, 1)
size_hint: None, None
size: self.texture_size
canvas.before:
Color:
rgba: 1, .5, 0, 1
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'label_2'
color: (0, 0, 0, 1)
''')
class MyApp(App):
def build(self):
return MainScreen
if __name__ == '__main__':
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
Window.clearcolor = (1, 1, 1, 1)
MyApp().run()
外观:
您需要的代码实现是:
from kivy.config import Config
from kivy.core.window import Window
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.graphics import Rectangle, Color
mainscreen = BoxLayout(orientation='vertical')
label1 = Label(text='label_1', font_size=18, color=(0, 0, 0, 1), size_hint=(None, None))
label1.bind(texture_size=label1.setter('size'))
def update_rect(instance, *args):
rect.pos = instance.pos
rect.size = instance.size
with label1.canvas.before:
Color(1, .5, 0, 1)
rect = Rectangle(pos=label1.pos, size=label1.size)
label1.bind(pos=update_rect, size=update_rect)
label2 = Label(text='label_2', color=(0, 0, 0, 1))
mainscreen.add_widget(label1)
mainscreen.add_widget(label2)
class MyApp(App):
def build(self):
return mainscreen
if __name__ == '__main__':
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
Window.clearcolor = (1, 1, 1, 1)
MyApp().run()
恕我直言,kv 中的实现在完成绑定时更具可读性和灵活性,就像适合大小的标签一样。
from kivy.config import Config
from kivy.core.window import Window
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.graphics import Rectangle, Color
from kivy.properties import ListProperty
class CustomLabel(Label):
bgcolor = ListProperty([0, 0, 0, 1])
def __init__(self, **kwargs):
if kwargs.get('bgcolor'):
self.bgcolor = kwargs['bgcolor']
kwargs.pop('bgcolor')
super(CustomLabel, self).__init__(**kwargs)
self.bind(texture_size=self.setter('size'))
with self.canvas.before:
self.p = Color(*self.bgcolor)
self.rect = Rectangle(pos=self.pos, size=self.size)
self.on_bgcolor()
self.bind(pos=self.geometry_bind, size=self.geometry_bind)
def on_bgcolor(self, *args):
self.p.rgba = self.bgcolor
def geometry_bind(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
class MyApp(App):
def build(self):
mainscreen = BoxLayout(orientation='vertical')
label1 = CustomLabel(text='label_1', font_size=18, color=(0, 0, 0, 1), size_hint=(None, None), bgcolor=(1, .5, 0, 1))
label2 = Label(text='label_2', color=(0, 0, 0, 1))
mainscreen.add_widget(label1)
mainscreen.add_widget(label2)
return mainscreen
if __name__ == '__main__':
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
Window.clearcolor = (1, 1, 1, 1)
MyApp().run()
解释:
bind
:bind(foo_property = callback)
函数负责调用foo_property变化时的回调。
setter
:setter('foo_property')
函数生成一个回调,允许您设置一个值。
如果同时加入两个函数:
class FooClass(Foo_EventDispatcher):
property_a = FooProperty(initial_value_a)
property_b = FooProperty(initial_value_b)
def __init__(self, **kwargs):
super(FooClass, self).__init__(**kwargs)
self.bind(property_a=self.setter('property_b'))
相当于.kv中的如下指令:
<FooClass>:
property_b: self.property_a
解决我的问题的另一种方法 - 基于@eyllanesc 的回答和 kivy crash course videos 的解决方案。我 post 在这里有两个原因:(1)使用这个版本可以清楚地看到发生了什么 - 背景实际绘制的方式和时间 - 没有另一个语法层(kivy 语言)并且没有 bind
和setter
这对我来说是全新的,(2) eyllanesc 提供了一些混乱的 python 代码。
代码:
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.graphics import Color, Rectangle
from kivy.app import App
class LabelWithBackground(Label):
def __init__(self, bgcolor, **kwargs):
super().__init__(**kwargs)
self.bgcolor = bgcolor
self.draw_background()
def draw_background(self):
if self.canvas is not None:
self.canvas.before.clear()
with self.canvas.before:
Color(*self.bgcolor)
Rectangle(pos=self.pos, size=self.size)
def on_size(self, *args):
self.draw_background()
def on_pos(self, *args):
self.size = self.texture_size
self.draw_background()
class MyApp2(App):
def __init__(self):
super().__init__()
self.layout = BoxLayout()
self.layout.orientation = 'vertical'
self.labels = [
Label(text='label_0', color=(0, 0, 0, 1)),
LabelWithBackground(text='label_1', color=(0, 0, 0, 1), size_hint=(.5, None), bgcolor=(1, .5, 0, 1)),
Label(text='label_2', color=(0, 0, 0, 1)),
LabelWithBackground(text='label_3', color=(0, 0, 0, 1), size_hint=(None, .25), bgcolor=(1, .5, 0, 1)),
Label(text='label_4', color=(0, 0, 0, 1)),
LabelWithBackground(text='label_5', color=(0, 0, 0, 1), size_hint=(None, None), bgcolor=(1, .5, 0, 1))]
for lbl in self.labels:
self.layout.add_widget(lbl)
def build(self):
return self.layout
if __name__ == '__main__':
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
Window.clearcolor = (1, 1, 1, 1)
MyApp2().run()
外观:
我有以下使用 kivy gui 框架创建的简单应用程序。这不是最简单的,因为 label_1
有背景色,而且它的大小是根据标签的文本修改的。这是我第一次接触 kivy。不幸的是,kivy 文档和大多数可通过 google 访问的示例大量使用 kivy 语言。我的问题是:如何在没有 kivy 语言的情况下仅使用 python 3 获得相同的结果?
代码:
from kivy.config import Config
from kivy.core.window import Window
from kivy.app import App
from kivy.lang import Builder
MainScreen = Builder.load_string('''
BoxLayout:
orientation: 'vertical'
Label:
text: 'label_1'
font_size: 18
color: (0, 0, 0, 1)
size_hint: None, None
size: self.texture_size
canvas.before:
Color:
rgba: 1, .5, 0, 1
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'label_2'
color: (0, 0, 0, 1)
''')
class MyApp(App):
def build(self):
return MainScreen
if __name__ == '__main__':
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
Window.clearcolor = (1, 1, 1, 1)
MyApp().run()
外观:
您需要的代码实现是:
from kivy.config import Config
from kivy.core.window import Window
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.graphics import Rectangle, Color
mainscreen = BoxLayout(orientation='vertical')
label1 = Label(text='label_1', font_size=18, color=(0, 0, 0, 1), size_hint=(None, None))
label1.bind(texture_size=label1.setter('size'))
def update_rect(instance, *args):
rect.pos = instance.pos
rect.size = instance.size
with label1.canvas.before:
Color(1, .5, 0, 1)
rect = Rectangle(pos=label1.pos, size=label1.size)
label1.bind(pos=update_rect, size=update_rect)
label2 = Label(text='label_2', color=(0, 0, 0, 1))
mainscreen.add_widget(label1)
mainscreen.add_widget(label2)
class MyApp(App):
def build(self):
return mainscreen
if __name__ == '__main__':
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
Window.clearcolor = (1, 1, 1, 1)
MyApp().run()
恕我直言,kv 中的实现在完成绑定时更具可读性和灵活性,就像适合大小的标签一样。
from kivy.config import Config
from kivy.core.window import Window
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.graphics import Rectangle, Color
from kivy.properties import ListProperty
class CustomLabel(Label):
bgcolor = ListProperty([0, 0, 0, 1])
def __init__(self, **kwargs):
if kwargs.get('bgcolor'):
self.bgcolor = kwargs['bgcolor']
kwargs.pop('bgcolor')
super(CustomLabel, self).__init__(**kwargs)
self.bind(texture_size=self.setter('size'))
with self.canvas.before:
self.p = Color(*self.bgcolor)
self.rect = Rectangle(pos=self.pos, size=self.size)
self.on_bgcolor()
self.bind(pos=self.geometry_bind, size=self.geometry_bind)
def on_bgcolor(self, *args):
self.p.rgba = self.bgcolor
def geometry_bind(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
class MyApp(App):
def build(self):
mainscreen = BoxLayout(orientation='vertical')
label1 = CustomLabel(text='label_1', font_size=18, color=(0, 0, 0, 1), size_hint=(None, None), bgcolor=(1, .5, 0, 1))
label2 = Label(text='label_2', color=(0, 0, 0, 1))
mainscreen.add_widget(label1)
mainscreen.add_widget(label2)
return mainscreen
if __name__ == '__main__':
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
Window.clearcolor = (1, 1, 1, 1)
MyApp().run()
解释:
bind
:bind(foo_property = callback)
函数负责调用foo_property变化时的回调。setter
:setter('foo_property')
函数生成一个回调,允许您设置一个值。
如果同时加入两个函数:
class FooClass(Foo_EventDispatcher):
property_a = FooProperty(initial_value_a)
property_b = FooProperty(initial_value_b)
def __init__(self, **kwargs):
super(FooClass, self).__init__(**kwargs)
self.bind(property_a=self.setter('property_b'))
相当于.kv中的如下指令:
<FooClass>:
property_b: self.property_a
解决我的问题的另一种方法 - 基于@eyllanesc 的回答和 kivy crash course videos 的解决方案。我 post 在这里有两个原因:(1)使用这个版本可以清楚地看到发生了什么 - 背景实际绘制的方式和时间 - 没有另一个语法层(kivy 语言)并且没有 bind
和setter
这对我来说是全新的,(2) eyllanesc 提供了一些混乱的 python 代码。
代码:
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.graphics import Color, Rectangle
from kivy.app import App
class LabelWithBackground(Label):
def __init__(self, bgcolor, **kwargs):
super().__init__(**kwargs)
self.bgcolor = bgcolor
self.draw_background()
def draw_background(self):
if self.canvas is not None:
self.canvas.before.clear()
with self.canvas.before:
Color(*self.bgcolor)
Rectangle(pos=self.pos, size=self.size)
def on_size(self, *args):
self.draw_background()
def on_pos(self, *args):
self.size = self.texture_size
self.draw_background()
class MyApp2(App):
def __init__(self):
super().__init__()
self.layout = BoxLayout()
self.layout.orientation = 'vertical'
self.labels = [
Label(text='label_0', color=(0, 0, 0, 1)),
LabelWithBackground(text='label_1', color=(0, 0, 0, 1), size_hint=(.5, None), bgcolor=(1, .5, 0, 1)),
Label(text='label_2', color=(0, 0, 0, 1)),
LabelWithBackground(text='label_3', color=(0, 0, 0, 1), size_hint=(None, .25), bgcolor=(1, .5, 0, 1)),
Label(text='label_4', color=(0, 0, 0, 1)),
LabelWithBackground(text='label_5', color=(0, 0, 0, 1), size_hint=(None, None), bgcolor=(1, .5, 0, 1))]
for lbl in self.labels:
self.layout.add_widget(lbl)
def build(self):
return self.layout
if __name__ == '__main__':
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
Window.clearcolor = (1, 1, 1, 1)
MyApp2().run()
外观: