小部件 parent 无法立即在 KV 文件中使用
Widget parent not immediately available in KV file
我的 KV 文件中有一个 class 的规则,我们将调用继承自 Widget class 的 Foo,我在 python 文件中创建了它的实例:(已删除大部分不相关的详细信息)
在python中:
Class Foo(Widget):
x_coord = NumericProperty()
y_coord = NumericProperty()
Kv:
<Foo>:
pos: self.x_coord + self.parent.bar, self.y_coord() + self.parent.barbar
但是当我实例化 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)
我收到一条错误消息 type object NoneType has no attribute bar
在我看来,一旦 class 被实例化,KV 文件就会尝试应用规则,但它还没有 parent 因为它还没有被添加任何事情。我什至尝试向 Foo 添加一个名为 parent 的临时子 class,它具有我引用的所有属性的工作值,这确实阻止了错误,但我立即得到了一个新的,因为 kivy 不能覆盖临时 class 以添加实际 parent.
我该如何解决这个问题?有没有办法将 parent 作为参数传递?或者我应该在 python 中写出规则并将其放入 Foo class?
的初始化中
parent
也是 属性。这意味着您可以创建 on_parent
方法,当它设置为使用它时调用它的属性:
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()
如果您想在父级 属性 更改时做出反应,您可以在 on_parent
方法中将方法绑定到父级的 属性:
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()
我的 KV 文件中有一个 class 的规则,我们将调用继承自 Widget class 的 Foo,我在 python 文件中创建了它的实例:(已删除大部分不相关的详细信息)
在python中:
Class Foo(Widget):
x_coord = NumericProperty()
y_coord = NumericProperty()
Kv:
<Foo>:
pos: self.x_coord + self.parent.bar, self.y_coord() + self.parent.barbar
但是当我实例化 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)
我收到一条错误消息 type object NoneType has no attribute bar
在我看来,一旦 class 被实例化,KV 文件就会尝试应用规则,但它还没有 parent 因为它还没有被添加任何事情。我什至尝试向 Foo 添加一个名为 parent 的临时子 class,它具有我引用的所有属性的工作值,这确实阻止了错误,但我立即得到了一个新的,因为 kivy 不能覆盖临时 class 以添加实际 parent.
我该如何解决这个问题?有没有办法将 parent 作为参数传递?或者我应该在 python 中写出规则并将其放入 Foo class?
的初始化中parent
也是 属性。这意味着您可以创建 on_parent
方法,当它设置为使用它时调用它的属性:
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()
如果您想在父级 属性 更改时做出反应,您可以在 on_parent
方法中将方法绑定到父级的 属性:
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()