玩轉VC++系統托盤程式(WIN8)
WINDOWS系統托盤是一個特殊區域,通常在桌面的右下角,也就是工作列的右邊。系統常駐在托盤的程式有時鐘,音量控制,輸入法,網路狀態等。第三方應用如QQ程式也是一個典型的托盤程式,當最小化時企鵝會乖乖的待在螢幕右下角等待主人的呼喚。
系統托盤的方便之處在於,程式在暫時不用時,將它放到托盤裡,隨用隨叫,不必將其關閉。而QQ在接收到訊息後,也會在托盤中閃動提示,十分人性化。
那麼如何用VC++來開發托盤程式呢?下面會用一個例子來玩轉WINDOWS托盤程式。
首先,定義一下需要的功能。(需求確定)
-
程式最小化到托盤。
-
右鍵點選,顯示一個選單。
-
滑鼠左鍵雙擊托盤圖示,開啟程式。
-
程式中點選一個按鈕,改變托盤圖示。
好了,就這麼簡單的Demo,下面看看如何實現。
其次,歸納一下用到的技術點。
-
托盤相關API
-
MFC對滑鼠操作訊息的接收
先來說說托盤相關的API。MFC並沒有直接提高便利的類來支援系統托盤程式設計,我們需要用到SHELLAPI中的Shell_NotifyIcon函式。原型為:
BOOL Shell_NotifyIcon(
DWORD dwMessage,
PNOTIFYICONDATA lpdata
);
函式很簡單清晰,只有兩個引數。引數一dwMessage用來指定托盤的動作,這是一個四位元組的值。如下:
-
NIM_ADD(0X00000000):新增一個系統托盤
-
NIM_MODIFY(0X00000001):系統托盤的修改
-
NIM_DELETE(0X00000002):系統托盤的刪除
-
NIM_SETFOCUS(0X00000003):令系統托盤獲得焦點
-
NIM_SETVERSION(0X00000004):系統托盤設定版本
引數二PNOTIFYICONDATA是專門為此服務的結構體。原型如下:
typedef struct _NOTIFYICONDATA { DWORD cbSize;//結構體的大小,單位是位元組 HWND hWnd;//此托盤程式的控制代碼 UINT uID;// 系統為托盤區域每個圖示分配的ID UINT uFlags;//簡單的說,就是一個標示 UINT uCallbackMessage;//回撥訊息。需要自定義一個訊息,用來接收滑鼠滑過或點選等訊息。 HICON hIcon;//圖示 TCHAR szTip[64];//提示文字的大小 DWORD dwState;//圖示的狀態 DWORD dwStateMask;//與上面類似 TCHAR szInfo[256];//顯示在氣泡通知中的文字 union { UINT uTimeout; UINT uVersion; }; TCHAR szInfoTitle[64];//氣泡通知的標題 DWORD dwInfoFlags;//修改氣泡通知相關的標示 GUID guidItem;//圖示的GUID HICON hBalloonIcon;//氣泡通知的圖示 } NOTIFYICONDATA, *PNOTIFYICONDATA;
再來說說MFC中對滑鼠操作資訊的接收。
其實上面的調查結果一出,這個問題也就迎刃而解了。關鍵在uCallbackMessage。我們會自定義一個訊息,比如就叫做WM_ICON_NOTIFY,當此托盤圖示有滑鼠滑過,懸停或點選,鍵盤操作時回撥這個接收自定義訊息的函式來處理。這一切都被安排好了,我們照著做就可以了。
第三、功能的實現
1.最小化到托盤
建立托盤的函式ToTray:
m_tnd.cbSize = sizeof(NOTIFYICONDATA);
m_tnd.hWnd = pWnd->GetSafeHwnd();
m_tnd.uID = uID;
m_tnd.hIcon = icon;
m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
m_tnd.uCallbackMessage = uCallbackMessage;
strcpy (m_tnd.szTip, szToolTip);
// Set the tray icon
Shell_NotifyIcon(NIM_ADD, &m_tnd);
視窗最小化在OnSysCommand中判斷:
else if (nID == SC_MINIMIZE)
{
ToTray();
ShowWindow(SW_HIDE);//隱藏視窗
}
2、3功能都可以在獲得托盤事件函式處理:
LRESULT CTrayIcon::OnTrayNotification(UINT wParam, LONG lParam)
{
//Return quickly if its not for this tray icon
if (wParam != m_tnd.uID)
return 0L;
// Clicking with right or left button brings up a context menu
if (LOWORD(lParam) == WM_RBUTTONUP /*|| LOWORD(lParam) == WM_LBUTTONUP*/)
{
//TODO:WHEN RIGHT CLICK,YOUR MENU SHOW HERE
}
else if (LOWORD(lParam) == WM_LBUTTONDBLCLK)
{
//TODO:DOUBLE LEFT CLICK,SHOW MAIN WINDOW
}
return 1;
}
4.修改圖示
這個就比較容易了,直接修改引數即可:
m_tnd.uFlags = NIF_ICON;
m_tnd.hIcon = hIcon;
Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
完整的例子請下載demo程式碼,借用了網上比較流行的封裝好的TrayIcon類。
參考: