Reputation: 315
Suppose I have a ThemeManager
object as a class attribute in my RootWidget
like so:
class RootWidget(Widget):
theme = ThemeManager()
The ThemeManager
defines a function that returns a hex color.
class ThemeManager:
def get_color(self):
return '#ffffffff'
Let's say I create a Button
in my RootWidget
using a kv
file. How would I be able to call the ThemeManager
functions from the kv
file? Here's an example that doesn't work:
import kivy
kivy.require('1.9.0')
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.lang import Builder
class ThemeManager:
def get_color(self):
return '#ffffffff'
class RootWidget(Widget):
theme = ThemeManager()
my_kv = Builder.load_string("""
#: import get_color_from_hex kivy.utils.get_color_from_hex
RootWidget:
Button:
color: get_color_from_hex(app.root.theme.get_color())
text: "Test"
""")
class TestApp(App):
def build(self):
return my_kv
if __name__ == '__main__':
TestApp().run()
Upvotes: 1
Views: 2237
Reputation: 1253
Since your question is already answered, here's a stab at the explanation, it's actually pretty simple (I think).
app.root is None at the point where your Button is trying to read the function. Because the order of things is (loosely):-
As to why 3. happens, the init method in app.py initializes self.root as None. It can then be set by load_kv (loads a kv with the same name as this app) or by run (which is what happens most of the time).
So you can call app.root in your on_press events (because these only happen in response to user interaction, when the app is fully created) but not in one-off widget initialization events.
Interestingly enough, root is not defined as an ObjectProperty in app.py, which means you can't bind to changes in it like you can with, say, the title and icon. Not sure if it'd ever change though, so this is probably moot.
Upvotes: 1