【问题标题】:Kivy label code from kivy language to python从kivy语言到python的kivy标签代码
【发布时间】:2019-01-17 16:54:07
【问题描述】:

我有以下使用 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()

外观:

【问题讨论】:

    标签: python python-3.x kivy kivy-language


    【解决方案1】:

    您需要的代码的实现是:

    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()
    

    说明:

    • bindbind(foo_property = callback) 函数负责在 foo_property 发生变化时调用回调。

    • settersetter('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
    

    【讨论】:

    • 感谢您的回答。你能解释一下bindsetter吗?
    • @Poolka 我的第一个代码仅按顺序实现逻辑,因此您可以看到元素的相关性,在此更新的代码中,我比您的代码更有效,在您的情况下,您清理指令并创建其他指令,在我的情况下只有重用。还添加了一个简短的解释,但如果您想要更准确的解释,请阅读文档。
    • 感谢您的解释。老实说,我决定尝试 kivy,因为它是用 python 编写的,并且与其他用于 python 的 gui 框架相比,它是 pythonic 的。现在看来 kivy 并不适合复杂/动态的 gui。
    • @Poolka pythonic 对你来说是什么?恕我直言,声明性语言有助于轻松创建视觉效果,但在业务逻辑部分,支持 OOP 的语言是最好的。而且kivy有双方所以只用python代码做代码会很乏味和难以忍受,一开始kv语言看起来很奇怪,但是当你使用非常简单的事实时。关于其他库,我推荐它用于移动设备,而不是桌面设备。
    • @Poolka 对于桌面我更喜欢使用 Qt (PyQt4 / PyQt5 / PySide / PySide2),因为它是一个成熟且多功能的库,有时我将它与 QML 结合起来,因为它可以快速实现视图(就像 Qt 的 kv 语言)。其他库,比如我用来做极简的东西的 tkinter,pygame 我几乎不用它等等。
    【解决方案2】:

    解决我的问题的另一种方法-基于@eyllanesc 的答案和kivy crash course videos 的解决方案。我在这里发布它有两个原因:(1)使用这个版本,人们可以清楚地看到正在发生的事情 - 实际绘制背景的方式和时间 - 没有另一个语法层(kivy 语言)并且没有 bindsetter 完全对我来说是新的,(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()
    

    外观:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-26
      • 1970-01-01
      • 1970-01-01
      • 2013-05-21
      • 1970-01-01
      • 2022-09-28
      • 1970-01-01
      相关资源
      最近更新 更多