第27課 工具提示控件
我們將學(xué)習工具提示控件:它是什么如何創(chuàng )建和使用.下載例子
工具提示是當鼠標在某特定區域上停留時(shí)顯示的一個(gè)矩形窗口.工具提示窗口包含一些編程者想要顯示的文本.在這點(diǎn)上,工具提示同狀態(tài)欄的作用是一樣的,所不同的是工具提示當單擊或者遠離指定區域的時(shí)候就會(huì )消逝,你可能熟悉與工具欄相關(guān)聯(lián)的工具提示,那些"提示"是工具欄控件提供的便利.如果你想要在其它窗口、控件中顯示工具提示的話(huà),就不得不自己創(chuàng )建他們.
既然已經(jīng)了解了什么是工具提示,就讓我們來(lái)看看如何創(chuàng )建他們.大致步驟如下:
.data注意窗口風(fēng)格:TIS_ALWAYSTIP指定了工具提示不管包含指定區域的窗口狀態(tài)如何,當鼠標移過(guò)指定區域的時(shí)候,工具提示總是顯示.簡(jiǎn)單的說(shuō)就是,即使窗口處于非激活狀態(tài),鼠標移過(guò)工具提示指定區域的時(shí)候,工具提示也會(huì )出現.
TooltipClassName db "Tooltips_class32",0
.code
.....
invoke InitCommonControls
invoke CreateWindowEx, NULL, addr TooltipClassName, NULL, TIS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL
工具提示控件創(chuàng )建了但還沒(méi)有顯示,我們想要當鼠標指針在某個(gè)區域之上時(shí)顯示工具提示窗口.現在需要指定這個(gè)區域.我們稱(chēng)這樣的區域為"工具",“工具”就是工具提示控件監視鼠標指針是否移過(guò)的位于窗口客戶(hù)區的一個(gè)方形區域.如果鼠標指針移過(guò)"工具",工具提示窗口就顯示."工具"可覆蓋整個(gè)客戶(hù)區或者僅僅是它的一部分.因此我們把"工具"分成兩種類(lèi)型,一種是作為一個(gè)窗口,另一種則是某窗口客戶(hù)區的一部分.兩種各有所用.覆蓋整個(gè)客戶(hù)區的"工具"通常用于按鈕、編輯控件等,你不必指定焦點(diǎn)域的坐標和大小:它被假定為窗口的整個(gè)客戶(hù)區.僅覆蓋窗口客戶(hù)區一部分的"工具"在你想把窗口客戶(hù)區分成幾個(gè)部分但又不想使用子窗口時(shí)特別有用,但需要指定左上角的坐標和寬高.
使用如下的 TOOLINFO 結構定義"工具":
TOOLINFO STRUCT
cbSize DWORD ?
uFlags DWORD ?
hWnd DWORD ?
uId DWORD ?
rect RECT <>
hInst DWORD ?
lpszText DWORD ?
lParam LPARAM ?
TOOLINFO ENDS
| 域名 | 說(shuō)明 |
| cbSize | TOOLINFO結構的大小.必須填充, 如果這個(gè)區域不被正確填充Windows并不會(huì )報錯,但你會(huì )得到不可預料的奇怪結果. |
| uFlags | 指定焦點(diǎn)域的屬性,可以是如下標志的聯(lián)合:
|
| hWnd | 包含"工具"的窗口句柄,如果你指定了TTF_IDISHWND標志,Windows將忽略該值,而使用uId成員的值作為窗口句柄.你需要填充這個(gè)域域如果:
|
| uId | 這個(gè)域的值可能有兩種含義,依 uFlags 是否包含TTF_IDISHWND.
|
| rect | 指定"工具"大小的rect結構.這個(gè)結構定義了一個(gè)以hWnd指定窗口客戶(hù)區左上角為基點(diǎn)的方形大小,簡(jiǎn)言之,如果你想指定客戶(hù)區的一部分作為"工具"就得填充這個(gè)結構,如果你指定了TTF_IDISHWND標志 ,控件就會(huì )忽略這個(gè)值.(你已經(jīng)選擇整個(gè)客戶(hù)區作為"工具") |
| hInst | 如果lpszText指定了字符串資源的標識,包含將作為工具提文本字符串資源的實(shí)例句柄.聽(tīng)起來(lái)有點(diǎn)費解,閱讀一下lpszText的說(shuō)明就可以明白這個(gè)域是干什么用的了.若lpszText不包含字符串資源標識,控件會(huì )忽略這個(gè)域. |
| lpszText | 這個(gè)域可以有如下幾個(gè)值:
|
總言之,你需要將TOOLINFO結構傳遞給工具提示控件之前填充填充好,它描述了你期望的"工具"屬性.
.data?成功返回 TRUE,否則返回 FALSE.
ti TOOLINFO <>
.......
.code
.......
<fill the TOOLINFO structure>
.......
invoke SendMessage, hwndTooltip, TTM_ADDTOOL, NULL, addr ti
WndProc proc hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
.......
if uMsg==WM_CREATE
.............
elseif uMsg==WM_LBUTTONDOWN || uMsg==WM_MOUSEMOVE || uMsg==WM_LBUTTONUP || uMsg==WM_RBUTTONDOWN || uMsg==WM_MBUTTONDOWN || uMsg==WM_RBUTTONUP || uMsg==WM_MBUTTONUP
invoke SendMessage, hwndTooltip, TTM_RELAYEVENT, NULL, addr msg
..........
.386
.model flat,stdcall
option casemap:none
include /masm32/include/windows.inc
include /masm32/include/kernel32.inc
include /masm32/include/user32.inc
include /masm32/include/comctl32.inc
includelib /masm32/lib/comctl32.lib
includelib /masm32/lib/user32.lib
includelib /masm32/lib/kernel32.lib
DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD
EnumChild proto :DWORD,:DWORD
SetDlgToolArea proto :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
.const
IDD_MAINDIALOG equ 101
.data
ToolTipsClassName db "Tooltips_class32",0
MainDialogText1 db "This is the upper left area of the dialog",0
MainDialogText2 db "This is the upper right area of the dialog",0
MainDialogText3 db "This is the lower left area of the dialog",0
MainDialogText4 db "This is the lower right area of the dialog",0
.data?
hwndTool dd ?
hInstance dd ?
.code
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke DialogBoxParam,hInstance,IDD_MAINDIALOG,NULL,addr DlgProc,NULL
invoke ExitProcess,eaxDlgProc proc hDlg:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
LOCAL ti:TOOLINFO
LOCAL id:DWORD
LOCAL rect:RECT
.if uMsg==WM_INITDIALOG
invoke InitCommonControls
invoke CreateWindowEx,NULL,ADDR ToolTipsClassName,NULL,/
TTS_ALWAYSTIP,CW_USEDEFAULT,/
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,/
hInstance,NULL
mov hwndTool,eax
mov id,0
mov ti.cbSize,sizeof TOOLINFO
mov ti.uFlags,TTF_SUBCLASS
push hDlg
pop ti.hWnd
invoke GetWindowRect,hDlg,addr rect
invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText1,id,addr rect
inc id
invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText2,id,addr rect
inc id
invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText3,id,addr rect
inc id
invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText4,id,addr rect
invoke EnumChildWindows,hDlg,addr EnumChild,addr ti
.elseif uMsg==WM_CLOSE
invoke EndDialog,hDlg,NULL
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
DlgProc endpEnumChild proc uses edi hwndChild:DWORD,lParam:DWORD
LOCAL buffer[256]:BYTE
mov edi,lParam
assume edi:ptr TOOLINFO
push hwndChild
pop [edi].uId
or [edi].uFlags,TTF_IDISHWND
invoke GetWindowText,hwndChild,addr buffer,255
lea eax,buffer
mov [edi].lpszText,eax
invoke SendMessage,hwndTool,TTM_ADDTOOL,NULL,edi
assume edi:nothing
ret
EnumChild endpSetDlgToolArea proc uses edi esi hDlg:DWORD,lpti:DWORD,lpText:DWORD,id:DWORD,lprect:DWORD
mov edi,lpti
mov esi,lprect
assume esi:ptr RECT
assume edi:ptr TOOLINFO
.if id==0
mov [edi].rect.left,0
mov [edi].rect.top,0
mov eax,[esi].right
sub eax,[esi].left
shr eax,1
mov [edi].rect.right,eax
mov eax,[esi].bottom
sub eax,[esi].top
shr eax,1
mov [edi].rect.bottom,eax
.elseif id==1
mov eax,[esi].right
sub eax,[esi].left
shr eax,1
inc eax
mov [edi].rect.left,eax
mov [edi].rect.top,0
mov eax,[esi].right
sub eax,[esi].left
mov [edi].rect.right,eax
mov eax,[esi].bottom
sub eax,[esi].top
mov [edi].rect.bottom,eax
.elseif id==2
mov [edi].rect.left,0
mov eax,[esi].bottom
sub eax,[esi].top
shr eax,1
inc eax
mov [edi].rect.top,eax
mov eax,[esi].right
sub eax,[esi].left
shr eax,1
mov [edi].rect.right,eax
mov eax,[esi].bottom
sub eax,[esi].top
mov [edi].rect.bottom,eax
.else
mov eax,[esi].right
sub eax,[esi].left
shr eax,1
inc eax
mov [edi].rect.left,eax
mov eax,[esi].bottom
sub eax,[esi].top
shr eax,1
inc eax
mov [edi].rect.top,eax
mov eax,[esi].right
sub eax,[esi].left
mov [edi].rect.right,eax
mov eax,[esi].bottom
sub eax,[esi].top
mov [edi].rect.bottom,eax
.endif
push lpText
pop [edi].lpszText
invoke SendMessage,hwndTool,TTM_ADDTOOL,NULL,lpti
assume edi:nothing
assume esi:nothing
ret
SetDlgToolArea endp
end start
分析:
創(chuàng )建主對話(huà)框窗口之后,使用CreateWindowEx創(chuàng )建工具提示控件.
invoke InitCommonControls
invoke CreateWindowEx,NULL,ADDR ToolTipsClassName,NULL,/
TTS_ALWAYSTIP,CW_USEDEFAULT,/
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,/
hInstance,NULL
mov hwndTool,eax
之后,我們繼續定義對話(huà)框四個(gè)角作為焦點(diǎn)域.
mov id,0 ; 焦點(diǎn)域ID
mov ti.cbSize,sizeof TOOLINFO
mov ti.uFlags,TTF_SUBCLASS ; 告訴控件子類(lèi)化窗口.
push hDlg
pop ti.hWnd ; 包含焦點(diǎn)域的窗口句柄
invoke GetWindowRect,hDlg,addr rect ; 獲得客戶(hù)區的大小
invoke SetDlgToolArea,hDlg,addr ti,addr MainDialogText1,id,addr rect
我們初始化TOOLINFO結構. 注意我們要把客戶(hù)區分成4個(gè)焦點(diǎn)域,因此我們需要知道客戶(hù)區的大小,所以調用GetWindowRect.因為我們不想自己向控件轉發(fā)消息,因此指定TIF_SUBCLASS 標志.
SetDlgToolArea 是計算焦點(diǎn)域矩形范圍的并向控件注冊的函數,我不詳細解釋計算過(guò)程.只說(shuō)明它把對話(huà)框分成4個(gè)焦點(diǎn)域.然后向控件發(fā)送TTM_ADDTOOL 消息, 在lParam參數中傳遞TOOLINFO結構的地址.
invoke SendMessage,hwndTool,TTM_ADDTOOL,NULL,lpti
在四個(gè)控件注冊之后,我們來(lái)看看對話(huà)框的按鈕,我們可以用ID來(lái)處理每個(gè)按鈕,但是實(shí)在太乏味了.我們使用EnumChildWindows函數列舉對話(huà)框上的所有控件并把他們注冊給控件,EnumChildWindows原型如下:
EnumChildWindows proto hWnd:DWORD, lpEnumFunc:DWORD, lParam:DWORD
hWnd 是父窗口句柄.
lpEnumFunc 是每個(gè)控件將調用的EnumChildProc函數地址.lParam 是應用程序定義的要傳給EnumChildProc 函數的值. EnumChildProc 函數定義如下:
EnumChildProc proto hwndChild:DWORD, lParam:DWORDhwndChild是EnumChildWindows函數枚舉的句柄. lParam 就是你傳遞給EnumChildWindows函數的同一個(gè)lParam.
invoke EnumChildWindows,hDlg,addr EnumChild,addr ti我們把TOOLINFO結構的地址放在lParam參數中傳遞,是因為我們要在EnumChild函數中注冊每個(gè)子控件.如果我們不使用這種方法,就需要將ti聲明為全局變量,但這可能會(huì )引入很多bug.
EnumChild proc uses edi hwndChild:DWORD,lParam:DWORD注意在例子中,我們使用了一種不同"工具":覆蓋整個(gè)客戶(hù)區的"工具",因此我們需要用包含"工具"窗口的句柄來(lái)填充uID成員,也必須在uFlags 成員中指定TTF_IDISHWND標志.
LOCAL buffer[256]:BYTE
mov edi,lParam
assume edi:ptr TOOLINFO
push hwndChild
pop [edi].uId ; we use the whole client area of the control as the tool
or [edi].uFlags,TTF_IDISHWND
invoke GetWindowText,hwndChild,addr buffer,255
lea eax,buffer ; use the window text as the tooltip text
mov [edi].lpszText,eax
invoke SendMessage,hwndTool,TTM_ADDTOOL,NULL,edi
assume edi:nothing
ret
EnumChild endp
聯(lián)系客服