托盤程序的信息提示通常是將鼠標光標移到托盤圖標上之後,Windows會發送消息給托盤程序,從而顯示提示信息——Tooltip。但在Windows XP中我們還看到有些系統托盤程序是自動顯示ToolTips信息的,也就是說不用將鼠標光標移到托盤圖標上便可顯示ToolTips,在這是怎麼實現的呢?本文將示范一種新奇的ToolTips風格,它叫做氣球提示:Balloon Tips。
Windows中與托盤圖標相關的提示有兩類:一類是傳統的信息提示方式,當光標移到圖標上時顯示;另一類是新式的信息提示即氣球提示,它是由你的程序來控制顯示。氣球提示有點像連環漫畫中的文字氣球。如圖一、圖二分別為本文例子程序TrayTest3在Windows 2000和Windows XP中運行的畫面:
在Windows 2000中運行的氣球提示,沒有關閉按鈕。
圖一 在Windows 2000運行
在Windows XP中運行。
圖二 在 Windows XP中運行的TrayTest3
氣球提示為托盤程序提供了一種非打擾式的方法通知用戶發生了某件事情。但是如何讓氣球提示顯示出來呢?所有的托盤圖標行為都是通過一個單純的API函數Shell_NotifyIcon來操作的。這個函數的一個參數是NOTIFYICONDATA結構,你可以利用這個結構來告訴Windows你想要做什麼。下面是這個結構的定義的最新版本(For IE5.0+),其中已經加入了新的成員:
typedef struct _NOTIFYICONDATA {
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
#if (_WIN32_IE < 0x0500)
WCHAR szTip[64];
#else
WCHAR szTip[128];
#endif
#if (_WIN32_IE >= 0x0500)
DWORD dwState;
DWORD dwStateMask;
WCHAR szInfo[256];
union {
UINT uTimeout;
UINT uVersion;
} DUMMYUNIONNAME;
WCHAR szInfoTitle[64];
DWORD dwInfoFlags;
#endif
} NOTIFYICONDATA, *PNOTIFYICONDATA;
有關這個結構的詳細信息和用法請參考本文前面的兩個部分:
系統托盤編程完全指南(一)
系統托盤編程完全指南(二)
在NOTIFYICONDATA.uFlags中的標志之一是NIF_TIP,用它來設置傳統的信息提示,即鼠標要移動到圖標上。新的標志NIF_INFO(由於_WIN32_IE >= 0x0500條件定義,因此在編譯時,請注意包含最新版本的頭文件shellapi.h,並保證鏈接最新版本的庫文件shell32.lib,分發程序時用最新版本的運行時動態鏈接庫shell32.dll)便是為顯示氣球提示所用的。也就是說,要顯示氣球提示,那麼在調用Shell_NotifyIcon函數時必須用NIF_INFO標志。提示文本填入szInfo域,標題文本填入szInfoTitle。你甚至可以在NOTIFYICONDATA.uTimeout中設置一個超時時間,當經過指定的毫秒數之後,氣球提示自動隱藏。
為了示范氣球提示的實現原理,我對本文前面兩個部分的例子以及CTrayIcon類進行了修改。CTrayIcon類中添加了一個新的方法ShowBalloonTip,這個方法有兩個重載函數,既可以用文本串來調用,也可以用資源ID來調用。用資源ID時,可以有選擇地加載文本串,並調用ShowBalloonTip的文本串版本,原型如下:
BOOL CTrayIcon::ShowBalloonTip(LPCTSTR szMsg,
LPCTSTR szTitle, UINT uTimeout, DWORD dwInfoFlags)
{
m_nid.cbSize=sizeof(NOTIFYICONDATA);
m_nid.uFlags = NIF_INFO;
m_nid.uTimeout = uTimeout;
m_nid.dwInfoFlags = dwInfoFlags;
strcpy(m_nid.szInfo,szMsg ? szMsg : _T(""));
strcpy(m_nid.szInfoTitle,szTitle ? szTitle : _T(""));
return Shell_NotifyIcon(NIM_MODIFY, &m_nid);
}
這個函數很容易理解,同時也夠繁瑣的,要把文本串載緩沖裡拷來拷去。缺省的dwInfoFlags設置為NIIF_INFO,在文本旁邊顯示信息圖標;其它可能的標志是NIIF_ERROR——表示出錯,NIIF_WARNING——表示警告,NIIF_NONE——沒有圖標。有關修改後的CTrayIcon以及TrayTest3源代碼請下載本文的例子。
只有一種方法可以顯示氣球提示(Shell_NotifyIcon),但終止的方法有多種。用戶可以在氣球上單擊鼠標,也可以單擊關閉按鈕(在Windows 2000裡沒有關閉按鈕,如圖一),或者Windows用超時機制來終止氣球提示。那麼是如何知道所發生的事件是什麼呢?每當創建托盤圖標時,你可以提供一個HWND和消息ID來接收事件發生的通知。如果用戶單擊氣球提示,Windows發送NIN_BALLOONUSERCLICK;如果超時或者單擊關閉按鈕,Windows則發送NIN_BALLOONTIMEOUT。就我所知,目前還沒有辦法區分是超時還是單擊了關閉按鈕。下表中列出的是所有與氣球提示相關的通知消息:
通知消息 描述 NIN_BALLOONSHOW 顯示氣球提示時發送 NIN_BALLOONHIDE 氣球提示消失時發送;例如,當圖標被刪除,如果因為超時或是用戶單擊鼠標氣球消失,此消息不會被發送 NIN_BALLOONTIMEOUT 當由於超時或者用戶單擊氣球上的關閉按鈕(X),使氣球消失時發送此消息 NIN_BALLOONUSERCLICK 當用戶在氣球提示上或托盤圖標上單擊鼠標(此時氣球處於顯示狀態)時發送此消息
在測試過程中,我發現一個奇特的現象:在Windows XP中,只要你的托盤程序擁有焦點,氣球提示便不會超時。顯然,你只有轉到其它應用程序,才能啟動計時器。在Windows 2000裡好像沒有這個問題。
你可以用TrayTest3來看通知消息。實際上,TrayTest3的功能就是查看通知消息:當托盤通知消息到達時顯示它們。查看的方法是先運行TrayTest3,單擊初始對話框的"確認"按鈕,然後雙擊托盤圖標調出圖一所示的窗口。用"查看|顯示氣球提示"菜單來讓TrayTest3顯示它的提示,然後當你關閉提示或等待超時的時候,你查看在主窗口中顯示的什麼通知消息。
最後時一點忠告:請不要濫用氣球提示和托盤圖標!很多程序員為了好玩和張揚個性而濫用托盤圖標。請在只有真正需要它時才去做。不要讓用戶覺得你的程序很討厭,這樣他們會毫不猶豫地卸載這些屏幕垃圾。如果你真的必需實現托盤圖標,至少要給用戶一個選項來關掉它。(完)
本文配套源碼