838
技術社區[雲棲]
[Qt Topic] – 全局熱鍵、托盤功能和隨機啟動
全局熱鍵、托盤功能和隨機啟動
作者:Jason Lee
日期:2010-04-24
平台:Qt SDKv2010.02.1 + Windows Xp
聲明:文章作者僅在Intel軟件網絡和CSDN博客發表本文,如有轉載,請注明出處
[1]全局熱鍵
Qt事件模型提供了這麼一個功能:在一個QObject實例遇到屬於它的事件之前,可以通過設置另外一個QObject實例來監視(過濾)這些事件。我們稱監視事件的對象為事件過濾器,即eventFilter。
通過QObject的eventFilter和installEventFilter兩個函數可以實現事件過濾的功能。前者的原型如下:
bool QObject::eventFilter(QObject *watched, QEvent *event)
該函數是一個虛函數,所以應該由子類(即用戶自定義的繼承於 QObject 類)來重新實現。實現了該虛函數的對象可以作為一個事件過濾器被安裝到指定對象上,目標對象通過使用 installEventFilter 來安裝事件過濾器:
void QObject::installEventFilter(QObject *filterObj)
上述是一段引言,現在回到全局熱鍵的問題。
要在 windows 下實現捕獲全局熱鍵的功能,自然免不了調用 windows API ,我們首先通過調用 API 向係統注冊全局熱鍵,然後通過事件過濾器來處理熱鍵消息。
注冊全局熱鍵的 API 如下:
BOOL RegisterHotKey( __in HWND hWnd, __in int id, __in UINT fsModifiers, __in UINT vk );
第一個參數是用來接收熱鍵消息的窗體句柄,我們將其設置為 Qt 中窗口 ID ;第二個參數是要設置的熱鍵標識;第三個參數代表組合鍵;第四個參數是熱鍵的虛擬鍵值。更詳細的信息可參閱 MSDN 。
當向係統注冊熱鍵成功後,就需要事件過濾器的功能了。由於這裏的事件是來自於 windows ,所以相應的事件過濾器就有點不同——需要使用 winEventFilter :
bool QCoreApplication::winEventFilter(MSG *msg long *result)
該成員函數也是一個虛函數,通過該過濾器可以處理 Qt 外部的消息。並且由於該函數是 QCoreApplication 的成員,要重寫該虛函數就要求我們自定義一個 QCoreApplication 的子類:
#ifndef QTAPP_H #define QTAPP_H #include <QApplication> #include <windows.h> class MyApp : public QApplication{ Q_OBJECT public: MyApp(int &argc, char **argv); ~MyApp(); virtual bool winEventFilter(MSG *msg, long *result); signals: void getF10HotKey(); void getF11HotKey(); }; #endif // QTAPP_H
最後我們在 winEventFilter 中處理熱鍵消息,並通過自定義的熱鍵信號來連接目標槽。在本實例中,通過熱鍵 F10 和 F11 來切換一個 checkBox 的選中狀態。並且因為是全局熱鍵,所以即便程序失去焦點,也可以響應到熱鍵消息。
[2] 托盤功能
Qt 中的托盤功能是通過 QSystemTrayIcon 類實現的。同時,該類還可以通過 setContextMenu 成員函數與 QMenu 類結合來產生一個上下文菜單。以下是一段具體代碼:
trayIcon = new QSystemTrayIcon(this); trayIcon->setIcon(QIcon(":/images/star.png")); trayMenu = new QMenu(this); showAct = new QAction(tr("Show"), this); hideAct = new QAction(tr("Hide"), this); exitAct = new QAction(tr("Exit"), this); trayMenu->addAction(showAct); trayMenu->addAction(hideAct); trayMenu->addSeparator(); trayMenu->addAction(exitAct); connect(showAct, SIGNAL(triggered()), this, SLOT(slotShowAct())); connect(hideAct, SIGNAL(triggered()), this, SLOT(slotHideAct())); connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); trayIcon->setContextMenu(trayMenu); connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayActived(QSystemTrayIcon::ActivationReason))); trayIcon->show();
係統托盤通過設置上下文菜單後,可以添加各種動作,從而產生一些指定行為。除此之外,如果我們要更生動地實現係統托盤圖標的顯隱,比如點擊關閉或者最小化按鈕後將程序隱藏到係統托盤中,而非實際關閉應用程序,可以通過結合 closeEvent 或者結合 changeEvent 來判斷 windowState 來重寫當用戶點擊關閉或者最小化按鈕時的處理代碼。
另外,托盤圖標可以做到的更生動的事是當有需要的時候可以彈出一個氣泡消息提示用戶,比如告知用戶某項下載任務已經完成。該功能則可以通過 QSystemTrayIcon 的成員函數 showMessage 來實現。
托盤功能的效果圖如下:
[3] 隨機啟動
在 Windows 下實現隨機啟動的功能,一般都是通過操作注冊表來實現的。我們可以考慮的 API 函數有:
LONG WINAPI RegCreateKeyEx( __in HKEY hKey, __in LPCTSTR lpSubKey, __reserved DWORD Reserved, __in_opt LPTSTR lpClass, __in DWORD dwOptions, __in REGSAM samDesired, __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, __out PHKEY phkResult, __out_opt LPDWORD lpdwDisposition );
可以通過結合第一個參數 hKey 和第二個參數 lpSubKey 來指定要在注冊表哪個位置上創建一個新項,並且由倒數第二個參數 phkResult 來指向獲得的項。其它的具體參數含義詳見 MSDN 。(項的解釋,來源於中文版的 windows 操作係統中的注冊表)
LONG WINAPI RegOpenKeyEx( __in HKEY hKey, __in_opt LPCTSTR lpSubKey, __reserved DWORD ulOptions, __in REGSAM samDesired, __out PHKEY phkResult );
顯然,同樣是通過 hKey 和 lpSubKey 來指定路徑,然後通過 phkResult 來指向獲得的項。
LONG WINAPI RegSetValueEx( __in HKEY hKey, __in_opt LPCTSTR lpValueName, __reserved DWORD Reserved, __in DWORD dwType, __in_opt const BYTE *lpData, __in DWORD cbData );
當我們打開一個項時,我們就獲得了該項的句柄。接著對該項進行操作時,比如修改某個值的內容,就需要該項的句柄作為第一個參數 hKey 。第二個參數是值名,如果項中不存在該值名則以改名添加一個新值到該項中。結合圖說明可以更加具體:
截止到 Run 是隨機啟動項在注冊表中所處的位置。
而新建項就是左邊這般模樣。
以上就是項中的值,有多種類型。我們可以通過往 Run 項添加新值來新增一個自啟動項目。
LONG WINAPI RegCloseKey( __in HKEY hKey );
操作結束後,需要記得關閉該項。
[ 後記 ] 我本來的預想示例程序是通過熱鍵來切換 checkBox 的選中狀態,進而控製程序是否隨機啟動,並且實現下係統托盤的簡單功能。但寫到這裏才發現已經淩晨,明天又有事情,所以目前隻實現了全局熱鍵和係統托盤的功能,而對於隨機啟動,隻放了兩個空函數在代碼中還沒來得及寫,隻是對相關 API 進行了一番粗略概覽。
希望大家不吝賜教。晚安 & 早安!
本實例源碼請見:https://download.csdn.net/source/2281281
最後更新:2017-04-02 05:21:03