標籤:win32 tooltip toolinfo 控制項
最近在MFC中使用ToolTip時有諸多疑惑,查閱了不少資料,仔細研究了MSDN文檔,在此記錄使用方法和注意事項,與大家共勉。
1.理論
首先,思考一下,如果是我們自己來實現ToolTip(工具提示)的功能,要如何做呢?最自然的想法是:當我們把滑鼠移動到希望提示的視窗時彈出一個提示視窗,我們把滑鼠移出希望提示的視窗時關閉提示視窗。OK,微軟也不會比我們聰明多少,它的實現基本思想就是這樣的。
需要注意的是微軟為了保證使用的方便,使用了設計模式中的觀察者模式,這樣使用方便,但是卻造成了理解上的不易。
簡單來說,觀察者模式就是設計有觀察者和被觀察對象,當被觀察對象觸發某些特定的動作時,會通知指定的觀察者採取相關動作。這裡觀察者和被觀察者要事先綁定並指定被觀察對象如何向觀察者發出通知,一般採用回呼函數或訊息通知的形式,這是Windows系統,當然是後一種了。
結合這裡ToolTip的實現,觀察者就是ToolTip(工具提示)視窗,被觀察者就是希望提示的視窗(Tool視窗),當滑鼠移動到希望提示的視窗(Tool視窗)上這一事件觸發後就會通知ToolTip(工具提示)視窗彈出,或者當滑鼠移出希望提示的視窗(Tool視窗)上這一事件觸發後就會通知ToolTip(工具提示)視窗隱藏。
那麼理論上,一般ToolTip的使用步驟如下:
1.建立Tooltip視窗,一般一個ToolTip視窗可用於多個Tool視窗的提示。
2.添加Tooltip視窗所觀察Tool視窗
3.所觀察Tool視窗產生滑鼠移入和移出事件時通知Tooltip視窗顯示和隱藏
2.實際使用
基本上微軟的實現和我們理論上描述的差不多,我們要實際使用ToolTip主要是搞懂訊息傳遞時的參數意義。
實際使用步驟如下:
1.使用CreateWindowEx建立ToolTip視窗
2.向新建立ToolTip視窗發送TTM_ADDTOOL訊息,為建立的ToolTip視窗添加所觀察Tool視窗
這個過程傳遞TOOLINFO型別參數來區別不同的Tool視窗和對應的提示文字
TOOLINFO的定義如下
typedef struct tagTOOLINFO{ UINT cbSize; UINT uFlags; HWND hwnd; UINT_PTR uId; RECT rect; HINSTANCE hinst; LPTSTR lpszText; #if (_WIN32_IE >= 0x0300) LPARAM lParam;#endif#if (_WIN32_WINNT >= 0x0501) void *lpReserved;#endif} TOOLINFO, NEAR *PTOOLINFO, *LPTOOLINFO;
部分參數定義如下
[1].cbSize
指的是TOOLINFO的大小,這裡一定要注意,許多有問題的地方就源於這裡。主要問題是下面這一句的定義
#if (_WIN32_WINNT >= 0x0501) void *lpReserved;#endif
在一些低版本的系統中使用高版本的編譯器,如在Windows 2000中使用VS 2005,這時候編譯器預設的版本大於0x0501,這個時候會有void *lpReserved定義,但是實際的Windows 2000中的comctl32.dll版本偏低,並沒有定義相關欄位,當實際調用時傳遞給dll中的TOOLINFO參數中cbSize偏大,dll檢測到這一條件後添加Tool視窗就失敗了。
解決方案很簡單,載入對應的dll或者減少cbSize。
在高版本的編譯器中,定義對應低版本作業系統的版本號碼_WIN32_WINNT 就可以減少cbSize了
提供高版本的dll並在高版本的編譯器中使用資訊清單檔即可載入對應的DLL版本
當然,如果你不是在低版本的系統中使用高版本的編譯器中使用的話就不需要考慮這個問題了。最常見的問題就是在XP中使用VS2005、2008系列編譯器引起的問題,這種情況下最簡單的就是連結正確的6.0版本 DLL如下:
#if defined _M_IX86#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")#elif defined _M_IA64#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")#elif defined _M_X64#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")#else#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")#endif
[2].uFlags
指明一些配置參數,見具體使用說明
以下兩個參數指明希望顯示工具提示的視窗或控制項,只需要選擇一種情況
[3].rect
如果希望滑鼠移動到某一個視窗的一個指定地區時顯示提示,這個rect就是指定地區,這個時候hwnd就是這個視窗控制代碼。這個時候uID只是一個自訂標識,用來區別不同的地區。
[4].uId
如果希望標移動到某一個控制項時顯示提示:uId就是這個控制項的ID號,這時候需要指明包含這個控制項的視窗控制代碼hwnd;如果指定uFlags參數包含TTF_IDISHWND,這時候uId就是這個控制項的控制代碼,這時候不需要指明hwnd。
以下參數指明希望顯示的工具提示文字
[5].lpszText
指明工具提示的顯示文字:當定義了hInstance時,lpszText是對應的字串資源ID號;如果沒有定義hInstance,lpszText指向自訂的字串buffer。如果指明lpszText參數為LPSTR_TEXTCALLBACK,建立ToolTip控制項時會發送給hwnd指定的視窗一個TTN_GETDISPINFO的通知訊息讓使用者響應這個訊息以獲得顯示的工具提示字串。
3.當滑鼠移入或移出希望顯示工具提示的視窗或控制項時,通知ToolTip提示視窗顯示或隱藏
這裡我們自然想到的是在希望顯示工具提示的視窗或控制項中響應滑鼠訊息。1.但是這樣做不僅麻煩,而且有些對話方塊和全部控制項無法響應WM_MOUSE訊息。這裡,微軟使用子類化希望顯示工具提示的視窗或控制項的方法截取指定的滑鼠訊息來通知ToolTip視窗顯示或隱藏。在uFlags參數中指明TTF_SUBCLASS,這樣在發送TTM_ADDTOOL時就子類化了對應的視窗或控制項,一般指明了這個參數就不需要使用者再做其他工作,這也是滿足絕大多數應用的使用方法。2.當然,你也可以自己子類化對應視窗或控制項,給ToolTip提示視窗發送TTM_RELAYEVENT通知訊息。3.但是對於一些單純使用子類化無法截取訊息的視窗如系統對話方塊,可能必須使用DLL鉤子來完成這樣的訊息重導向。
3.代碼實現首先確認載入對應版本控制項
然後在WM_CREATE或WM_INITDIALOG訊息中建立ToolTip工具提示視窗
//建立提示視窗hwndTip = CreateWindowEx(WS_EX_TOPMOST,TOOLTIPS_CLASS,NULL,WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,hDlg,NULL,hInstance,NULL);
接下來為各個視窗和控制項添加提示文字,在這個過程中做了視窗子類化的工作,注意隨滑鼠移動(Track類)的工具提示還是要自己處理WM_MOUSEMOVE訊息,並且他不能和其他的視窗或控制項共用ToolTip提示視窗。下面是各種常用情況的添加工具提示,完整的實現見附件原始碼。
/** *功能:為hwnd指定視窗地區rect添加工具提示文字szTipText *參數:hwndTip -- 用於顯示提示文字的ToolTip視窗 *hwnd、rect、uId --要顯示提示文字的視窗、地區和自訂的ID *szTipText --待顯示的工具提示文字 *返回:無 *其他:2014/05/30 By Jim Wen Ver1.0**/void AddRectTool(HWND hwndTip, HWND hwnd, RECT rect, UINT uid, LPCTSTR szTipText){ TOOLINFOtti;//設定提示視窗的資訊memset(&tti, 0, sizeof(TOOLINFO));tti.cbSize= sizeof(TOOLINFO);tti.uFlags= TTF_SUBCLASS;tti.hwnd= hwnd;tti.rect= rect;tti.uId= uid;tti.lpszText= szTipText; //新增一個提示SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &tti);} /** *功能:為指定控制項添加工具提示文字 *參數:hwndTip -- 用於顯示提示文字的ToolTip視窗 *hwnd、uId --控制項的父視窗、控制項ID *hInstance、szStringRes --應用程式控制代碼和工具提示文字字串資源ID *返回:無 *其他:2014/05/30 By Jim Wen Ver1.0**/void AddWindowTool1 (HWND hwndTip, HWND hwnd, UINT uid, HINSTANCE hInstance, LPCTSTR szStringRes){ TOOLINFOtti;//設定提示視窗的資訊memset(&tti, 0, sizeof(TOOLINFO));tti.cbSize= sizeof(TOOLINFO);tti.uFlags= TTF_IDISHWND | TTF_SUBCLASS ;tti.uId= (UINT_PTR)GetDlgItem(hwnd, uid);tti.hinst= hInstance;tti.lpszText= szStringRes;//新增一個提示SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &tti);} /** *功能:為指定控制項添加工具提示文字,這裡的文字通過給hwnd發送訊息來獲得 *參數:hwndTip -- 用於顯示提示文字的ToolTip視窗 *hwnd、uId --控制項的父視窗、控制項ID *返回:無 *其他:2014/05/30 By Jim Wen Ver1.0**/void AddWindowTool2 (HWND hwndTip, HWND hwnd, UINT uid){ TOOLINFOtti;//設定提示視窗的資訊memset(&tti, 0, sizeof(TOOLINFO));tti.cbSize= sizeof(TOOLINFO);tti.uFlags= TTF_IDISHWND | TTF_SUBCLASS ;tti.hwnd= hwnd;tti.uId= (UINT_PTR)GetDlgItem(hwnd, uid);tti.lpszText= LPSTR_TEXTCALLBACK;//新增一個提示SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &tti);} /** *功能:為指定控制項添加工具提示文字,這個工具提示是隨滑鼠移動的,這個不能定義TTF_SUBCLASS,必須自己傳遞滑鼠訊息 *在WM_MOUSE中通過TTM_TRACKPOSITION來確認工具提示文字位置 *可以通過TTM_TRACKACTIVATE來確認顯示和隱藏 *不能和其他的提示共用一個ToolTip提示視窗 *參數:hwndTip -- 用於顯示提示文字的ToolTip視窗 *hwnd、uId --控制項的父視窗、控制項ID *szTipText --待顯示的工具提示文字 *返回:無 *其他:2014/05/30 By Jim Wen Ver1.0**/BOOL g_bIsVisible=FALSE;void AddWindowTool3 ( HWND hwndTip, HWND hwnd, UINT uid, LPCTSTR szTipText){ TOOLINFOtti;//設定提示視窗的資訊memset(&tti, 0, sizeof(TOOLINFO));tti.cbSize= sizeof(TOOLINFO);tti.uFlags= TTF_IDISHWND | TTF_TRACK ;tti.uId= (UINT_PTR)GetDlgItem(hwnd, uid);tti.lpszText= szTipText;//新增一個提示SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &tti);//顯示工具提示SendMessage(hwndTip, TTM_TRACKACTIVATE,(WPARAM)TRUE,(LPARAM)&tti);g_bIsVisible = TRUE;} /** *功能:為指定控制項添加多行工具提示文字,這裡的文字必須通過給hwnd發送訊息來獲得 *參數:hwndTip -- 用於顯示提示文字的ToolTip視窗 *hwnd、uId --控制項的父視窗、控制項ID *返回:無 *其他:2014/05/30 By Jim Wen Ver1.0**/void AddWindowTool4 (HWND hwndTip, HWND hwnd, UINT uid, LPCTSTR szTipText){ TOOLINFOtti;//設定提示視窗的資訊memset(&tti, 0, sizeof(TOOLINFO));tti.cbSize= sizeof(TOOLINFO);tti.uFlags= TTF_CENTERTIP | TTF_IDISHWND | TTF_SUBCLASS ;tti.hwnd= hwnd;tti.uId= (UINT_PTR)GetDlgItem(hwnd, uid);tti.lpszText= LPSTR_TEXTCALLBACK;//新增一個提示SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &tti);}
完整示範原始碼下載連結原創,轉載請註明來自http://blog.csdn.net/wenzhou1219