【问题标题】:Creating attributes to widgets in separate .kv files在单独的 .kv 文件中为小部件创建属性
【发布时间】:2023-03-09 00:55:01
【问题描述】:

我正在学习编写 Kivy 应用程序。我创建了一个由两个网格布局组成的玩具应用程序。一个包含两个按钮,另一个包含两个标签。任务是在单击按钮时修改标签。当所有布局都在同一个 .kv 文件中时,我可以非常简单地做到这一点,只需以标准方式创建 id 和属性。

当我将布局拆分为单独的 .kv 文件时,我无法做同样的事情。我想这样做,因为我实际从事的项目太复杂,无法包含在单个 .kv 文件中。所以这是我的代码:

主要python代码:

# filename DynamicApp.py
import kivy
kivy.require('1.9.0')

from kivy.app import App
from kivy.uix.relativelayout import RelativeLayout
from kivy.lang import Builder

Builder.load_file("myfirstgrid.kv")
Builder.load_file("mysecondgrid.kv")

class DynamicWidgets(RelativeLayout):
    pass

class DynamicApp(App):
    def build(self):
        return DynamicWidgets()

if __name__ == "__main__":
    DynamicApp().run()

基础 kivy 文件:

# File name: DynamicApp.kv
#:kivy 1.9.0
<DynamicWidgets>:
    MyFirstGrid:

    MySecondGrid:

第一个网格的kivy

# File name: myfirstgrid.kv
#:kivy 1.9.0        
<MyFirstGrid@GridLayout>        
    id: _my_first_grid
    rows: 1
    cols: 2
    Label:
        id: _label_1
        text: "Hello World"
    Label:
        id: _label_2
        text: "Hello World"

第二个网格的 Kivy

# File name: myseoncdgrid.kv
#:kivy 1.9.0
#:import mybutton mybutton
<MySecondGrid@GridLayout>   
    size_hint: 0.25, 0.25
    pos_hint: {'center_x': 0.5, 'y' : 0}
    rows: 1
    cols: 2
    MyButton:
        text: 'Do it'
        label_1: _label_1
    MyButton:
        text: 'Do it Again'
        label_2: _label_2

mybutton.py 控制按钮操作,此处未显示,因为我无法在 MyButton 小部件中创建属性和引用,因为它给了我错误 NameError: name '_label_2' is not defined

我采用了完全相同的策略,但将所有 kv 都放在一个文件中,并且可以正常工作。

如何为其他 .kv 文件中的小部件创建引用和属性。

我觉得我缺少一些基本的东西。

谢谢

【问题讨论】:

    标签: python python-2.7 kivy


    【解决方案1】:

    根据Kv Language 上的文档,“ID 的范围仅限于声明它的规则”。这意味着标签 ID 在&lt;My*Grid@GridLayout&gt; 之外无效。这是有道理的,因为规则可以应用于任何 UI 树中的小部件,并且它无法提前知道自身外部存在或不存在什么。

    您的问题的解决方案是使用Properties。您可以将标签文本绑定到StringProperty,然后当您在代码中更改它时(按下按钮),Kivy 将为您更新标签。如果不能方便地相互引用小部件,可以将属性放在App 对象上,在kv 中始终可以将其引用为app

    ex(未经测试):

    class DynamicApp(App):
        label1 = StringProperty("Hello World")
        label2 = StringProperty("Hello World")
        def build(self):
            return DynamicWidgets()
    
    ...
    
    <MyFirstGrid@GridLayout>        
        rows: 1
        cols: 2
        Label:
            text: app.label1
        Label:
            text: app.label2
    
    ...
    
    <MySecondGrid@GridLayout>   
        size_hint: 0.25, 0.25
        pos_hint: {'center_x': 0.5, 'y' : 0}
        rows: 1
        cols: 2
        MyButton:
            text: 'Do it'
            on_press: app.label1 = "did it"
        MyButton:
            text: 'Do it Again'
            on_press: app.label2 = "did it again"
    

    【讨论】:

    • 谢谢,我想我觉得令人困惑的是,如果所有 .kv 都保存在同一个文件中,那么我可以根据需要设置属性。毕竟,这些小部件都是&lt;DynamicWidgets&gt; 的孩子等等,为了方便起见,它只是将kv保存在不同的文件中。
    • 您认为按照我的方式而不是按照您的方式进行操作有优缺点吗?该应用程序真的是一个玩具,实际上按钮会以更深刻的方式修改标签或其他小部件(设置可见性等)
    • ids的范围之所以成为规则本身,是因为规则是一个模块化的组件。在 您的 的情况下,您知道小部件都是 &lt;DynamicWidgets&gt; 的子级,但 Kivy 通常无法做出这样的假设,因为规则不知道它将被插入到哪里(它甚至可能不知道有父母)。
    • 就优点/缺点而言,我认为使用属性更简洁一些(代码更少,而且您不必四处寻找跟踪 id)。它还使您可以更轻松地访问代码,您只需访问一个属性,而不是手动引用您的小部件树。第二种方式也比较脆弱,如果你重新排列你的 UI,你所有的引用都会中断并且需要重写。
    【解决方案2】:

    所以我想我已经能够回答我自己的问题了。正如我的直觉告诉我的那样,您实际上可以在不同的 KV 文件中引用 id。您只需要确保正确管理引用:

    # File name: DynamicApp.kv
    #:kivy 1.9.0
    <DynamicWidgets>:
        MyFirstGrid:
            id: _my_first_grid
            my_second_grid: _my_second_grid
        MySecondGrid:
            id: _my_second_grid
            my_first_grid: _my_first_grid
    

    # File name: myfirstgrid.kv
    #:kivy 1.9.0        
    <MyFirstGrid@GridLayout>        
        id: _my_first_grid
        label_1: _label_1
        label_2: _label_2
        rows: 1
        cols: 2
        Label:
            id: _label_1
            text: "Hello World"
        Label:
            id: _label_2
            text: "Hello World"
    

    # File name: myseoncdgrid.kv
    #:kivy 1.9.0
    #:import mybutton mybutton
    <MySecondGrid@GridLayout>   
        size_hint: 0.25, 0.25
        pos_hint: {'center_x': 0.5, 'y' : 0}
        rows: 1
        cols: 2
        MyButton:
            text: 'Do it'
            on_press: self.onClick1(*args)
        MyButton:
            text: 'Do it Again'
            on_press: self.onClick2(*args)
    

    #file button.py
    from kivy.uix.button import Button
    
    class MyButton(Button):
        def onClick1(self, instance):
            print 'OK'
            mfg = self.parent.my_first_grid
            mfg.label_1.text = "Hello Universe"
            return True
        def onClick2(self, instance):
            mfg = self.parent.my_first_grid
            mfg.label_2.text = "Hello Galaxy"
            return True
    

    【讨论】:

    • 请注意,您不必将所有 id 分配给小部件上的属性,有一种简单的方法可以访问它们:kivy.org/docs/guide/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 2020-09-16
    相关资源
    最近更新 更多