如何从 kivy/python 中的小部件树中获取所有小部件的列表。递归函数没有按预期工作
How to get list of all widgets from widget tree in kivy/python. Recursion function not working as expected
我有一个包含多个布局、按钮、复选框、行编辑器和其他小部件的应用程序。我想收集所有这些小部件的列表,以便在应用程序关闭时保存它们的状态。如果可能的话,我宁愿不要将它们存储在一些硬编码列表中,这样我以后可以有更多选项来动态修改小部件。
基本问题看起来很简单,我有一个根小部件,然后有子小部件,其中一些有自己的子小部件。小部件树。我尝试的解决方案是编写一个递归函数来遍历每个小部件和 return 个子部件。
def traverse(item):
try:
for i in iter(item):
for j in traverse(i):
yield j
except TypeError:
yield item
此函数适用于列表,例如 [1, [2, 3], [4, 5, [[6, 7], 8], 9], 10]
returning 一个包含所有 int 值的列表。它甚至可以与我制作的一些简单的 类 一起使用,并将它们存储在一个假的小部件树中。但是,当我将它引入我的应用程序时,我在 return 中得到一个空列表,没有错误或异常。我对如何使用生成器和 yield 有基本的了解,但我一定遗漏了一些东西。
我已经使用 kivy1.9.1 和 python 做了一个我正在尝试做的基本示例。如果您单击其中一个按钮,它应该会打印出所有子部件的列表,但它不会:
main.py:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class MyRootLayout(BoxLayout):
def traverse(self, item): # function in question
try:
for i in iter(item):
try:
for j in self.traverse(i.children):
yield j
except:
yield i
except TypeError:
yield item
def printwidgetlist(self): # Called when a button is pressed
print [child for child in self.traverse(self.children)]
class TestApp(App):
def build(self):
return MyRootLayout()
if __name__ == '__main__':
TestApp().run()
和定义小部件树的 test.kv 文件:
#:kivy 1.9.1
<MyRootLayout>:
Label:
id: label_1_id
text: "label 1"
Label:
id: label_2_id
text: "label 2"
GridLayout:
cols: 2
Button:
text: "button 1"
on_press: root.printwidgetlist()
Button:
text: "button 2"
on_press: root.printwidgetlist()
GridLayout:
Label:
id: label_4_id
text: "other stuff"
Label:
id: label_3_id
text: "label 3"
您可以在每个小部件上调用 self.children,这是我用来获取要迭代的子项列表的方法。有没有比我尝试的更好的方法来获取所有小部件?我的遍历函数是否遗漏了什么?我敢肯定这很简单。我不是最先进的程序员。
我想要得到的输出是这样的:
[...
<kivy.uix.label.Label object at 0x0000000003632BA8>,
<kivy.uix.gridlayout.GridLayout object at 0x0000000003632AD8>,
<kivy.uix.label.Label object at 0x0000000003632B40>,
...]
首先,将所有输入小部件的名称设置为描述性的名称,比方说 input_widget
。你可以直接在kv lang里面设置。
其次,从根级别递归查找:
class MyRootLayout(BoxLayout):
def save_states(self):
def save_state(widget):
for child in widget.children:
save_state(child)
if 'input_widget' in child.name:
# Do something here to save the state.
pass
for child in self.children:
save_state(child)
也许在提出这个问题时它不可用,但现在有 Widget.walk
方法,其中 returns 一个遍历树的生成器,返回小部件正向布局顺序:
我有一个包含多个布局、按钮、复选框、行编辑器和其他小部件的应用程序。我想收集所有这些小部件的列表,以便在应用程序关闭时保存它们的状态。如果可能的话,我宁愿不要将它们存储在一些硬编码列表中,这样我以后可以有更多选项来动态修改小部件。
基本问题看起来很简单,我有一个根小部件,然后有子小部件,其中一些有自己的子小部件。小部件树。我尝试的解决方案是编写一个递归函数来遍历每个小部件和 return 个子部件。
def traverse(item):
try:
for i in iter(item):
for j in traverse(i):
yield j
except TypeError:
yield item
此函数适用于列表,例如 [1, [2, 3], [4, 5, [[6, 7], 8], 9], 10]
returning 一个包含所有 int 值的列表。它甚至可以与我制作的一些简单的 类 一起使用,并将它们存储在一个假的小部件树中。但是,当我将它引入我的应用程序时,我在 return 中得到一个空列表,没有错误或异常。我对如何使用生成器和 yield 有基本的了解,但我一定遗漏了一些东西。
我已经使用 kivy1.9.1 和 python 做了一个我正在尝试做的基本示例。如果您单击其中一个按钮,它应该会打印出所有子部件的列表,但它不会:
main.py:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class MyRootLayout(BoxLayout):
def traverse(self, item): # function in question
try:
for i in iter(item):
try:
for j in self.traverse(i.children):
yield j
except:
yield i
except TypeError:
yield item
def printwidgetlist(self): # Called when a button is pressed
print [child for child in self.traverse(self.children)]
class TestApp(App):
def build(self):
return MyRootLayout()
if __name__ == '__main__':
TestApp().run()
和定义小部件树的 test.kv 文件:
#:kivy 1.9.1
<MyRootLayout>:
Label:
id: label_1_id
text: "label 1"
Label:
id: label_2_id
text: "label 2"
GridLayout:
cols: 2
Button:
text: "button 1"
on_press: root.printwidgetlist()
Button:
text: "button 2"
on_press: root.printwidgetlist()
GridLayout:
Label:
id: label_4_id
text: "other stuff"
Label:
id: label_3_id
text: "label 3"
您可以在每个小部件上调用 self.children,这是我用来获取要迭代的子项列表的方法。有没有比我尝试的更好的方法来获取所有小部件?我的遍历函数是否遗漏了什么?我敢肯定这很简单。我不是最先进的程序员。 我想要得到的输出是这样的:
[...
<kivy.uix.label.Label object at 0x0000000003632BA8>,
<kivy.uix.gridlayout.GridLayout object at 0x0000000003632AD8>,
<kivy.uix.label.Label object at 0x0000000003632B40>,
...]
首先,将所有输入小部件的名称设置为描述性的名称,比方说 input_widget
。你可以直接在kv lang里面设置。
其次,从根级别递归查找:
class MyRootLayout(BoxLayout):
def save_states(self):
def save_state(widget):
for child in widget.children:
save_state(child)
if 'input_widget' in child.name:
# Do something here to save the state.
pass
for child in self.children:
save_state(child)
也许在提出这个问题时它不可用,但现在有 Widget.walk
方法,其中 returns 一个遍历树的生成器,返回小部件正向布局顺序: