系統托盤大家應該都瞭解,如果程序需要常時間運行,將程序縮小到托盤中是個不錯的選擇。
現在看看系統托盤應該怎麼實現:
一、NOTIFYICONDATA結構體
首先,必須知道一個結構體NOTIFYICONDATA
,這是MFC中包含系統需要的用來傳遞托盤區域消息的信息結構體,有了它,我們今天的任務就完全可以輕鬆完成了!
這時候,我們可以在我們的類中申明一個NOTIFYICONDATA的成員變量爲m_nid。
接下來,我們可以給這個結構體變量賦我們想要的值了,記住賦值語句要寫在OnInitDialog初始化窗口函數裏,不要寫在構造函數中,否則將會無效。
m_nid.cbSize = sizeof( NOTIFYICONDATA );
m_nid.hWnd = m_hWnd;m_nid.uID = IDR_MAINFRAME;
m_nid.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
m_nid.uCallbackMessage = WM_SYSTEMTRAY; //自定義消息
m_nid.hIcon = m_hIcon;
strcpy(m_nid.szTip, "認證系統客戶端");
::Shell_NotifyIcon(NIM_ADD, &m_nid);
然後,讓我們一句句的解析這段代碼,
m_nid.cbSize = sizeof( NOTIFYICONDATA );
cbSize表示結構體的大小,以字節爲單位,這裏賦值了NOTIFYICONDATA的結構體標準大小就行了,用sizeof函數就能獲得其字節大小
m_nid.hWnd = m_hWnd;
hWnd是你想要賦予托盤的窗口句柄,MFC的窗口類中因爲都是繼承CDialog類,所以其中會有一個成員變量是m_hWnd保存着當前實例窗口的具體句柄,我們將其賦值給它就行了
m_nid.uID = IDR_MAINFRAME;
uID指的是應用程序定義的任務欄圖標的標識符,簡單的時候就是圖片圖標的ID,這裏的ID你可以進入工程下的ResourceView中找到Icon文件夾下的圖標,裏面的ID號就是我們現在要賦值的具體ID,Shell_NotifyIcon函數調用時,hWnd和UID成員用來標示具體要操作的圖標,可以通過多次的調用,來實現不同uID將多個圖標關聯到一個窗口hWnd上,從而實現托盤圖標切換的效果。當然你也可以在此處自定義一個ID使用。
m_nid.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
uFlags表明具體哪些其他成員爲合法數據,簡單的說就是隻有在uFlags中提到過的變量,才能發揮其作用,具體uFlags可以由以下一些成員組合:
NIF_ICON 表示hicon成員起作用。
NIF_MESSAGE 表示uCallbackMessage成員起作用
NIF_TIP 表示szTip成員起作用
當然還有許多別的如:NIF_STATE,NIF_INFO,NIF_GUID,這裏就具體先介紹上面三個,其他想了解的話可以具體查msdn
m_nid.uCallbackMessage = WM_SYSTEMTRAY;
uCallbackMessage是應用程序定義的消息標示,當鼠標在托盤鼠標上點擊事件的時候,程序的WM_SYSTEMTRAY就會被髮出,我們可以爲WM_SYSTEMTRAY定義一個消息響應函數,進行處理。也可以在WindowProc函數中就能獲得的該消息,從而做出事件響應,如下:
switch(message)
{
case WM_SYSTEMTRAY: //自定義消息
//具體響應消息
break;
}
其中,大家可以看出WM_SYSTEMTRAY不是系統消息,而是自定義的一個消息,用於表示這個特殊的事件發生了,至於怎麼定義呢,就是用宏了
#define WM_SYSTEMTRAY WM_USER+1
這裏解釋下,爲什麼WM_SYSTEMTRAY要宏定義成WM_USER+1呢,據我瞭解WM_USER是系統消息中的最後一個,也就是說這樣定義就不會和系統的消息衝突成一個同樣的值。
m_nid.hIcon = m_hIcon;
增加、修改或刪除的圖片句柄,用於控制托盤的圖標,m_hIcon是自定義的一個窗口圖標句柄
HICON m_hIcon;
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
當然你可以直接將m_nid.hIcon = m_hIcon 改成 m_nid.hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME)
strcpy(m_nid.szTip, "認證系統客戶端");
szTip是一個字符串指針,是在鼠標放在圖標上的時候,會出現的提示消息。
::Shell_NotifyIcon(NIM_ADD, &m_nid);
最後一個是一個全局函數 BOOL Shell_NotifyIcon(DWORD dwMessage,PNOTIFYICONDATA ipdata);參數dwMessage表示要執行的操作,可選值爲:
NIM_ADD 表示在托盤區域增加圖標
NIM_DELETE 表示刪除托盤區域的圖標
NIM_MODIFY 表示修改托盤區域的圖標
NIM_SETFOCUS 表示聚焦到托盤圖標上
第二個參數就是我們上面介紹過的NOTIFYICONDATA結構體的指針了。
如果操作成功函數會返回TRUE,否則返回FALSE。
///////////////////////////////////////////////////////////////////////////////////
OK,托盤的實現就是這麼簡單的啦,但是如果你想具體深入瞭解,可以查看MSDN裏面具體的解釋,也可以跟本人溝通
下面介紹下應用,具體的應用情況很多。
我們就來簡單的講一下,怎麼實現窗口隱藏後,雙擊托盤使窗口再出現,和右擊托盤出現退出窗口的實現
上面叫到了自定義的消息,在WindowProc函數中,我們可以具體實現
switch(message)
{
case WM_SYSTEMTRAY: //自定義消息
if (lParam == WM_LBUTTONDBLCLK)
{
ShowWindow(SW_SHOWNORMAL);
}
break;
}
上面的代碼就實現了,雙擊托盤實現顯示窗口的代碼,非常簡單,我們就不具體剖析了。
要實現右擊托盤顯示彈出窗口,我們必須先在資源中創建一個菜單,然後加入以下代碼
case WM_SYSTEMTRAY: //自定義消息
if (lParam == WM_RBUTTONDOWN)
{
//右擊彈出托盤菜單
CMenu menu;
menu.LoadMenu(IDR_MENU1);
CMenu *pPopUp=menu.GetSubMenu(0);
CPoint pt;
GetCursorPos(&pt);
SetForegroundWindow();
pPopUp->TrackPopupMenu(TPM_RIGHTBUTTON,pt.x,pt.y,this);
PostMessage(WM_NULL,0,0);
}
break;
代碼中,剛開始定義了一個CMenu的對象,然後將我們之前創建的菜單ID加載進去,然後獲得鼠標當前的位置,在這個位置上將菜單顯示出來
。其他的,大家自己發現和探索吧。
另外注意點擊對話框的關閉按鈕退出時,刪除系統化托盤圖標。