Kivy:获取小部件ID并通过独特属性访问小部件

kil*_*bee 6 python widget kivy

我是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()
Run Code Online (Sandbox Code Playgroud)

因此,当您运行代码时,将有两个按钮:

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

我的问题是:

  1. 'id'不是像'名字'那样的财产吗?
  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
Run Code Online (Sandbox Code Playgroud)

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

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

<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)
Run Code Online (Sandbox Code Playgroud)

实际上困扰我的是我在这个"全局"字典中使用'on_pos'事件注册我的小部件...我真的不喜欢,但我无法找到任何可靠的方法来调用寄存器方法之后widget被初始化了(on_pos在init阶段之后被调用,当widget被定位,之后非常罕见,所以...似乎是最不用的方式,用我对kivy api的知识来做这个,命令小部件用.kv初始化语言等;所以如果有更好的方法,我会对任何指针非常粗糙).

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

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

Key*_*Usr 5

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

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

Button:
    id: test
    text: 'self.id'
#or
Button:
    id: 'test'
    text: 'self.id'
Run Code Online (Sandbox Code Playgroud)

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


回答第二个和第三个:

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

蟒蛇类:

self.ids.simple_layout
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

但是,要像 python 全局变量那样通过 id 访问所有小部件,这是不可能的。您需要先访问类/小部件,然后再访问它的ids字典