使用Kivy为同一事件添加多个处理程序的最佳/正确方法是什么?

时间:2018-03-17 10:00:13

标签: python event-handling kivy

我最近发现了Kivy-Framework,我现在正在玩PongGame-Example。 我实现了一些函数,通过给paddle类提供一些可以绑定到键盘事件的处理程序,可以用键盘控制拨片。 不幸的是,我与kivy的事件绑定有点挣扎。

首先,我在PongGame课程中尝试了以下内容

self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
self._keyboard.bind(on_key_down=self.player1.on_keyboard_down)
self._keyboard.bind(on_key_up=self.player1.on_keyboard_up)
self._keyboard.bind(on_key_down=self.player2.on_keyboard_down)
self._keyboard.bind(on_key_up=self.player2.on_keyboard_up)

在c#和WPF中,我曾经能够将多个处理程序绑定到同一个事件,我想我在Kivy的文档中看到了类似的东西。 不幸的是,在Kivy中,这似乎具有以下添加的绑定被后者覆盖的效果,这导致仅第二个桨能够移动。 在文档中,我发现kivy会阻止将函数作为处理程序多次添加,因此我尝试fbind而不是因为文档说

  

与bind()相反,它不会检查此函数和largs / kwargs之前是否已绑定此名称。因此,多次绑定相同的回调只会继续添加它。

我认为这两种方法都被视为同一个功能。不幸的是结果是一样的。

所以我所做的就是创建其他方法来将处理程序组合在一起并改为绑定它们。

def __init__(self, **kwargs):
    super(PongGame, self).__init__(**kwargs)
    self.player1.set_input_keys('w', 's')
    self.player2.set_input_keys('up', 'down')
    self._keyboard = Window.request_keyboard(self._keyboard_closed, self)

    self._keyboard.bind(on_key_down=self._on_key_down)
    self._keyboard.bind(on_key_up=self._on_key_up)

def _keyboard_closed(self):
    self._keyboard.bind(on_key_down=self._on_key_down)
    self._keyboard.bind(on_key_up=self._on_key_up)
    self._keyboard = None

def _on_key_down(self, keyboard, keycode, text, modifiers):
    self.player2.on_keyboard_down(keyboard, keycode, text, modifiers)
    self.player1.on_keyboard_down(keyboard, keycode, text, modifiers)

def _on_key_up(self, keyboard, keycode):
    self.player1.on_keyboard_up(keyboard, keycode)
    self.player2.on_keyboard_up(keyboard, keycode)

不幸的是,这有一个缺点,就是我不能解除个别处理程序的绑定。例如,当从两个玩家切换到一个玩家时。

我是kivy的新手并以某种方式表达了我将这辆车放在马前的感觉。

处理这个问题的权利或方法是什么?

此处填写代码https://pastebin.com/uq9pxHcF 除了我使用#:kivy 1.10.0之外,kv文件与tutorial (you may have to scroll down a bit)中的示例完全相同。

1 个答案:

答案 0 :(得分:1)

<强> 1。正确的方法

您可以使用_on_keyboard_down方法处理密钥代码。

class PongGame(Widget):
    ball = ObjectProperty(None)
    player1 = ObjectProperty(None)
    player2 = ObjectProperty(None)

    PLAYER1_UP = 'w'
    PLAYER1_DOWN = 's'
    PLAYER2_UP = 'up'
    PLAYER2_DOWN = 'down'
    SENSITIVITY = 10

    def __init__(self, **kwargs):
        super(PongGame, self).__init__(**kwargs)
        self._keyboard = Window.request_keyboard(
            self._keyboard_closed, self, 'text')
        self._keyboard.bind(on_key_down=self._on_keyboard_down)

    def _keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_keyboard_down)
        self._keyboard = None

    def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
        if keycode[1] == self.PLAYER1_UP:
            self.move_player(self.player1, self.SENSITIVITY)
        elif keycode[1] == self.PLAYER1_DOWN:
            self.move_player(self.player1, -self.SENSITIVITY)
        if keycode[1] == self.PLAYER2_UP:
            self.move_player(self.player2, self.SENSITIVITY)
        elif keycode[1] == self.PLAYER2_DOWN:
            self.move_player(self.player2, -self.SENSITIVITY)
        return True

    def move_player(self, player, displacement):
        player.center_y += displacement

    # serve_ball and update methods, ref tutorial
    # ...

注释

  • 为了能够只用一组键来玩两边,我们打破了if-elif链。
  • 使用_keyboard_closed un 绑定处理程序,参考docs中的示例。

<强> 2。处理程序处理

你对那辆车说得对,你倒退了。来自Event Dispatcher

  

如果回调已经绑定到给定的事件或属性,则不会再次添加它。

假设 相同的 处理程序无法多次添加到同一事件中,并使用常规绑定。您真正想要的是为同一事件调用 不同的 方法。幸运的是,这很容易......

def __init__(self, **kwargs):
    super(PongGame, self).__init__(**kwargs)
    self._keyboard = Window.request_keyboard(
        self._keyboard_closed, self, 'text')
    self._keyboard.bind(on_key_down=self._on_keyboard_down1)
    self._keyboard.bind(on_key_down=self._on_keyboard_down2)

def _keyboard_closed(self):
    self._keyboard.unbind(on_key_down=self._on_keyboard_down1)
    self._keyboard.unbind(on_key_down=self._on_keyboard_down2)
    self._keyboard = None

def _on_keyboard_down1(self, keyboard, keycode, text, modifiers):
    if keycode[1] == self.PLAYER1_UP:
        self.move_player(self.player1, self.SENSITIVITY)
    elif keycode[1] == self.PLAYER1_DOWN:
        self.move_player(self.player1, -self.SENSITIVITY)
    return True

def _on_keyboard_down2(self, keyboard, keycode, text, modifiers):
    if keycode[1] == self.PLAYER2_UP:
        self.move_player(self.player2, self.SENSITIVITY)
    elif keycode[1] == self.PLAYER2_DOWN:
        self.move_player(self.player2, -self.SENSITIVITY)
    return False

有一个问题,最后添加的处理程序应该返回False,否则它会将事件标记为已处理,并且永远不会调用第一个处理程序。

为了更深入的了解,我建议再看看kivy properties

  

调用这两个函数的原因很简单。绑定没有   意思是压倒一切。拥有这两个功能是多余的,你   通常应该只使用一种倾听/反应的方法   财产变化。