• kivy Properties


    Introduction to Properties

    Properties are an awesome way to define events and bind to them. Essentially, they produce events such that when an attribute of your object changes, all properties that reference that attribute are automatically updated.

    There are different kinds of properties to describe the type of data you want to handle.

    Declaration of a Property

    To declare properties, you must declare them at the class level. The class will then do the work to instantiate the real attributes when your object is created. These properties are not attributes: they are mechanisms for creating events based on your attributes:

    class MyWidget(Widget):
    
        text = StringProperty('')
    

    When overriding __init__, always accept **kwargs and use super() to call the parent’s __init__ method, passing in your class instance:

    def __init__(self, **kwargs):
        super(MyWidget, self).__init__(**kwargs)
    

    Dispatching a Property event

    Kivy properties, by default, provide an on_<property_name> event. This event is called when the value of the property is changed.

    Note

    If the new value for the property is equal to the current value, then the on_<property_name> event will not be called.

    For example, consider the following code:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
     class CustomBtn(Widget):
    
         pressed = ListProperty([0, 0])
    
         def on_touch_down(self, touch):
             if self.collide_point(*touch.pos):
                 self.pressed = touch.pos
                 return True
             return super(CustomBtn, self).on_touch_down(touch)
    
         def on_pressed(self, instance, pos):
             print ('pressed at {pos}'.format(pos=pos))
    

    In the code above at line 3:

    pressed = ListProperty([0, 0])
    

    We define the pressed Property of type ListProperty, giving it a default value of [0, 0]. From this point forward, the on_pressed event will be called whenever the value of this property is changed.

    At Line 5:

    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            self.pressed = touch.pos
            return True
        return super(CustomBtn, self).on_touch_down(touch)
    

    We override the on_touch_down() method of the Widget class. Here, we check for collision of the touch with our widget.

    If the touch falls inside of our widget, we change the value of pressed to touch.pos and return True, indicating that we have consumed the touch and don’t want it to propagate any further.

    Finally, if the touch falls outside our widget, we call the original event using super(…) and return the result. This allows the touch event propagation to continue as it would normally have occurred.

    Finally on line 11:

    def on_pressed(self, instance, pos):
        print ('pressed at {pos}'.format(pos=pos))
    

    We define an on_pressed function that will be called by the property whenever the property value is changed.

    Note

    This on_<prop_name> event is called within the class where the property is defined. To monitor/observe any change to a property outside of the class where it’s defined, you should bind to the property as shown below.

    Binding to the property

    How to monitor changes to a property when all you have access to is a widget instance? You bind to the property:

    your_widget_instance.bind(property_name=function_name)
    

    For example, consider the following code:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
     class RootWidget(BoxLayout):
    
         def __init__(self, **kwargs):
             super(RootWidget, self).__init__(**kwargs)
             self.add_widget(Button(text='btn 1'))
             cb = CustomBtn()
             cb.bind(pressed=self.btn_pressed)
             self.add_widget(cb)
             self.add_widget(Button(text='btn 2'))
    
         def btn_pressed(self, instance, pos):
             print ('pos: printed from root widget: {pos}'.format(pos=.pos))
    

    If you run the code as is, you will notice two print statements in the console. One from the on_pressed event that is called inside the CustomBtn class and another from the btn_pressed function that we bind to the property change.

    The reason that both functions are called is simple. Binding doesn’t mean overriding. Having both of these functions is redundant and you should generally only use one of the methods of listening/reacting to property changes.

    You should also take note of the parameters that are passed to the on_<property_name> event or the function bound to the property.

    def btn_pressed(self, instance, pos):
    

    The first parameter is self, which is the instance of the class where this function is defined. You can use an in-line function as follows:

    1
    2
    3
    4
    5
    6
    7
     cb = CustomBtn()
    
     def _local_func(instance, pos):
         print ('pos: printed from root widget: {pos}'.format(pos=pos))
    
     cb.bind(pressed=_local_func)
     self.add_widget(cb)
    

    The first parameter would be the instance of the class the property is defined.

    The second parameter would be the value, which is the new value of the property.

    Here is the complete example, derived from the snippets above, that you can use to copy and paste into an editor to experiment.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     from kivy.app import App
     from kivy.uix.widget import Widget
     from kivy.uix.button import Button
     from kivy.uix.boxlayout import BoxLayout
     from kivy.properties import ListProperty
    
     class RootWidget(BoxLayout):
    
         def __init__(self, **kwargs):
             super(RootWidget, self).__init__(**kwargs)
             self.add_widget(Button(text='btn 1'))
             cb = CustomBtn()
             cb.bind(pressed=self.btn_pressed)
             self.add_widget(cb)
             self.add_widget(Button(text='btn 2'))
    
         def btn_pressed(self, instance, pos):
             print ('pos: printed from root widget: {pos}'.format(pos=pos))
    
     class CustomBtn(Widget):
    
         pressed = ListProperty([0, 0])
    
         def on_touch_down(self, touch):
             if self.collide_point(*touch.pos):
                 self.pressed = touch.pos
                 # we consumed the touch. return False here to propagate
                 # the touch further to the children.
                 return True
             return super(CustomBtn, self).on_touch_down(touch)
    
         def on_pressed(self, instance, pos):
             print ('pressed at {pos}'.format(pos=pos))
    
     class TestApp(App):
    
         def build(self):
             return RootWidget()
    
    
     if __name__ == '__main__':
         TestApp().run()
    

    Running the code above will give you the following output:

    ../_images/property_events_binding.png

    Our CustomBtn has no visual representation and thus appears black. You can touch/click on the black area to see the output on your console.

    Compound Properties

    When defining an AliasProperty, you normally define a getter and a setter function yourself. Here, it falls on to you to define when the getter and the setter functions are called using the bind argument.

    Consider the following code.

    1
    2
    3
    4
    5
    6
    7
     cursor_pos = AliasProperty(_get_cursor_pos, None, bind=(
         'cursor', 'padding', 'pos', 'size', 'focus',
         'scroll_x', 'scroll_y'))
     '''Current position of the cursor, in (x, y).
    
     :attr:`cursor_pos` is a :class:`~kivy.properties.AliasProperty`, read-only.
     '''
    

    Here cursor_pos is a AliasProperty which uses the getter _get_cursor_pos with the setter part set to None, implying this is a read only Property.

    The bind argument at the end defines that on_cursor_pos event is dispatched when any of the properties used in the bind= argument change.

  • 相关阅读:
    [置顶] 也论百度轻应用--一个开发者的吐槽
    HDU 1506 Largest Rectangle in a Histogram
    [置顶] 搭建apache+tomcat+memcached集群环境
    (step8.2.6)hdu 1848(Fibonacci again and again——组合博弈)
    SQL2005、2008、2000 清空删除日志
    网络获取北京时间和系统时间
    C++界面库
    Cocos2d-X游戏开发之Windows7+VS2010环境搭建(亲测)
    华为面试题——一道关于指针方面的编程题(C/C++)
    java之Math
  • 原文地址:https://www.cnblogs.com/pythonClub/p/10537570.html
Copyright © 2020-2023  润新知