Qt之自定義托盤


    說起Qt,真是個不錯的ui庫,不僅僅ui做的好,其他方面也不差,在平台擴展方面也是非常的強大。這篇文章我將會分析下qt的托盤,QSystemTrayIcon是qt的托盤類,托盤類的用途是什么我就不說了,自行百科就好,關鍵問題是我們要實現自定義的托盤。

    說起常用的客戶端軟件,qq,微信等聊天工具,有這么幾個托盤事件:

1、來消息圖標閃爍

2、氣泡消息提示

3、鼠標左鍵單擊、左鍵雙擊、右鍵單擊、滾動單擊

    上述這三種事件QSystemTrayIcon類都完全能夠解決,但是托盤的hover事件卻無能為力,如圖1所示,途圖中是幫助文檔中的一段描述,指明了只有在x11系統中,可以捕獲到系統的tooltip事件,其他系統都無能為力,我自己也看了下qt的源碼,果真是這樣的,有興趣的同學可以自行在研究下。

圖1 幫助文檔

    如圖2所示,qq有消息時,鼠標hover在圖盤彈出菜單,那么qq是怎么做的呢,既然qq都到做到了,這個功能我們自己想必肯定也能實現。

圖2 托盤hover彈框

    好了,上邊說了這么多,僅僅是為了鋪墊我自己實現的托盤,完全脫離了qt中的托盤類QSystemTrayIcon,不過也不能說完全脫離,部分代碼還是從qt源碼中摘出來的。文章的最后我附上我自己用qt實現的自定義托盤和下載別人用mfc自定義實現的自定義托盤。

    因為win32我自己也不是特別了解,因此我也是大概說下自定義托盤需要了解的東西,首先是NOTIFYICONDATA結構,這個結構百科講的特別詳細,看一下就知道怎么用,然后是Shell_NotifyIcon這個api,這個方法就是對托盤操作的接口。具體參數百科中說的很詳細,不過如果你不想看也無所謂,直接往下看也可以。對盤托的操作在windows平台下都是一樣的,關鍵問題是用qt怎么接受這個圖盤的hover和leave消息。

    關於這個托盤的實現我也是從mfc的示例代碼中獲取的啟發,然后用qt方法實現,接下來我就直接說下用qt實現的步驟:

1、首先我們需要了解下QAbstractNativeEventFilter這個接口類,繼承這個接口類的類可以把自己注冊到app中,然后就能獲取到整個app

的事件,事件的處理函數為nativeEventFilter,該類有3個參數,具體可以參見這篇文字qt捕獲全局windows消息 這個文章中說的不全是對的,不過能抓取到app消息應該是沒問你的,本篇博客的demo也是印證了這個問題。注冊代碼如下:

 1 qApp->installNativeEventFilter(this); 

2、第二步就是創建托盤圖標,創建托盤圖標的時候,windows提供了api,代碼如下:

 1 NOTIFYICONDATA    nid;
 2     QLabel *l = new QLabel;
 3     nid.cbSize = sizeof nid;
 4     nid.hIcon = qt_pixmapToWinHICON(QIcon(":/trayIcon/Resources/childrenWidget.ico").pixmap(16, 16));
 5     nid.hWnd = HWND(l->winId());
 6     nid.uCallbackMessage = WM_TRAYNOTIFY;
 7     nid.uID = 1;
 8     nid.uFlags = NIF_ICON | NIF_MESSAGE;
 9 
10     Shell_NotifyIcon(NIM_ADD, &nid);

    此處代碼中有一個標簽l,創建他是因為創建圖標時需要一個接受鼠標事件的窗口句柄hWnd,如果沒有句柄,那么托盤也不能創建成功;其他成員的含義從變量的命名上應該也能理解,我重點說下uFlags這個變量,他其實本身沒有什么含義,主要是為了標示NOTIFYICONDATA結構中其他成員那個是有效的,這個也方便了我們后續對托盤圖標的修改。比如說修改tooltip、修改圖標等信息。uCallbackMessage是消息id,在我們后續處理的邏輯中會用到

3、鼠標事件處理

 1 bool trayIcon::nativeEventFilter(const QByteArray & eventType, void * message, long * result)
 2 {
 3     if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG")
 4     {
 5         MSG * pMsg = reinterpret_cast<MSG *>(message);
 6         if (pMsg->message == WM_TRAYNOTIFY)
 7         {
 8             switch (pMsg->lParam)
 9             {
10             case WM_MOUSEMOVE:
11                 m_traypos.OnMouseMove();
12                 break;
13             case WM_MOUSEHOVER:
14                 m_Menu->show();
15                 break;
16             case WM_MOUSELEAVE:
17                 m_Menu->hide();
18                 break;
19             case WM_LBUTTONDBLCLK:
20             //    m_Menu->show();
21                 break;
22             case WM_LBUTTONDOWN:
23             //    m_Menu->show();
24                 break;
25             case WM_RBUTTONDOWN:
26             //    m_Menu->show();
27                 break;
28             }
29         }
30     }
31 
32     return false;
33 }

上述代碼主要是針對鼠標事件的一個處理。WM_TRAYNOTIFY消息是我們開始的時候注冊到圖盤中的消息,當托盤發生鼠標事件的時候我們只需要關注自己注冊的消息,對於windows托盤稍微有了解的同學可能也知道,微軟沒有提供給我們托盤圖標的進入和離開事件,而僅僅提供了鼠標move的事件,不過僅僅有這一個事件我們就可以模擬出其他的事件來。細心的同學將會注意到 m_traypos.OnMouseMove();這句代碼,其實m_tryapos這個對象是一個move事件處理類,他可以模擬出鼠標hover和leave事件來。關於這個類的解釋我就不說了,是一個國外的大牛寫的,demo中有源文件。

4、程序退出時銷毀托盤圖標

Shell_NotifyIcon(NIM_DELETE, &m_NotifyIconData);

    通過上述的代碼整理,簡單的托盤就可以實現了,因為我是自己做的demo,因此不是所有事件的處理了的,高級定制的功能如果有興趣的同學可以給我留言,或者私信我可以,如果是我實現了的,我將願意和大家一起分享。我下邊鏈接中的這個demo其實比較粗糙,就僅僅的可以實現鼠標在托盤圖標上的hover和leave請求。

    最后我上兩張效果圖,圖3是mfc示例的鼠標hover截圖,圖4是qt示例的鼠標hover截圖

圖3 mfc示例demo

圖4 qt示例demo

注意:這個demo非常粗糙,不過我已經講明了怎么實現一個自己的托盤,關於需要怎么實現一個完美的托盤,同學們可以參考qt的源碼中qsystemtrayicon_win.cpp文件,該文件就是QSystemTrayIcon類的真正實現。

qt示例鏈接:http://download.csdn.net/detail/qq_30392343/9608076

mfc示例鏈接:http://download.csdn.net/detail/qq_30392343/9608078

 

如果您覺得文章不錯,不妨給個 打賞,寫作不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!! 

 

  


很重要--轉載聲明

  1. 本站文章無特別說明,皆為原創,版權所有,轉載時請用鏈接的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords
  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM