如何使用tkinter.bind方法生成单个按键事件信号
我有一个简单的用户界面,它应该能打印出我按下的每一个键。
我需要每次真正按下键的时候只生成一次信号。
我该怎么做呢?
默认情况下,tkinter会在按下键时生成一次信号,然后会等大约0.5秒,再开始循环生成信号,直到发生KeyRelease事件。
if __name__ == '__main__':
from tkinter import Tk, Frame
root = Tk()
frame = Frame(root, width=200, height=200, bg="white")
frame.pack()
def key_handler(event):
print(event.char, event.keysym, event.keycode)
return 'break'
root.bind('<Key>', key_handler)
root.mainloop()
在绑定函数的末尾使用'break'并不能停止下一个事件的调用。
另外(因为这是一个小问题,不值得单独发帖),我该怎么创建这些按键组合呢?:
- "Shift"加上某个数字
- 某个数字加上'+'或'-'符号
更新: 我其实不想这样做:
def key_handler(event):
global eve
if eve != event.keysym:
eve = event.keysym
print(event.char, event.keysym, event.keycode)
因为信号在我想完全移除它的时候仍然在处理。但我不太清楚Dummy信号对整个程序的影响,所以这个解决方案可能有意义吗?
更新,包含用户的一些解决方案:
我把答案加在了问题的正文里,因为我不小心在添加答案之前关闭了问题,所以在这里分享一下:
这是一个使用绑定/解绑解决方案的例子:
class KeyHandler:
def __init__(self, key: str):
self.func_id = root.bind(f'<KeyPress-{key}>', self.key_press)
root.bind(f'<KeyRelease-{key}>', self.key_release)
def key_release(self, event: Event):
print('released', event.char)
self.func_id = root.bind(f'{event.char}', self.key_press)
def key_press(self, event: Event):
print('pressed', event.char)
root.unbind(f'{event.char}', self.func_id)
KeyHandler('1')
KeyHandler('2')
KeyHandler('3')
KeyHandler('4')
root.mainloop()
这是一个使用简单的状态检查解决方案的例子(处理所有与当前键相关的事件,可能会导致事件过多):
keys = []
def key_handler(event: Event):
global keys
if event.type is EventType.KeyPress:
if not (event.keycode in keys):
keys.append(event.keycode)
print('pressed', event.char)
elif event.type is EventType.KeyRelease:
if event.keycode in keys:
print('released', event.char)
keys.remove(event.keycode)
root.bind('<KeyPress-9>', lambda e: key_handler(e))
root.bind('<KeyRelease-9>', lambda e: key_handler(e))
1 个回答
2
问题在于,tkinter(一个用于制作图形界面的工具)无法区分单次按键和长按。有些系统上尤其如此。可能是你的键盘在向tkinter发送多个按键事件。换句话说,当用户长按一个键时,tkinter无法保证你只会收到一次按下和一次松开的信号。
你需要想出一些方法来判断什么算是一次独特的、故意的按键,什么又不是。你可以选择在按键和上一次按键不同时才报告,或者只有在相同按键之间经过一段时间后才报告,类似这样的方式。
如果不知道你期望用户长按一个键时会发生什么,就很难给出更具体的建议。