系統托盤(通知區域)自 Windows 95 以來成為長時間執行應用程式(防毒、即時通訊、媒體播放器、輸入法)的標準 UI 模式。MFC 未提供現成類別,開發者需直接呼叫 Shell_NotifyIcon API。本文系列將從零建立可重用的 CTrayIcon 類別,涵蓋圖示管理、ToolTip、右鍵選單、雙擊行為、Explorer 重啟自動恢復、氣球提示等完整功能。
BOOL Shell_NotifyIcon(DWORD dwMessage, PNOTIFYICONDATA pnid);
dwMessage 操作類型:
| 值 | 用途 |
|---|---|
| NIM_ADD | 新增圖示到通知區 |
| NIM_MODIFY | 修改現有圖示(圖示、ToolTip 等) |
| NIM_DELETE | 移除圖示 |
| NIM_SETFOCUS | 將焦點還給通知區(如 ESC 取消選單時) |
| NIM_SETVERSION | 指定 Shell 版本行為 (IE4/IE5) |
NOTIFYICONDATA 關鍵欄位:
typedef struct _NOTIFYICONDATA {
DWORD cbSize; // sizeof(NOTIFYICONDATA) 必填
HWND hWnd; // 接收回呼訊息的視窗
UINT uID; // 圖示識別碼 (多圖示時區分)
UINT uFlags; // 有效欄位旗標組合
UINT uCallbackMessage; // 自訂回呼訊息 ID
HICON hIcon; // 圖示控制代碼
CHAR szTip[64]; // ToolTip 文字
} NOTIFYICONDATA;
uFlags 組合:NIF_MESSAGE (啟用回呼)、NIF_ICON (圖示有效)、NIF_TIP (ToolTip 有效)。
設定 uCallbackMessage = WM_MY_TRAY_NOTIFY 並包含 NIF_MESSAGE。使用者在圖示上滑鼠動作(移動、單擊、雙擊、右鍵)時,Windows 向 hWnd 送出 WM_MY_TRAY_NOTIFY:
wParam = uID (圖示 ID)lParam = 滑鼠訊息 (WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_RBUTTONUP, WM_LBUTTONDBLCLK 等)隱藏 NOTIFYICONDATA、旗標組合、訊息代碼等繁瑣細節,提供直觀介面:
SetIcon(UINT nResourceID) — 以資源 ID 設定圖示,自動讀取同 ID 字串資源作 ToolTipSetIcon(HICON) / SetStandardIcon(IDI_WINLOGO) — 直接用控制代碼或系統圖示SetIcon(0) — 移除圖示 (內部轉 NIM_DELETE)SetNotificationWnd(CWnd*, UINT msg) — 指定接收通知的視窗與訊息 IDOnTrayNotification(WPARAM, LPARAM) — 預設處理右鍵彈選單、雙擊執行首項命令
class CMainFrame : public CFrameWnd {
protected:
CTrayIcon m_trayIcon; // 托盤圖示實例
// ...
};
CMainFrame::CMainFrame() : m_trayIcon(IDR_TRAYICON) { }
IDR_TRAYICON 同時作為:圖示資源 ID、ToolTip 字串資源 ID、右鍵選單資源 ID。
#define WM_MY_TRAY_NOTIFICATION (WM_USER + 0)
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1;
m_trayIcon.SetNotificationWnd(this, WM_MY_TRAY_NOTIFICATION);
m_trayIcon.SetIcon(IDI_MYICON); // 圖示 + ToolTip
return 0;
}
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_MESSAGE(WM_MY_TRAY_NOTIFICATION, OnTrayNotification)
END_MESSAGE_MAP()
LRESULT CMainFrame::OnTrayNotification(WPARAM wp, LPARAM lp)
{
// 可自行處理特定滑鼠事件 (如記錄 Log)
return m_trayIcon.OnTrayNotification(wp, lp); // 委派預設行為
}
IDR_TRAYICON MENU DISCARDABLE
BEGIN
POPUP "托盤(&T)"
BEGIN
MENUITEM "開啟(&O)", ID_APP_OPEN
MENUITEM "關於 TrayTest(&A)...", ID_APP_ABOUT
MENUITEM SEPARATOR
MENUITEM "結束 TrayTest(&S)", ID_APP_SUSPEND
END
END
CTrayIcon 自動:
TrackPopupMenu 顯示選單(首項設為預設黑體)ID_APP_OPEN)WM_COMMAND 走標準 MFC 路由若直接呼叫 TrackPopupMenu,使用者按 ESC 或點選單外區域,選單不會自動消失。解決方案 (MSDN Q135788):
::SetForegroundWindow(m_nid.hWnd); // 關鍵:先設定前景視窗
::TrackPopupMenu(pSubMenu->m_hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON,
pt.x, pt.y, 0, m_nid.hWnd, NULL);
此為 CTrayIcon 內建處理,使用者無需關心。
OnClose)。托盤圖示並非所有應用程式都需要。濫用會造成通知區擁擠(圖五「噩夢版」),使用者體驗極差。請遵循:
CTrayIcon 封裝、選單/ToolTip/雙擊行為(本文)TaskbarCreated 自動重建圖示 (Explorer 重啟恢復)Balloon Tips (Win2000/XP)完整原始碼含 CTrayIcon.h/cpp、TrayTest1 專案,歡迎下載參考。