简体   繁体   中英

How to get list of all widgets from widget tree in kivy/python. Recursion function not working as expected

I have an app that contains multiple layouts, buttons, checkboxes, lineedits, and other widgets. I want to gather a list of all these widgets so I can save their state when the app is closed. I would prefer not to store them in some hardcoded list if possible so I can have more options to dynamically modify the widgets later.

The basic problem seems simple, I have a root widget which then has child widgets, some of those have child widgets of their own. A widget tree. My attempted solution has been to write a recursive function to go through each widget and return children.

def traverse(item):
    try:
        for i in iter(item):
            for j in traverse(i):
                yield j
    except TypeError:
        yield item

This function works with a list like [1, [2, 3], [4, 5, [[6, 7], 8], 9], 10] returning a single list with all the int values. It even works with some simple classes I made and stored inside each other in a fake widget tree. However when I introduce it into my app I get an empty list in return with no errors or exceptions. I have the basic idea of how to use generators and yield but I must be missing something. I've made a basic example of what I am trying to do using kivy1.9.1 and python. If you click one of the buttons it should print a list of all child widgets but it doesn't:

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()

and the test.kv file that defines the widget tree:

#: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"

You can call self.children on each widget which is what I am using to get lists of children to iterate over. Is there a better way to get all widgets than what I am attempting? Is my traverse function missing something? I'm sure it's something simple. I'm not the most advanced programmer. The output I am looking to get is something like this:

[...
 <kivy.uix.label.Label object at 0x0000000003632BA8>,
 <kivy.uix.gridlayout.GridLayout object at 0x0000000003632AD8>,
 <kivy.uix.label.Label object at 0x0000000003632B40>,
 ...]

First, set names of all input widgets to something descriptive, let's say input_widget . You can set them directly in the kv lang.

Second, find them recursively from the root level:

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)

Maybe it wasn't available at the time this question was asked, but now there is Widget.walk method which returns A generator that walks the tree, returning widgets in the forward layout order :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM