2

I'm testing Kivy v1.10.0, and don't understand why the location where I set a Kivy property makes a difference.

This code works:

from kivy.app import App
from kivy.properties import ListProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget


class CustomBtn(Widget):
    pressed = ListProperty([0, 0])

    def __init__(self, **kwargs):
        super(CustomBtn, self).__init__(**kwargs)
        # self.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)


class RootWidget(BoxLayout):
    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        cb = CustomBtn()
        self.add_widget(cb)
        cb.bind(pressed=self.btn_pressed)

    def btn_pressed(self, instance, pos):
        print(pos)


class MyApp(App):
    def build(self):
        return RootWidget()


if __name__ == '__main__':
    MyApp().run()

However, if I replace the line currently at class level:

pressed = ListProperty([0, 0])

by the equivalent in CustomBtn.__init__():

self.pressed = ListProperty([0, 0])

I get an error in instruction cb.bind(pressed=self.btn_pressed):

File "kivy\_event.pyx", line 438, in kivy._event.EventDispatcher.bind (kivy\_event.c:6500)
KeyError: 'pressed'

I believe declaring (assigning) an attribute at class level out of any method and doing the same in __init__() were equivalent. Kivy properties are not Python attributes, and maybe the sequence in which objects are built is different and makes a difference for Kivy?

mins
  • 4,503
  • 9
  • 45
  • 62

1 Answers1

2

I believe declaring (assigning) an attribute at class level out of any method and doing the same in __init__() were equivalent.

Nope. Kivy's properties - are descriptors (way it works). Descriptor object should be stored in class to work. It's Python thing - nothing Kivy specific.

Mikhail Gerasimov
  • 27,590
  • 10
  • 86
  • 127
  • I commented an answer on the linked question (I did that earlier but forgot since then): An instance attribute which is a descriptor will be rebound to the type of the assigned value if assigned again (e.g. `self.pressed = touch.pos` discards the descriptor and rebound `pressed` to `pos`). – mins Nov 04 '17 at 13:25
  • if you try that you'll see that no, since the class manages its attribute setting, it won't accept the new value if it's of the wrongr type. – Tshirtman Nov 06 '17 at 01:03