【问题标题】:Change focus to Tkinter program using system-wide hotkey使用系统范围的热键将焦点更改为 Tkinter 程序
【发布时间】: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


【解决方案1】:

eryksun 指出了问题 - 我为热键使用了错误的大小写。 ord("v") 应该是 ord("V")

【讨论】:

  • 我认为this answer 是在 tkinter 中处理 RegisterHotKey 和 GetMessageA 的正确方法。您还需要退出(例如在关闭应用程序时)等待消息,因为 GetMessageA 仅在收到某些内容后才返回。
  • 感谢链接人。 Tkinter 似乎很难理解。
猜你喜欢
  • 2011-04-15
  • 2012-05-30
  • 1970-01-01
  • 2012-01-04
  • 2012-04-30
  • 1970-01-01
  • 2014-03-17
  • 2013-12-07
相关资源
最近更新 更多