【问题标题】:Accessing value of child widget property in kivy lang and python在 kivy lang 和 python 中访问子小部件属性的值
【发布时间】:2018-11-26 06:42:57
【问题描述】:
  1. 如何覆盖 Kivy 小部件子部件的默认值?即MyWidget.label 是“默认”,但我想将其更改为例如'紫龟'当MyRootWidget的孩子?

  2. 我可以像在MyRootWidget.__init__() 中那样访问children 的children,但这似乎很麻烦,尤其是对于一棵深树...有没有更优雅的方法?

我一直在查看 Kivy lang 和 Widget 页面,但无法理解是否存在解决方案。我在 SO 页面中还没有看到这个问题(尽管在我搜索时确实回答了一个不同的问题)。

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty, StringProperty


root = Builder.load_string('''
<MyWidget@BoxLayout>:
    orientation: 'vertical'
    Label:
        id: label
        text: 'DEFAULT'

<MyRootWidget@BoxLayout>:
    id: root_widget
    MyWidget:
        id: w1
        # (---1---) 
''')


class MyRootWidget(BoxLayout):
    w1 = ObjectProperty()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        print(self.ids.w1.ids.label.text)  # (---2---)


class MainApp(App):
    def build(self):
        return MyRootWidget()


if __name__ == '__main__':
    MainApp().run()

【问题讨论】:

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


    【解决方案1】:

    首先,在实现任何代码之前,您必须设计您的类。

    首先我们将使用 MyWidget,在您的要求中表明您希望文本是可修改的,因此它必须是根属性。

    MyWidget
    ┌--------------------------┐
    |                          |
    | ┌-------------┐   text---┼--->
    | | Label       |     |    |
    | |    *text ---┼-----┘    |
    | └-------------┘          |
    └--------------------------┘
    

    MyRootWidget 也可以这样做:

    MyRootWidget
    ┌-----------------------------┐
    |                             |
    | ┌-------------┐ obj_widget--┼--->
    | | MyWidget  --┼-----┘       |
    | |             |             |
    | └-------------┘             |
    └-----------------------------┘
    

    属性的深度取决于您的要求,但如果我们观察到公开属性,则意味着在根中创建一个属性并进行绑定,以便在修改根属性时也会修改内部属性。

    实现上述你会得到以下结果:

    from kivy.app import App
    from kivy.lang import Builder
    from kivy.uix.boxlayout import BoxLayout
    from kivy.properties import ObjectProperty, StringProperty
    
    root = Builder.load_string('''
    <MyWidget@BoxLayout>:
        text: "DEFAULT"
        obj_label: label
        orientation: 'vertical'
        Label:
            id: label
            text: root.text
    
    <MyRootWidget@BoxLayout>:
        obj_widget: w1
        MyWidget:
            id: w1
            text: "purple turtle"
    ''')
    
    class MyRootWidget(BoxLayout):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            print(self.obj_widget.text) 
    
    class MainApp(App):
        def build(self):
            return MyRootWidget()
    
    if __name__ == '__main__':
        MainApp().run()
    

    因此,为了避免使用 id,您可以为子小部件创建一个别名,就像我对 obj_widget 所做的那样,它是 w1 的别名。

    根据设计,您不应直接访问完整的树,但您必须修改层的属性,如果修改了该层,则必须更新其内部部分的必要数据,以避免类之间的耦合。

    【讨论】:

    • 那么要修改一个小部件中的任何属性,该属性必须是根属性吗?如果这深入了几层孩子,我是否需要跨多个层“链接”一个属性以将属性获取到需要访问它的小部件,或者是否有一些捷径可以让父母访问曾孙的属性? (在两个方向上,例如,小部件更新曾孙中的标签,曾孙 TextInput 更新曾祖父母中的标签。)
    • @DanielB。您将其视为层,而您缺少类的概念:类是某种东西,它对某些东西有好处。例如,如果您要创建一个作为登录小部件的类,让我们调用这个 Login 类,所以正确的是从外部您可以看到用户名和密码的属性,开发人员将要使用你的类对使用该类的内部类(例如 TextInput)不感兴趣。它就像一个有输入和输出的黑匣子。因此,没有通用的响应,这取决于该类将提供什么服务。
    • @DanielB。我建议您花点时间为您的类设计一个 UML 图,属性表示属于该类的对象的静态特征,而函数是改变该静态属性的动态部分。让我们来看一个简单的例子,我们创建了球类,它将具有大小、位置、速度等属性以及 move、setSize、setVelocity 等方法。在内部绘制球时,您可以使用 Image 但它是否需要从外部访问图像?,不,没有必要。
    • @DanielB。总之关注你的类(Widget)并建立其代表属性,然后在实现内部将内部元素的属性与代表属性联系起来。层数无所谓。当您实现一个小部件时,不要考虑您的项目,只需考虑该类的目标,还要考虑您可以在另一个项目中使用该类,使其具有通用性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-16
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    • 2016-10-12
    • 1970-01-01
    相关资源
    最近更新 更多