【发布时间】:2014-05-07 19:48:50
【问题描述】:
我正在尝试注册一个系统范围的热键,它将在我的 Tkinter 程序中触发一些操作。我使用this 作为参考。当我从该链接运行代码时,它工作正常。我正在努力将那里的循环与 Tkinter 中的事件循环集成。
Tkinter 循环需要定期检查被按下的热键。这应该是微不足道的,使用root.after()。但是,该程序似乎根本没有注意到被按下的热键,即使它处于焦点位置也是如此。
这是一个简洁的代码示例 - 它尽可能简短。它代表我尝试修改链接中的代码以与 Tkinter 很好地配合。
from tkinter import *
import ctypes
from ctypes import wintypes
import win32con
user32 = ctypes.windll.user32
byref = ctypes.byref
def hotkey_handler(root):
msg = wintypes.MSG()
if user32.GetMessageA(byref(msg), None, 0, 0) != 0:
if msg.message == win32con.WM_HOTKEY:
if msg.wParam == 1:
print("hotkey pressed")
user32.TranslateMessage(byref(msg))
user32.DispatchMessageA(byref(msg))
root.after(1, hotkey_handler, root)
root = Tk()
if user32.RegisterHotKey(None, 1, win32con.MOD_SHIFT, ord("v")) != 0:
print("--Hotkey registered!")
root.after(1, hotkey_handler, root)
root.mainloop()
我注意到的一个怪癖是,如果我将 root.after() 的第一个参数设置为零,则 GUI 无法正确绘制,Python 有时会崩溃。
【问题讨论】:
-
如果将值设置为零,它会使事件循环饿死——它忙于清空永不为空的“之后”队列,以至于它从来没有时间服务任何其他类型的事件(例如作为重绘请求)。
-
@BryanOakley:谢谢,这清楚了。我想是这样的,但我很难理解事件队列的概念。
-
@eryksun:我对多线程几乎一无所知。我试图不惜一切代价避免这种方法,部分原因是对于我想要实现的目标来说,这似乎完全是矫枉过正。按下热键时,必须在 Tk 窗口中触发某种响应。因此不是必须将热键消息发布到 Tk 窗口吗?还是我误解了(很可能!)消息是如何工作的?
-
@eryksun:哈利路亚!非常感谢!不敢相信这是一件如此愚蠢的事情……但它总是如此,不是吗? :)(我不会使用 Shift+V,这只是为了说明目的。Win+V 实际上是我的目标。)
标签: python python-3.x ctypes pywin32