【发布时间】:2016-06-17 23:39:35
【问题描述】:
我是 Kivy 的新手,我有一个小演示 sn-p 来演示我的问题:
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)。
我的问题是:
- 'id' 不是和'name' 一样的属性吗?
- 如何从 python 端访问每个小部件的 id?
额外问题:
- 我可以通过它的 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 在 init 阶段之后立即调用,当小部件被定位时,以后很少,所以......根据我对 kivy api 的了解,似乎是最不麻烦的方式,订单小部件被初始化使用 .kv 语言等;所以如果有更好的方法,我会非常感谢任何指针)。
无论如何,通过这种方式,我可以轻松地从 .kv 将任何事件绑定到任何类中的任何方法
要记住的一件事是 gid(全局 id)需要在全球范围内唯一,但我发现没有比在本地保持 id 唯一更令人不安的了(这对我来说可能同样或什至更令人困惑)。正如我所说 - 我想以不同的方式注册小部件,但我找不到任何其他可靠的方法来做到这一点(而且我不认为 Clock 对于这些事情是可靠的)。
【问题讨论】: