如何解除以Kivy语言自动绑定的属性?

时间:2013-07-06 08:24:27

标签: python kivy

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

Widget:
    Label:
        pos: self.parent.pos

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

这是一个显示我的意思的小例子。 Button 向上GridLayout移至顶部,Down移至底部Button 中心中心位于屏幕中间。我的问题是,当我点击向上向下时,我的中心按钮就不再存在了。

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

3 个答案:

答案 0 :(得分:3)

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

  1. 您已经有一个FloatLayout(您的根小部件)。用它代替 创建一个新的FloatLayout。
  2. 从网格中删除小部件之前。
    • 存储它的大小,
    • 将size_hint设置为None,无
    • 设置pos_hint以将小部件放在中心位置。
  3. 将小部件添加到网格时,请执行相反的操作。
  4. 这是您使用这些修复程序的代码::

    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绑定的属性,你可以使用内省来获取属性的list of observers。所以对于你的情况,它将是这样的东西::

    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语言的优势......只使用它如果你真的明白你在做什么。< / p>

答案 1 :(得分: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()

答案 2 :(得分: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()