Python 使用Kivy为同一事件添加多个处理程序的最佳/正确方法是什么?
我最近发现了Kivy框架,目前正在使用。 我实现了一些函数,通过给palle类一些可以绑定到键盘事件的处理程序,可以用键盘控制拨片。 不幸的是,我对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
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
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开发中大量使用。感谢提供更多信息,我还不知道这些模式。