很重要--轉載聲明
- 本站文章無特別說明,皆爲原創,版權全部,轉載時請用連接的方式,給出原文出處。同時寫上原做者:朝十晚八 or Twowords
- 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時經過修改本文達到有利於轉載者的目的。
提及Qt,真是個不錯的ui庫,不只僅ui作的好,其餘方面也不差,在平臺擴展方面也是很是的強大。這篇文章我將會分析下qt的托盤,QSystemTrayIcon是qt的托盤類,托盤類的用途是什麼我就不說了,自行百科就好,關鍵問題是咱們要實現自定義的托盤。html
提及經常使用的客戶端軟件,qq,微信等聊天工具,有這麼幾個托盤事件:windows
一、來消息圖標閃爍api
二、氣泡消息提示微信
三、鼠標左鍵單擊、左鍵雙擊、右鍵單擊、滾動單擊app
上述這三種事件QSystemTrayIcon類都徹底可以解決,可是托盤的hover事件卻無能爲力,如圖1所示,途圖中是幫助文檔中的一段描述,指明瞭只有在x11系統中,能夠捕獲到系統的tooltip事件,其餘系統都無能爲力,我本身也看了下qt的源碼,果然是這樣的,有興趣的同窗能夠自行在研究下。ide
圖1 幫助文檔函數
如圖2所示,qq有消息時,鼠標hover在圖盤彈出菜單,那麼qq是怎麼作的呢,既然qq都到作到了,這個功能咱們本身想必確定也能實現。工具
圖2 托盤hover彈框post
好了,上邊說了這麼多,僅僅是爲了鋪墊我本身實現的托盤,徹底脫離了qt中的托盤類QSystemTrayIcon,不過也不能說徹底脫離,部分代碼仍是從qt源碼中摘出來的。文章的最後我附上我本身用qt實現的自定義托盤和下載別人用mfc自定義實現的自定義托盤。ui
由於win32我本身也不是特別瞭解,所以我也是大概說下自定義托盤須要瞭解的東西,首先是NOTIFYICONDATA結構,這個結構百科講的特別詳細,看一下就知道怎麼用,而後是Shell_NotifyIcon這個api,這個方法就是對托盤操做的接口。具體參數百科中說的很詳細,不過若是你不想看也無所謂,直接往下看也能夠。對盤託的操做在windows平臺下都是同樣的,關鍵問題是用qt怎麼接受這個圖盤的hover和leave消息。
關於這個托盤的實現我也是從mfc的示例代碼中獲取的啓發,而後用qt方法實現,接下來我就直接說下用qt實現的步驟:
一、首先咱們須要瞭解下QAbstractNativeEventFilter這個接口類,繼承這個接口類的類能夠把本身註冊到app中,而後就能獲取到整個app
的事件,事件的處理函數爲nativeEventFilter,該類有3個參數,具體能夠參見這篇文字qt捕獲全局windows消息 這個文章中說的不全是對的,不過能抓取到app消息應該是沒問你的,本篇博客的demo也是印證了這個問題。註冊代碼以下:
1 qApp->installNativeEventFilter(this);
二、第二步就是建立托盤圖標,建立托盤圖標的時候,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,在咱們後續處理的邏輯中會用到
三、鼠標事件處理
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中有源文件。
四、程序退出時銷燬托盤圖標
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