22

In Kivy language, it is possible to refer to the root widget with something like

<RootWidget>:
    BoxLayout:
        SomeButton:
            on_press: print root

but trying to access root from Python is impossible

class SomeButton(Button):
    def __init__(self, **kwargs):
        super(SomeButton, self).__init__(**kwargs)
        self.text = "Button"
        self.font_size = 15
    def on_press(self, *args):
        print root

and will result in

NameError: global name 'root' is not defined

or if using self.root,

AttributeError: 'SomeButton' object has no attribute 'root'
Dan Lowe
  • 51,713
  • 20
  • 123
  • 112
Tan Wang
  • 811
  • 1
  • 6
  • 16
  • Refer to these links 1) http://stackoverflow.com/questions/30202801/how-to-access-id-widget-of-different-class-from-a-kivy-file-kv/30220800#30220800 – kiok46 Aug 23 '15 at 06:00
  • 2) http://stackoverflow.com/questions/30874370/update-labels-text-when-pressing-a-button-in-kivy-for-python/30878714#30878714 – kiok46 Aug 23 '15 at 06:00

4 Answers4

37

If you want the actual root widget from the App then I use the following from within any Widget class...

from kivy.app import App
...
class myWidget(BoxLayout):
    app= App.get_running_app()
    app.root.whatever-you-want
Jim Morris
  • 2,870
  • 24
  • 15
6

Inside a kv file, root always refers to a parent with angle brackets. There can therefore be multiple roots which you can refer to in a kv file, depending on where you are in the file.

# Root here refers to the parent class in angle brackets
<SomeClass>:
    BoxLayout:
        Label:
            text: root.label_text

# and further down in the same kv file, this other
# class is also a root.. here root refers to
# this class
<SomeOtherClass/Widget/LayoutEtc>:
    BoxLayout:
        Label:
            text: root.label_text

In a python file then, these classes could be represented like so:

class SomeClass:

    label_text = StringProperty("I'm a label")

    def __init__(**kwargs):
        super(SomeClass, self).__init__(**kwargs)
        b = BoxLayout()
        l = Label(text=self.label_text)
        b.add_widget(l)
        self.add_widget(b)
        # now we're set up like the first class in the above kv file

Now look above and compare how the kv file assigned the text to the label, and how it's done in the python file above. In kv it was root.label_text, but above, the class uses self. As in, text=self.label_text. It's also used when adding the boxlayout, self.add_widget(b). self is a way of referring to the current instance of the class.

That's how you basically refer to what would be 'root' in the kv file, but in the python file.

If you don't know why self is used, then I advise learning about classes in python, as that's where the explanation to that lies.

Totem
  • 7,189
  • 5
  • 39
  • 66
3

My workaround was just to declare a global variable within the main App's build() method, something like global root and root = self.root since the root widget is accessible when you're in the App class. You can do the same thing with app.

Tan Wang
  • 811
  • 1
  • 6
  • 16
  • 2
    **Quite possibly a bad idea.** You're now holding a module-scoped strong reference to your root Kivy widget, preventing that widget and thus your entire Kivy app from being cleanly garbage-collected at app shutdown. In short, [just access `App.get_running_app().root` instead as in the current top answer](https://stackoverflow.com/a/43576254/2809027). If that's too cumbersome, encapsulate that in a dynamic magical property that indirectly hides the getter call. – Cecil Curry Jun 24 '22 at 05:58
0

Just to put it out there.

Parent

Button:
  on_press: root.something()

Parent of parent:

Button:
  on_press: root.parent.something()
monolith
  • 1,606
  • 1
  • 12
  • 21