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

Let's say I define several widgets (buttons) in Kiwi on the fly and dynamically assign their identifier. I do not use kv language in this use case. I can save the link to the widget id without tracking the widget itself: then I would like to access the widget through its id. Can I do something like "get widget by id"? (If I defined the widget in the kv file, I could use self.ids.the_widget_id to access the widget itself through its identifier)

+4
source share
3 answers

Kivy widgets create a tree structure. Children of any widget are accessible through the attribute children. If you want, you can only save the link to the root window, and then iterate over it using the method walk:

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()were added to kivy.uix.widget.Widgetin version 1.8.1 Kivy. For older versions, you need to recursively parse the tree:

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()
+2
source

You can get the widget using the identifiers directly. For example, in your code, you can change the button text with the following snippet:

self.ids.2.ids.3.ids.1.text = '!!!!'
+1
source

You can change the properties of each widget using ids:

self.ids['order_number'].text='S1212'
0
source

Source: https://habr.com/ru/post/1548637/


All Articles