【问题标题】:How to get list of all widgets from widget tree in kivy/python. Recursion function not working as expected如何从 kivy/python 中的小部件树中获取所有小部件的列表。递归函数未按预期工作
【发布时间】:2016-11-01 08:35:51
【问题描述】:

我有一个包含多个布局、按钮、复选框、行编辑和其他小部件的应用程序。我想收集所有这些小部件的列表,以便在应用程序关闭时保存它们的状态。如果可能的话,我不希望将它们存储在一些硬编码列表中,以便以后可以有更多选项来动态修改小部件。

基本问题似乎很简单,我有一个根小部件,然后有子小部件,其中一些有自己的子小部件。小部件树。我尝试的解决方案是编写一个递归函数来遍历每个小部件并返回子级。

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] 这样的列表,返回一个包含所有 int 值的列表。它甚至可以与我制作的一些简单的类一起工作,并在一个假的小部件树中相互存储。但是,当我将它引入我的应用程序时,我得到一个空列表作为回报,没有错误或异常。我对如何使用生成器和产量有基本的想法,但我一定遗漏了一些东西。 我已经使用 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>,
 ...]

【问题讨论】:

    标签: python recursion widget kivy


    【解决方案1】:

    也许在问这个问题时它不可用,但现在有Widget.walk 方法返回一个遍历树的生成器,以前向布局顺序返回小部件

    https://kivy.org/doc/stable/api-kivy.uix.widget.html?highlight=widget%20walk#kivy.uix.widget.Widget.walk

    【讨论】:

      【解决方案2】:

      首先,将所有输入小部件的名称设置为具有描述性的名称,例如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)
      

      【讨论】:

      • 谢谢。我想我在试图让我的功能列出清单时走神了。添加名称属性确实简化了该过程。 if 语句缺少缩进,以防其他人正在尝试此代码。
      猜你喜欢
      • 1970-01-01
      • 2021-07-10
      • 2022-06-11
      • 2021-01-21
      • 2017-09-23
      • 1970-01-01
      • 1970-01-01
      • 2020-07-14
      • 2022-01-07
      相关资源
      最近更新 更多