Qt/PyQt中使用系统全局的快捷键

本文介绍如何在Qt和PyQt中实现系统全局快捷键的功能,包括使用RegisterHotKey注册快捷键,以及重载QApplication的winEventFilter函数来响应快捷键事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Qt/PyQt中使用系统全局的快捷键

除了全局快捷键部分外,其他的都比较简单,都是我实现“onekeycodehighlighter"中碰到的一些小问题,这里顺面整理一下。事实上,稍微懂一点的人,去看看one key code highlighter的源代码都能明白了。这里相当于将其详细的剖析一下。。。。。。。另外,实现上用Python+PyQt,事实上,主要的部分是对Qt的一些类的使用,所以其实看懂了C++的Qt中使用上是一样的。啥?你看不懂Python?好的,这就是我为什么靠C++吃饭,却学习JAVA,JavaScript,Lua,Python,Bash的一个原因,不然你看不懂别人在写啥-_-!(当然,我基本上也就学到能看懂)
对于pyQt完全不懂的,这里也不用看了,《pyqt的学习(1) 入门》,《pyqt(2) 对话框...

概述

使用系统全局的快捷键总是键很酷的事情,在你的程序已经失去焦点的时候,还能响应用户的按键,完成任务,多酷啊。特别的,我的one key code highlighter只有一个SystemTrayIcon(托盘图标)和一些菜单,不使用系统全局的快捷键而用菜单去实现命令的话,我还不如用快捷方式去使用chc2c呢(就如我以前做的那样)。所以,对于这个我自己需要而实现的软件,怎么说,也需要有这个功能,无奈的是,偏偏Qt中其实原生不支持此功能,那么,只好放弃移植性去使用win32 API了。

Qt中的实现

主要的API为:(来自MSDN)

BOOL RegisterHotKey(          HWND hWnd,
    int id,
    UINT fsModifiers,
    UINT vk
);

Qt中实现并不算什么大问题,《Qt中使用全局热键》中有一些说明,此文说明了一件事情,技术文章的价值不以篇幅来衡量,而是以技术含量衡量,此文没有太多的文字,但是详细解释了所有过程。
主要步骤为用RegisterHotKey向系统注册全局的快捷键,然后重载QApplication的winEventFilter函数,并响应msg为WM_HOTKEY时的消息,整个过程类似于在Windows下的OnMessage进行消息响应,只是这次是在Qt中。原文给出的示例代码如下:(原文排版有点乱,但是不损其技术价值)

bool winEventFilter(MSG *msg, long *result)
{
    if(WM_HOTKEY==msg->message)
    {
        qDebug()<<"winmsg return true";
        emit hotKey(int(msg->wParam),LOWORD(msg->lParam),HIWORD(msg->lParam));
        return TRUE;
    }
    return FALSE;
}
这种实现很简单,我就不多说了,Qt嘛,毕竟还是C++,只不过这里放弃移植性调用Win32 API,并且响应消息而已,没有什么太多新的东西。

PyQt中的实现

相对于Qt中的实现来说,对于Qt中没有的东西,很显然PyQt中也很难有了,那么,我们还是只能通过调用Win32 API了,而在Python中调用Win32 API就没有那么太简单了。。。。。。。
介绍的是用ctypes来调用,当然,因为感觉此部分会与本主题太偏,所以额外写了一篇文章讲述。《Python与C之间的相互调用(Python C API及Python ctypes库)》,看了前文就会知道,其实用Python C API包装以下RegisterHotKey也可以实现一样的效果,知识用ctypes更简单一些。
这里就直接讲RegisterHotKey的调用了。以下是一些代码片段。。。。。

from ctypes import c_bool, c_int, WINFUNCTYPE, windll
from ctypes.wintypes import UINT

prototype = WINFUNCTYPE(c_bool, c_int, c_int, UINT, UINT)
paramflags = (1, 'hWnd', 0), (1,'id', 0), (1,'fsModifiers', 0), (1,'vk', 0)
self.RegisterHotKey = prototype(('RegisterHotKey', windll.user32), paramflags)

r = self.RegisterHotKey(c_int(self.mainWindow.winId()), HOT_KEY_ID, config.modifier, ord( config.hotkey.upper() ))
if not r:
      QtGui.QMessageBox.critical(None, 'Hot key','Can't Register Hotkey Win + Z')
      sys.exit(1)
这里用了比直接调用RegisterHotKey更复杂的方法来使用ctypes,(在Python与C之间的相互调用(Python C API及Python ctypes库)》中描述了最简单的办法),好处是实现了“命名参数”及参数默认值,这里虽然实际没有使用-_-!另外,利用config中的配置的大写字母的ord,来表示Windows中的虚拟键值真是很方便,为什么这样能省去那一大堆的VK_*定义?因为WinUser.h中就是这样定义这些VK_*的。。。。。。。
还有,mainWindow实际是一个QMainWindow的对象,其winId函数可以获取到Windows窗口的句柄,这里将其转化为c_int而不是HWND,因为在Python中不允许int到HWND的转换(这有点扭曲),知道原因的请告诉我。完成了这些后,QApplication的winEventFilter函数的重载还是少不了的。

以下是我的一段实现代码:

    # these code don't have compatibility with other OS
    def winEventFilter(self, msg):
        debug_out("Message:" + str(hex(msg.message)) )
        if msg.message == WM_HOTKEY:
            if isClipboardEmpty():
                self.mainWindow.trayIcon.showMessage("failed","Clipboard is Empty.")
                return True, 0
            debug_out("Got the Hotkey!")
            debug_out(config.filename)
            
            import imp
            imp.reload(config)
            chc2c(self.mainWindow.syn, config.color, config.isLineNumber, config.filename)
            self.mainWindow.trayIcon.showMessage("success","transformed the data in clipboard to html.")
            return True, 0
        
        return False, 0

基本思路与C++中并无差异,查找到WM_HOTKEY,然后响应之。我这里利用了reload来达到每次都动态查询配置的效果^^chc2c就是我的主要函数。
以上就是PyQt中实现全局快捷键的全部过程了。

另外,我本来以为假如愿意使用PyWin32的话,直接可以调用其中的RegisterHotKey,后来竟然在里面没有找到,奇了怪了。

参考文章

Qt中使用全局热键

完整源代码获取说明

由于篇幅限制,本文一般仅贴出代码的主要关心的部分,代码带工程(或者makefile)完整版(如果有的话)都能用MercurialGoogle Code中下载。文章以博文发表的日期分目录存放,请直接使用Mercurial克隆下库:

https://onekeycodehighlighter.googlecode.com/hg/

Mercurial使用方法见《分布式的,新一代版本控制系统Mercurial的介绍及简要入门

要是仅仅想浏览全部代码也可以直接到google code上去看,在下面的地址:

http://code.google.com/p/onekeycodehighlighter/source/browse/

 

 



<think>我们参考了多个引用,其中引用[1]和引用[3]展示了使用QShortcut类来创建快捷键,并绑定到函数上。 引用[2]提到了QKeySequenceEdit用于输入快捷键,但用户的问题是如何设置和使用快捷键,所以主要关注设置方法。 引用[4]和引用[5]展示了两种设置快捷键的方法:一种是直接给控件设置快捷键(setShortcut),另一种是使用QShortcut创建独立的快捷键。 根据用户的问题,我们需要介绍两种主要方法: 1. 使用控件的setShortcut方法(适用于按钮等控件) 2. 使用QShortcut类(适用于全局快捷键或没有关联控件的快捷键) 步骤: 1. 导入必要的模块:从PyQt5.QtWidgets导入QShortcut,从PyQt5.QtGui导入QKeySequence。 2. 设置快捷键的方式有两种: a. 对于按钮等控件,可以直接使用setShortcut方法,参数为字符串(如"Ctrl+S")或QKeySequence对象。 b. 使用QShortcut类创建快捷键对象,然后连接其activated信号到槽函数。 注意:使用QShortcut创建的快捷键全局的(在应用程序激活时有效),而控件自带的setShortcut通常只在控件获得焦点时有效(除非设置setShortcutEnabled(True)并确保控件在窗口内)。但根据PyQt文档,QShortcut创建的快捷键在窗口内有效(除非设置了上下文,如Qt.ApplicationShortcut等)。 下面我们给出两种方法的示例代码。</think>在 PyQt5 中设置和使用快捷键主要有两种方法,下面我将详细介绍具体实现步骤: ### 方法一:使用 QShortcut 类(推荐) 这是最灵活的方式,可以创建全局快捷键: ```python from PyQt5.QtWidgets import QShortcut, QApplication from PyQt5.QtGui import QKeySequence class MyWindow(QMainWindow): def __init__(self): super().__init__() # 创建快捷键对象 shortcut_save = QShortcut(QKeySequence("Ctrl+S"), self) shortcut_save.activated.connect(self.save_file) shortcut_quit = QShortcut(QKeySequence("Ctrl+Q"), self) shortcut_quit.activated.connect(self.close) def save_file(self): print("保存文件操作") ``` ### 方法二:使用控件的 setShortcut() 方法 适用于按钮等控件的快捷键绑定: ```python from PyQt5.QtWidgets import QPushButton class MyWindow(QMainWindow): def __init__(self): super().__init__() # 创建按钮并设置快捷键 btn_save = QPushButton("保存(S)", self) btn_save.setShortcut("Ctrl+S") # 设置快捷键 btn_save.clicked.connect(self.save_file) # 也可以使用助记符 btn_quit = QPushButton("退出(&Q)") # Alt+Q 作为快捷键 btn_quit.clicked.connect(self.close) ``` ### 关键说明: 1. **快捷键格式**: - 单键:`"F1"`, `"Space"`, `"Esc"` - 组合键:`"Ctrl+C"`, `"Shift+Alt+T"`, `"Ctrl+Shift+R"` - 标准快捷键:`QKeySequence.Save`, `QKeySequence.Quit` 2. **特殊键位码**: ```python from PyQt5.QtCore import Qt # 使用键位码组合 shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_S), self) ``` 3. **作用范围**: - `QShortcut` 创建的快捷键在窗口激活时全局有效 - `setShortcut()` 设置的快捷键仅在控件获得焦点时有效 4. **注意事项**: - 避免快捷键冲突(如多个功能使用相同快捷键) - 跨平台兼容性:Mac 系统使用 `Cmd` 键代替 `Ctrl` 键 - 使用标准快捷键可自动适应不同操作系统[^2] ### 完整示例 ```python import sys from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QShortcut, QTextEdit) from PyQt5.QtGui import QKeySequence class EditorWindow(QMainWindow): def __init__(self): super().__init__() # 文本编辑区 self.text_edit = QTextEdit(self) self.setCentralWidget(self.text_edit) # 按钮快捷键 btn_clear = QPushButton("清空(&C)", self) btn_clear.move(10, 10) btn_clear.setShortcut("Ctrl+Shift+C") btn_clear.clicked.connect(self.clear_text) # 全局快捷键 QShortcut(QKeySequence("Ctrl+Z"), self).activated.connect(self.undo) QShortcut(QKeySequence("Ctrl+S"), self).activated.connect(self.save) QShortcut(QKeySequence.Print, self).activated.connect(self.print) def clear_text(self): self.text_edit.clear() def undo(self): self.text_edit.undo() def save(self): print("文件保存操作") def print(self): print("打印操作") if __name__ == "__main__": app = QApplication(sys.argv) window = EditorWindow() window.show() sys.exit(app.exec_()) ``` ### 最佳实践建议: 1. 使用标准快捷键提高用户体验一致性 2. 为常用功能提供键盘替代方案 3. 在菜单项/按钮文本中显示快捷键提示 4. 使用 `QKeySequenceEdit` 允许用户自定义快捷键[^2] 5. 禁用上下文不相关的快捷键(如无选中文本时禁用复制) [^1]: PyQt5 提供了多种设置快捷键的方式,包括 QShortcut 和控件内置方法 [^2]: QKeySequenceEdit 可用于创建自定义快捷键输入界面 [^3]: 全局快捷键绑定推荐使用 QShortcut 实现 [^4]: setShortcut() 方法适用于按钮等控件的快捷键设置 [^5]: 按钮快捷键可配合助记符(&)使用,提高可访问性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI算法网奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值