如何取消绑定用Kivy语言自动绑定的属性? [英] How to unbind a property automatically binded in Kivy language?

查看:80
本文介绍了如何取消绑定用Kivy语言自动绑定的属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Widget:
    Label:
        pos: self.parent.pos

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

这里有一个小例子来说明我的意思. Button GridLayout移至顶部,将Down移至底部. Button Center (中心)位于屏幕中央.我的问题是,当我单击向上向下时,居中"按钮不再存在.

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上使用不断更新位置的动画.按钮的正常位置应在网格布局内,但有时按钮之一会飞过屏幕并返回相同位置.问题是我无法在我的网格布局也移动的同时使它们飞行,因为该属性已绑定,并且一旦尝试飞行的按钮将立即返回到网格.这也意味着绑定有时是理想的.我想要的是控制绑定和取消绑定.

解决方案

评论现在似乎无效,因此我将其发布为答案.

  1. 您已经有一个FloatLayout(您的根窗口小部件).用它代替 创建一个新的FloatLayout.
  2. 从网格中删除窗口小部件之前.
    • 存储它的大小,
    • 将size_hint设置为无,无"
    • 设置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的属性,则可以使用自省来获取


Why do I want to do that in any case? I am using an animations on the GridLayout that constantly updates the position. The normal position of the buttons should be inside the gridlayout but once in a while one of the buttons flies over the screen and come back to the same position. The problem is that I cannot make them fly while my gridlayout is also moving because the property is bound and as soon as the button try to fly it goes back to the grid. That also means that the binding is sometimes desirable. What I want is have control of the bind and unbind.

解决方案

Comments don't seem to be working right now so I'll post this as a answer.

  1. You already have a FloatLayout(your root widget). Use that instead of creating a new FloatLayout.
  2. Before removing the widget from the grid.
    • store it's size,
    • set size_hint to None, None
    • set pos_hint to position the widget in the center.
  3. When adding the widget to grid do the reverse.

Here's your code with these fixes::

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

Update 1:

If for whatever reason you still need to unbind the properties bound by kvlang you can do so using introspection to get a list of observers for the property. so for your case it would be something like this::

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

You would need to use the latest master for this. I should fore-warn you to be extremely careful with this though you'd need to reset the bindings set in kvlanguage, but then you loose the advantage of kv language... Only use this If you really understand what you are doing.

这篇关于如何取消绑定用Kivy语言自动绑定的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆