如何使用tkinter.bind方法生成单个按键事件信号

1 投票
1 回答
58 浏览
提问于 2025-04-12 15:10

我有一个简单的用户界面,它应该能打印出我按下的每一个键。
我需要每次真正按下键的时候只生成一次信号。
我该怎么做呢?
默认情况下,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无法保证你只会收到一次按下和一次松开的信号。

你需要想出一些方法来判断什么算是一次独特的、故意的按键,什么又不是。你可以选择在按键和上一次按键不同时才报告,或者只有在相同按键之间经过一段时间后才报告,类似这样的方式。

如果不知道你期望用户长按一个键时会发生什么,就很难给出更具体的建议。

撰写回答