创建与on_touch_down一样调度事件冒泡的kivy行为

时间:2016-10-09 10:42:40

标签: 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的{​​{1}}事件。

如果我使用on_test_event在行为中派遣某个事件,这个事件将始终分派给所有孩子,无论他们返回什么内容。但是如果某个小部件没有调用on_touch_down,我希望不要发送on_test_event

我该怎么办?有什么想法吗?

1 个答案:

答案 0 :(得分:2)

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

正如你所看到的,它会迭代它的childern并发送事件直到 True 被返回。

要创建类似的行为,您可以创建自己的混合类,并使其所有类固有或** 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)

玩得开心!