Kivy : how to get widget by id (without kv)

kivy, python, widget

Solution

Kivy widgets make tree structure. Children of any widget are avaiable through `children` atribute. If you want, you can keep reference only to root window and then iterate over it's widgets using `walk` method:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button 

class MyWidget(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        button = Button(text="...", id="1")
        button.bind(on_release=self.print_label)

        l1 = BoxLayout(id="2")
        l2 = BoxLayout(id="3")

        self.add_widget(l1)
        l1.add_widget(l2)             
        l2.add_widget(button)

    def print_label(self, *args):
        for widget in self.walk():
            print("{} -> {}".format(widget, widget.id))

class MyApp(App):
    def build(self):
        return MyWidget()

if __name__ == '__main__':
    MyApp().run()

`walk()` and `walk_reverse()` method were added to `kivy.uix.widget.Widget` in 1.8.1 version of Kivy. For older versions you need to recursively parse tree yourself:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button 

class MyWidget(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        button = Button(text="...", id="1")
        button.bind(on_release=self.print_label)

        l1 = BoxLayout(id="2")
        l2 = BoxLayout(id="3")

        self.add_widget(l1)
        l1.add_widget(l2)             
        l2.add_widget(button)

    def print_label(self, *args):
        children = self.children[:]
        while children:
            child = children.pop()
            print("{} -> {}".format(child, child.id))
            children.extend(child.children)

class MyApp(App):
    def build(self):
        return MyWidget()

if __name__ == '__main__':
    MyApp().run()

Problem

Let's say I define on the fly in Kivy a few widgets (buttons) and dynamically assign their id. I'm not using kv language in this use case. I can keep a reference of a widget id without keeping track of the widget itself : then I'd like to access the widget through its id. Can I do something like "get widget by id" ? (If I had defined the widget in a kv file, I could have used self.ids.the_widget_id to access the widget itself through its id)

Original source