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

Python 使用Kivy为同一事件添加多个处理程序的最佳/正确方法是什么?,python,event-handling,kivy,Python,Event Handling,Kivy,我最近发现了Kivy框架,目前正在使用。 我实现了一些函数,通过给palle类一些可以绑定到键盘事件的处理程序,可以用键盘控制拨片。 不幸的是,我对kivy的事件绑定有点纠结 起初,我在我的乒乓球课上尝试了以下方法 self._keyboard = Window.request_keyboard(self._keyboard_closed, self) self._keyboard.bind(on_key_down=self.player1.on_keyboard_down) self._key

我最近发现了Kivy框架,目前正在使用。 我实现了一些函数,通过给palle类一些可以绑定到键盘事件的处理程序,可以用键盘控制拨片。 不幸的是,我对kivy的事件绑定有点纠结

起初,我在我的乒乓球课上尝试了以下方法

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)
不幸的是,这有一个缺点,即我无法解除单个处理程序的绑定。例如,当从两名玩家切换到一名玩家时

我是新来基维的,不知怎么的,我觉得我在这里是本末倒置

处理这个问题的正确方法是什么

完整的代码在这里
kv文件与中的示例完全相同,只是我使用了
:kivy 1.10.0

1。正确的方法

您可以使用键盘上的下键方法处理按键代码

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链
  • 使用
    \u keyboard\u closed
    解除处理程序的绑定,请参考中的示例
2。处理程序处理

你说得对,你把车倒了。从:

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

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

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:

调用这两个函数的原因很简单。绑定不起作用 意思是压倒一切。拥有这两个功能是多余的,您可以 通常应仅使用倾听/回应的方法之一 属性更改


共享.kv………@eyllansc抱歉,kv文件与教程中的相同。除了版本之外,我没有对kv文件中的代码做任何更改。更新了我的问题我的初始解决方案与您的第一个示例类似,但后来我突然想到,我可能应该在Paile类中实现输入处理,我当时就是这么做的,这就是最终让我在绑定方面遇到麻烦的原因。像我这样做本身就是错误的吗?一开始我觉得它更聪明,因为我不必为其他玩家(桨)编写额外的处理代码,尽管我已经可以想到其他的缺点。例如,在设计过程的后期,当Papper类被其他类替换时,处理代码必须重新编写。@Takiro将Papper与输入源紧密耦合,灵活性很低。您可以通过添加抽象层来实现松散耦合。这可以像我的
move\u player
功能一样简单。进入设计模式的世界,和支持松耦合,并在游戏和GUI开发中大量使用。感谢提供更多信息,我还不知道这些模式。