我是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来引用小部件。
首先,我创建了一个将由我的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(小部件类变量)时才会注册小部件,并且它是唯一的。这样我就可以在这个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)
实际困扰我的事情是,我在这个“全球”字典中用'on_pos'事件注册我的小部件...我真的不喜欢,但我找不到任何可靠的方式来调用寄存器在窗口小部件初始化之后的方法(on_pos在初始阶段之后立即被调用,当窗口小部件被定位时,后来非常少,所以...似乎是最不用的方式,通过我对kivy api的知识,订单窗口小部件被初始化使用.kv语言等;所以如果有更好的方法,我会对任何指针非常粗糙。)
无论如何,这样我就可以轻松地将任何事件绑定到任何类中的任何方法,直接来自.kv
要记住的一件事是gid(全局id)需要在全球范围内是独一无二的,但我没有发现比在本地保持id唯一更令人不安(这对我来说可能同样甚至更加困惑)。正如我所说的 - 我想以不同的方式注册小部件,但我找不到任何其他可靠的方法来做到这一点(而且我发现Clock不可靠这样的东西)。
答案 0 :(得分:3)
Isn&#39; id&#39;一个属性就像&#39; name&#39;?
不,ids是一种特殊的语法,只存在于kv语言中,或者可以通过python(self.ids.idname
)中规则的根小部件访问。 是一个id属性,但我不确定它在任何地方实际使用过,它似乎主要是出于传统原因而存在。我想我们正考虑将其删除。
如何从python端访问每个小部件的id?
通过根小部件的ids
属性。例如,在MyBox方法中,您可以编写self.ids.simple_layout
来获取SimpleLayout。
我正在考虑创建所有小部件的字典{id:widget object}以便于访问
这通常不可能,因为多个小部件可以具有相同的ID。这就是为什么它们是规则本地的,并通过规则的根小部件进行访问。
如果您愿意,您可以自己构建这样的列表,或者考虑重复,或者说您不会创建它们。
答案 1 :(得分:3)
实际上,没有。您的小部件中的name
是一个变量,根据文档,id
只是一个小部件引用,weakref
。也许python docs会帮助您了解它的工作原理。你所做的是在小部件内打印id
,而不是变量“id”。
在kivy docs中解释说,在解析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
.kv
如果它再次与.kv
一起使用,则忽略它。因此,当直接调用id(而非类似字典的d [key])时,它的行为类似于空/ None
变量。我希望我是对的。
回答第二个和第三个问题:
如果您的意思是id
MyBox
直接访问小部件,例如SimpleLayout
,则为是。
python class:
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全局工作那样通过id来访问所有小部件,这是不可能的。您需要先访问类/小部件,然后再访问其ids
字典
答案 2 :(得分:0)
最近我一直在问自己一个类似的问题:如何访问另一个小部件中的属性。我自己找到了答案,我在这里发帖,因为我发现它不是很直观。
这段代码的想法很简单:当点击一个按钮时,它会改变另一个类的子窗口小部件中的属性。
通常在相同的小部件树内进行调用时,它非常简单,可以通过简单的self.ids.simple_layout
(或app
,self
或{{1 }})。
root
棘手的部分是from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
kv = """
<Test>:
Button:
text: "Access label"
on_press: root.access_label()
MyWidget:
id: my_widget
<MyWidget>
Label:
id: my_label
text: "not yet accessed"
"""
Builder.load_string(kv)
class MyWidget(BoxLayout):
pass
class Test(BoxLayout):
def access_label(self):
self.ids.my_widget.ids.my_label.text = 'Accessed!'
class TestApp(App):
def build(self):
return Test()
if __name__ == '__main__':
TestApp().run()
,而且self.ids.my_widget.ids.my_label.text
必须位于根小部件而不是my_widget
定义中。
我不确定我是否完全理解自己,但据我所知,似乎在用另一个类定义另一个小部件时,它会创建另一个树,这意味着:
<My_widget>
。如果我错了,请纠正我