#python #kivy
#python #kivy
Вопрос:
Давайте начнем с базового примера:
class OuterWidget(Widget):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
print('on_touch_down', self)
return True # doesn't dispatch to InnerWidget
return super().on_touch_down(touch)
class InnerWidget(Widget):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
print('on_touch_down', self)
return super().on_touch_down(touch)
Событие отправляется OuterWidget
первому, если оно вызывает super().on_touch_down(touch)
отправку событий дочерним виджетам, иначе событие не отправляется следующим. Это понятно.
Я хочу создать некоторое поведение, которое происходит с on_touch_down
и действует таким же образом. Давайте попробуем:
class TestBehavior(Widget):
def __init__(self, **kwargs):
self.register_event_type('on_test_event')
super().__init__(**kwargs)
def on_test_event(self, touch):
pass
def on_touch_down(self, touch):
self.dispatch('on_test_event', touch) # Some event that happens with on_touch_down
return super().on_touch_down(touch)
class OuterWidget(TestBehavior, Widget):
def on_test_event(self, touch):
if self.collide_point(*touch.pos):
print('on_test_event', self)
return True # doesn't affect anything, both widgets would recieve on_test_event
return super().on_test_event(touch)
class InnerWidget(TestBehavior, Widget):
def on_test_event(self, touch):
if self.collide_point(*touch.pos):
print('on_test_event', self)
return True
return super().on_test_event(touch)
on_test_event
пузырящийся не будет работать так же, как on_touch_down
. Независимо от того OuterWidget
, куда будет отправлено возвращаемое событие InnerWidget
. Это происходит потому, что оба виджета получат on_touch_down
событие, которое срабатывает on_test_event
.
Похоже, что если я использую on_touch_down
для отправки какого-либо события в поведении, это событие всегда будет отправляться всем дочерним элементам, независимо от того, что любой из них вернул. Но я не хочу отправлять on_test_event
next, если какой-то виджет не вызывался super().on_test_event(touch)
.
Как я могу это сделать? Есть идеи?
Ответ №1:
Класс Widget обрабатывает свои события для всех своих дочерних элементов следующим образом:
(скопировано из widget.py )
def on_touch_down(self, touch):
'''Receive a touch down event.
:Parameters:
`touch`: :class:`~kivy.input.motionevent.MotionEvent` class
Touch received. The touch is in parent coordinates. See
:mod:`~kivy.uix.relativelayout` for a discussion on
coordinate systems.
:Returns: bool
If True, the dispatching of the touch event will stop.
If False, the event will continue to be dispatched to the rest
of the widget tree.
'''
if self.disabled and self.collide_point(*touch.pos):
return True
for child in self.children[:]:
if child.dispatch('on_touch_down', touch):
return True
Как вы можете видеть, он выполняет итерацию по своему дочернему элементу и отправляет событие до тех пор, пока не будет возвращено значение True.
Чтобы создать подобное поведение, вы можете создать свой собственный класс mix-in и сделать весь свой класс неотъемлемым от него или в ** monkey patch Widget **
ИМХО, это будет немного запутанно, я бы сделал, чтобы создать функцию:
def fire_my_event(widget):
if hasattr(widget, 'on_test_event'):
if widget.on_test_event():
return True
for c in widget.children[:]:
if fire_my_event(c):
return True
#in your code somewhere
class SomeWidget(Image): #or anything else ...
def on_touch_down(self, touch):
fire_my_event(self)
Получайте удовольствие!