1

Kivy 语言自动在属性中创建内部绑定。例如,如果我们将父级的位置分配给子级的位置,那么子级的位置将自动更新:

Widget:
    Label:
        pos: self.parent.pos

在这种情况下,如果我们移动 parent Widget,那么 child 也会移动。如何解除财产pos与孩子的绑定?我知道如何解除绑定(属性)[http://kivy.org/docs/api-kivy.uix.widget.html#using-properties] 我绑定自己但是如果我不知道如何解除绑定它绑定的方法的名称

这是一个小例子来说明我的意思。Button Up将移动到GridLayout顶部和底部中心位于屏幕中间。我的问题是,当我单击向上向下时,我的居中按钮不再存在。DownButton

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不断更新位置的动画。按钮的正常位置应该在网格布局内,但有时其中一个按钮会飞过屏幕并返回到相同的位置。问题是,当我的网格布局也在移动时,我无法让它们飞行,因为属性已绑定,并且一旦按钮尝试飞行,它就会返回网格。这也意味着有时需要绑定。我想要的是控制绑定和解除绑定。

4

3 回答 3

3

评论现在似乎不起作用,所以我将其发布为答案。

  1. 您已经有一个 FloatLayout(您的根小部件)。使用它而不是创建一个新的 FloatLayout。
  2. 从网格中删除小部件之前。
    • 存储它的大小,
    • 将 size_hint 设置为 None、None
    • 设置 pos_hint 以将小部件定位在中心。
  3. 将小部件添加到网格时,请执行相反的操作。

这是您的代码与这些修复::

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()

更新1:

如果出于某种原因您仍然需要取消绑定由 kvlang 绑定的属性,您可以使用自省来获取该属性的观察者列表。所以对于你的情况,它会是这样的::

observers = self.center_widget.get_property_observers('pos')
print('list of observers before unbinding: {}'.format(observers))
for observer in observers:
    self.center_widget.unbind(pos=observer)
print('list of observers after unbinding: {}'.format(self.center_widget.get_property_observers('pos')))

为此,您需要使用最新的 master。我应该预先警告您要非常小心,尽管您需要重置在 kvlanguage 中设置的绑定,但是这样您就失去了 kv 语言的优势……只有在您真正了解自己在做什么时才使用它。

于 2013-07-08T07:13:19.600 回答
0

根据@qua-non 的建议,我暂时将孩子转移到另一位家长那里。它实际上解除了它的绑定,或者可能将它重新绑定到新的父级。无论出于何种原因,这是一个部分解决方案,当我将其从 GridLayout 中取出(即当我按下回车键时)并将其放入新的父级时,它不会自动更新位置。我需要在“开箱即用”按钮之后按“向上”(或“向下”)。

但是,它确实会立即返回。当您第二次再次单击“开箱即用”按钮时,它会回到原来的位置。这部分工作完美。它继续服从其父母的指示。

换句话说,当我从网格中取出时它不会立即起作用,但是当我把它放回去时它会起作用。

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
    float: _float
    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"
    FloatLayout:
        id: _float
        size_hint: None,None
""")

class Example(FloatLayout):
    def centerize(self, instance):
        if self.center_button.parent == self.center_widget:
            self.center_widget.remove_widget(self.center_button)
            self.float.add_widget(self.center_button)
            self.float.size = self.center_button.size
            self.float.x = self.center_button.x
            self.float.center_y = self.center_y
        else:
            self.float.remove_widget(self.center_button)
            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()
于 2013-07-08T02:49:42.480 回答
0

这是与我尝试的非常相似的东西。不同之处在于我结束了手动绑定属性,因此我可以取消绑定它们。基本上,如果我取消注释#pos: self.parent.pos“开箱即用”按钮的行,那么除非我Button按照@qua-non 的建议将其分配给另一个父级,否则我无法取消绑定它们。

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder

Builder.load_string("""
<Example>:
    center_button: _center_button
    GridLayout:
        cols: 3
        size_hint: .7, .3
        pos_hint: {'center_x': .5}
        Button:
            on_press: self.parent.y = 0
            text: "Down"
        Widget:
            Button:
                id: _center_button
                size: self.parent.size
                #pos: self.parent.pos
                on_press: root.centerize(*args)
                text: "Out of the Grid"
        Button:
            on_press: self.parent.top = root.height
            text: "Up"
""")

class Example(FloatLayout):
    def __init__(self, **kwargs):
        super(Example, self).__init__(**kwargs)
        self.center_button.parent.bind(pos=self.binder)
        self.centered = False

    def binder(self, instance, value):
        self.center_button.pos = instance.pos

    def centerize(self, instance):
        if self.centered:
            self.center_button.parent.bind(pos=self.binder)
            self.center_button.y = self.center_button.parent.y
            self.centered = False
        else:
            self.center_button.parent.unbind(pos=self.binder)
            self.center_button.center_y = self.height/2
            self.centered = True

class ExampleApp(App):
    def build(self):
        return Example()

if __name__ == "__main__":
    ExampleApp().run()
于 2013-07-08T15:55:40.170 回答