許多常駐應用程式(輸入法、防毒軟體、下載工具)會在任務列通知區域(系統托盤)放置專屬圖標,提供狀態指示與快捷操作。本文以 C++ Builder 為例,詳細說明如何建立、顯示、隱藏、回應托盤圖標事件,並實現「關閉視窗最小化到托盤、雙擊圖標還原、右鍵選單」等經典行為。
NOTIFYICONDATA 結構定義托盤圖標屬性:
typedef struct _NOTIFYICONDATA {
DWORD cbSize; // 結構大小
HWND hWnd; // 接收回呼訊息的視窗句柄
UINT uID; // 圖標識別碼
UINT uFlags; // 有效欄位旗標:NIF_MESSAGE|NIF_ICON|NIF_TIP
UINT uCallbackMessage; // 自訂回呼訊息編號
HICON hIcon; // 圖標控制代碼
TCHAR szTip[128]; // 滑鼠懸停提示文字
} NOTIFYICONDATA;
關鍵 API:Shell_NotifyIcon(dwMessage, &data)
NIM_ADD:新增圖標NIM_DELETE:移除圖標NIM_MODIFY:修改圖標/提示/回呼訊息class TForm1 : public TForm {
__published:
TButton *OKButton, *CancelButton;
TLabel *Label1;
void __fastcall FormCreate(TObject *Sender);
void __fastcall FormDestroy(TObject *Sender);
void __fastcall OKButtonClick(TObject *Sender);
void __fastcall CancelButtonClick(TObject *Sender);
private:
unsigned uIconMessage; // 自訂回呼訊息編號
void AddTray(); // 建立托盤圖標
void DeleteTray(); // 移除托盤圖標
protected:
virtual void __fastcall WndProc(Messages::TMessage &Message); // 重寫視窗程序
public:
__fastcall TForm1(TComponent* Owner);
};
void TForm1::AddTray() {
NOTIFYICONDATA nid = {0};
nid.cbSize = sizeof(nid);
nid.hWnd = Handle;
nid.uID = 1;
nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
nid.uCallbackMessage = uIconMessage;
strncpy(nid.szTip, "我的任務", sizeof(nid.szTip));
Application->Icon->LoadFromFile("e:\\yxg\\map\\system\\ico\\yxg.ico");
nid.hIcon = Application->Icon->Handle;
Shell_NotifyIcon(NIM_ADD, &nid);
}
void TForm1::DeleteTray() {
NOTIFYICONDATA nid = {0};
nid.cbSize = sizeof(nid);
nid.hWnd = Handle;
nid.uID = 1;
Shell_NotifyIcon(NIM_DELETE, &nid);
}
void __fastcall TForm1::WndProc(Messages::TMessage &Message) {
if (Message.Msg == uIconMessage) {
switch (Message.LParam) {
case WM_LBUTTONDBLCLK: // 左鍵雙擊:結束程式
Application->Terminate();
break;
case WM_RBUTTONDBLCLK: // 右鍵雙擊:顯示主視窗
ShowWindow(Application->Handle, SW_SHOW);
Application->ShowMainForm = true;
Visible = true;
break;
}
return;
}
TForm::WndProc(Message); // 其他訊息交給基類處理
}
void __fastcall TForm1::FormCreate(TObject *Sender) {
uIconMessage = RegisterWindowMessage("IconNotify"); // 取得唯一訊息編號
AddTray();
Visible = false; // 啟動時隱藏主視窗
}
void __fastcall TForm1::FormDestroy(TObject *Sender) {
DeleteTray(); // 程式結束前移除圖標
}
void __fastcall TForm1::OKButtonClick(TObject *Sender) {
Visible = false;
ShowWindow(Application->Handle, SW_HIDE);
Application->ShowMainForm = false;
}
void __fastcall TForm1::CancelButtonClick(TObject *Sender) {
Application->Terminate();
}
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
try {
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
ShowWindow(Application->Handle, SW_HIDE); // 隱藏應用程式主視窗
Application->ShowMainForm = false;
Application->Run();
} catch (Exception &exception) {
Application->ShowException(&exception);
}
return 0;
}
| 技術點 | 說明 |
|---|---|
| RegisterWindowMessage | 產生系統唯一訊息編號,避免與其他程式衝突 |
| WndProc 重寫 | 攔截托盤回呼訊息(WM_LBUTTONDBLCLK 等),實現自訂行為 |
| NIM_MODIFY | 可動態更換圖標、更新提示文字、修改回呼訊息 |
| WinMain 隱藏主視窗 | 確保程式啟動即駐留托盤,不顯示工作列按鈕 |
| Application->ShowMainForm = false | 配合 SW_HIDE 徹底隱藏 VCL 主視窗機制 |
WM_RBUTTONUP 顯示 TPopupMenu,提供「開啟、設定、退出」選項。Timer 週期性呼叫 NIM_MODIFY 更換圖標,實現動畫效果(見文章 ID 7864)。NIF_INFO、szInfo、szInfoTitle、dwInfoFlags 顯示豐富通知。掌握托盤程式設計,是開發常駐背景應用、系統工具的基本功。