在 Kivy 语言中,属性会自动创建内部绑定。例如,如果我们将父节点的位置分配给子节点的位置,那么子节点的位置将自动更新:
Widget: Label: pos: self.parent.pos
在这种情况下,如果我们移动父节点 Widget,子节点也会移动。那么我们如何从子节点解除属性 pos 的绑定呢?我们知道如何解除我们自己绑定的(属性)[kivy.org/docs/api-ki…
下面是一个小例子,说明了我的意思。向上按钮将 GridLayout 移动到顶部,向下按钮将 GridLayout 移动到底部。居中按钮将自身定位在屏幕中央。我的问题是,当我点击向上或向下时,我的居中按钮就不再居中了。
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
Builder.load_string("""
<Example>:
GridLayout:
id: _box
cols: 3
size_hint: .7, .3
pos_hint: {'center_x': .5}
x: 0
Widget:
Button:
pos: self.parent.pos
size: self.parent.size
on_press: _box.y = 0
text: "Down"
Widget:
Button:
pos: self.parent.pos
size: self.parent.size
on_press: self.center_y = root.height/2
text: "Out of the Grid"
Widget:
Button:
pos: self.parent.pos
size: self.parent.size
on_press: _box.top = root.height
text: "Up"
""")
class Example(FloatLayout):
pass
class ExampleApp(App):
def build(self):
return Example()
if __name__ == "__main__":
ExampleApp().run()
在某些情况下,我为什么想这样做?我们在 GridLayout 上使用一种动画,不断更新位置。按钮的正常位置应该在网格布局内,但偶尔会有一个按钮飞出屏幕然后返回到相同的位置。问题是,当网格布局也在移动时,我们无法让它们飞出,因为属性被绑定了,一旦按钮尝试飞出,它就会回到网格布局。这也意味着有时绑定是需要的。我想要的是能够控制绑定和解除绑定。
解决方案
- 使用 FloatLayout 作为根部件,而不是创建一个新的 FloatLayout。
- 在从网格中移除部件之前,存储它的尺寸,将 size_hint 设置为 None, None,并设置 pos_hint 以将部件定位在中心。
- 将部件添加到网格时,执行相反的操作。
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
Builder.load_string("""
<Example>:
center_button: _center_button
center_widget: _center_widget
grid:_grid
GridLayout:
id: _grid
cols: 3
size_hint: .7, .3
pos_hint: {'center_x': .5}
x: 0
Widget:
Button:
pos: self.parent.pos
size: self.parent.size
on_press: _grid.y = 0
text: "Down"
Widget:
id: _center_widget
Button:
id: _center_button
pos: self.parent.pos
size: self.parent.size
on_press: root.centerize(*args)
text: "Out of the Grid"
Widget:
Button:
pos: self.parent.pos
size: self.parent.size
on_press: _grid.top = root.height
text: "Up"
""")
class Example(FloatLayout):
def centerize(self, instance):
if self.center_button.parent == self.center_widget:
_size = self.center_button.size
self.center_widget.remove_widget(self.center_button)
self.center_button.size_hint = (None, None)
self.add_widget(self.center_button)
self.center_button.pos_hint = {'center_x': .5, 'center_y':.5}
else:
self.remove_widget(self.center_button)
self.center_button.size_hint = (1, 1)
self.center_widget.add_widget(self.center_button)
self.center_button.size = self.center_widget.size
self.center_button.pos = self.center_widget.pos
class ExampleApp(App):
def build(self):
return Example()
if __name__ == "__main__":
ExampleApp().run()