Kivy:获取小部件 ID 并通过唯一属性访问小部件

新手上路,请多包涵

我是 Kivy 的新手,我有这个演示我的问题的小演示片段:

 from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder

class KivyGuiApp(App):
    def build(self):
        return root_widget

class MyBox(BoxLayout):
    def print_ids(self, *args):
        print("\nids:")
        for widget in self.walk():
            print("{} -> {}".format(widget, widget.id))
    def print_names(self, *args):
        print("\nnames:")
        for widget in self.walk():
            print("{} -> {}".format(widget, widget.name))

root_widget = Builder.load_string("""
MyBox:
    id: screen_manager
    name: 'screen_manager'

    SimpleLayout:
        id: simple_layout
        name: 'simple_layout'

<SimpleLayout@BoxLayout>:
    id: simple_layout_rule
    name: 'simple_layout_rule'
    Button:
        id: button_ids
        name: 'button_ids'
        text: 'print ids to console'
        on_release: app.root.print_ids()
    Button:
        id: button_names
        name: 'button_names'
        text: 'print names to console'
        on_release: app.root.print_names()
""")

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

所以当你运行代码时会有两个按钮:

  • 首先遍历所有小部件并打印它们的名称(按预期工作 - 为每个小部件返回“名称”),
  • 第二个按钮也遍历所有小部件,但不是名称打印它们的 id(这不起作用 - 为每个 id 返回 None)。

我的问题是:

  1. “id”不是像“name”一样的属性吗?
  2. 如何从 python 端访问每个小部件的 id?

奖金问题:

  1. 我可以通过它的 id(假设所有 id 都是唯一的)“全局”访问一个小部件吗?通过“全局”我的意思是例如访问(在上面的代码中)来自’MyBox:’小部件的id而不引用父子,而只是通过id(或者可能是每个小部件唯一的任何其他属性)。我正在考虑创建一个包含所有小部件的字典 { id : widget object } 以便于访问,除非有另一种我不知道的方法?需要强调的是——我试图避免以父子方式进行引用(当您想稍后更改小部件树时,这会相当混乱)并且我想以 .kv 语言生成小部件。那么最好的方法是什么?

编辑:

所以这是我能想到的通过唯一的“全局”ID 引用小部件的最简单方法。

首先,我创建了一个将由我的 App 类继承的类:

 class KivyWidgetInterface():
    ''' interface for  global widget access '''
    global_widgets = {}
    def register_widget(self, widget_object):
        ''' registers widget only if it has unique gid '''
        if widget_object.gid not in self.global_widgets:
            self.global_widgets[widget_object.gid] = widget_object

    def get_widget(self, widget_gid):
        ''' returns widget if it is registered '''
        if widget_gid in self.global_widgets:
            return self.global_widgets[widget_gid]
        else:
            return None

因此,只有当小部件具有 gid(一个小部件类变量)并且它是唯一的时,才会被注册。这样我就可以在这个字典中只存储重要的小部件。此外,它可以从 .kv 和 python 端轻松访问。

现在我创建 gid 变量并将它们注册到 .kv 中的字典:

 <PickDirectory>:
    gid: 'pick_directory'
    on_pos: app.register_widget(self)
    on_selection: app.get_widget('filelist').some_func()
<FileListView>:
    gid: 'filelist'
    on_pos: app.register_widget(self)
    Button:
        name: 'not important'
    Button:
        gid: 'tab_browse_button1'
        on_pos: app.register_widget(self)

实际上困扰我的是我在这个“全局”字典中使用’on_pos’事件注册我的小部件……我真的不喜欢,但我无法找到任何可靠的方法来调用注册方法小部件已初始化(在初始化阶段之后立即调用 on_pos,当小部件被定位时,以后很少,所以……根据我对 kivy api 的了解,这似乎是最不麻烦的方法,顺序小部件是用 .kv 初始化的语言等;因此,如果有更好的方法,我将非常感谢任何指点)。

无论如何,这样我就可以轻松地将任何事件绑定到任何类中的任何方法,直接来自 .kv

要记住的一件事是 gid(全局 id)需要在全球范围内是唯一的,但我发现这没有比在本地保持 id 唯一更令人不安的了(这对我来说可能同样甚至更令人困惑)。正如我所说 - 我想以不同的方式注册小部件,但我找不到任何其他可靠的方法来做到这一点(而且我发现 Clock 对此类事情不可靠)。

原文由 kilbee 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 896
2 个回答

实际上,不。 name 在你的小部件中是一个变量, id 只是一个小部件参考, weakref 根据文档。也许 python 文档 会帮助您了解它是如何工作的。您所做的是打印 id ,而不是小部件内的变量“id”。

kivy 文档 中解释说 kv 被解析后,ids 被收集到 ObservableDict 中。 id 的工作方式类似于 python dict 键 id:Widget 但只有通过字典访问( ids )。我认为 kv 解析器只是将所有 id 放入 dict 中,并且仅适用于它创建的 dict。

 Button:
    id: test
    text: 'self.id'
#or
Button:
    id: 'test'
    text: 'self.id'

即使它像字符串一样写,也没有任何改变。所以我希望解析器的行为是这样的:抓住 id: 之后的任何整个单词,变成一个字符串,附加到 ids 字典 <id_string>:Widget_weakref id c6 --- 在你的 .kv 或者如果它再次与 .kv 一起工作则忽略它。因此,当 id 被直接调用时(不是类似字典的 d[key]),它的行为就像一个空的/ None 变量。我希望我是对的。

回答第二个和第三个:

如果您的意思是通过 idMyBox 直接访问小部件,例如 SimpleLayout ,那么是的。

蟒蛇类:

 self.ids.simple_layout

kv MyBox 规则:

 MyBox:
    id: screen_manager
    name: 'screen_manager'
    BoxLayout:
        Label:
            id: my_label
            text: 'test'
        Button:
            text: 'button'
            on_release: self.text = root.ids.my_label.text

但是,要像 python globals 一样通过 id 访问所有小部件,这是不可能的。您需要先访问类/小部件,然后访问其 ids 字典

原文由 Peter Badida 发布,翻译遵循 CC BY-SA 3.0 许可协议

“id”不是像“name”一样的属性吗?

不,ids 是一种特殊语法,仅存在于 kv 语言中,或者可通过 python 中规则的根小部件访问 ( self.ids.idname )。 一个 id 属性,但我不确定它是否真的在任何地方使用,它似乎主要是出于遗留原因而存在。我想我们正在考虑删除它。

如何从 python 端访问每个小部件的 id?

通过根小部件的 ids 属性。例如,在 MyBox 方法中,您可以编写 self.ids.simple_layout 以获得 SimpleLayout。

我正在考虑创建一个包含所有小部件的字典 { id : widget object } 以便于访问

这通常是不可能的,因为多个小部件可以具有相同的 ID。这就是为什么它们是规则本地的并通过规则的根小部件访问的原因。

如果您愿意,您可以自己构建这样一个列表,要么考虑重复项,要么知道您不会创建它们。

原文由 inclement 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题