I have a rule in my KV file for a class that we'll call Foo that inherits from the Widget class, which I create instances of in my python file: (most irrelevant details have been removed)
In python:
Class Foo(Widget):
x_coord = NumericProperty()
y_coord = NumericProperty()
In Kv:
<Foo>:
pos: self.x_coord + self.parent.bar, self.y_coord() + self.parent.barbar
However when I instantiate the class:
new_foo = Foo()
new_foo.x_coord = 7
new_foo.y_coord = 10
[do some more stuff with it]
<a parent widget>.add_widget(new_foo)
I get an error saying type object NoneType has no attribute bar
It seems to me that the KV file tries to apply the rule as soon as the class is instantiated, but it hasn't got a parent yet because it hasn't been added to anything. I even tried adding a temporary subclass called parent to Foo which had working values for all the properties i referenced, and this did stop the error, but I immediately got a new one as kivy couldn't overwrite the temporary class to add the actual parent.
How do I get around this? Is there a way of passing the parent as an argument? Or should I write out the rule in python instead and put it in an init for the Foo class?
parent
is a property too. That means you can create on_parent
method to be called when its set to use it properties:
from kivy.app import App
from kivy.properties import NumericProperty
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
class Parent(FloatLayout):
bar = NumericProperty(20)
class Child(Button):
def on_parent(self, obj, parent):
self.pos = (parent.bar, parent.bar)
class MyApp(App):
def build(self):
parent = Parent()
child = Child(text="Test", size_hint=(None, None))
parent.add_widget(child)
return parent
if __name__ == '__main__':
MyApp().run()
If you want to react when parent property is changed you can bind a method to parent's property in on_parent
method:
from functools import partial
from kivy.app import App
from kivy.clock import Clock
from kivy.properties import NumericProperty
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
class Parent(FloatLayout):
bar = NumericProperty(20)
class Child(Button):
def on_parent(self, obj, parent):
self.pos = (parent.bar, parent.bar)
parent.bind(bar=self.update_pos)
def update_pos(self, obj, bar):
self.pos = (bar, bar)
class MyApp(App):
def build(self):
parent = Parent()
child = Child(text="Test", size_hint=(None, None))
parent.add_widget(child)
Clock.schedule_once(partial(self.change_parent_bar, parent), 3)
return parent
def change_parent_bar(self, parent, dt):
parent.bar = 50
if __name__ == '__main__':
MyApp().run()