我有以下用kivy gui框架创建的简单应用程序。它不是最简单的,因为label_1有背景色,并且它的大小是根据标签的文本修改的。这是我第一次接触基维。不幸的是,kivy文档和大多数通过google访问的示例都大量使用kivy语言。我的问题是:如果只使用python 3,如果没有kivy语言,我如何获得相同的结果?
代码:
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()看上去如何:

发布于 2019-01-17 18:38:31
所需代码的实现是:
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()IMHO在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发布于 2019-01-17 19:36:07
另一种解决我的问题的方法--基于@eyllanesc的答案和奇维速成班录像的解决方案。我在这里发布它有两个原因:(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()看上去如何:

https://stackoverflow.com/questions/54240728
复制相似问题