黑客手册第十九课 树型视图控件.docx
《黑客手册第十九课 树型视图控件.docx》由会员分享,可在线阅读,更多相关《黑客手册第十九课 树型视图控件.docx(21页珍藏版)》请在冰豆网上搜索。
![黑客手册第十九课 树型视图控件.docx](https://file1.bdocx.com/fileroot1/2023-5/25/9c33c068-d0d6-4226-9eb7-16d96ccf7c24/9c33c068-d0d6-4226-9eb7-16d96ccf7c241.gif)
黑客手册第十九课树型视图控件
黑客手册第十九课树型视图控件
本课中,我们将学习如何使用树型视图控件。
另外还要学习如何在树型视图中完成拖拉动作,以及如何使用图象列表。
例子
理论:
树型视图是种特别的窗口,我们可以使用它目了然地表示某种层次关系。
譬如象在资源管理器中左边窗口中的就是树型视图。
您可以调用CreateWindowEx来创建树型视图,传递个类名""SysTreeView32川,或者您也可以把它放到一个对话框中去。
不要忘了在您的代码中加入InitCommonControls函数。
树型视图有几种特有的风格。
下面是几种经常使用的。
TVSHASBUTTONS二在父项目中显示(+)或(-)。
用户可以通过点击该符号来展开
或收起该父项目下的子项目。
如果想在根目录下也有这个符号必须指定
TVSLINESATROOT风格。
TVSHASLINES二二在层次中用线条来连接各个项目名称。
TVSLINESATROOT二在根目录下的项目也用线连接。
如果没有指定TVSHASLINES风
格,该风格也就会被忽略。
像其它的通用控件一样,树型视图用消息来完成通信。
父窗口发送一系列的消息给树型视
图,而树型视图发送"noti日cation"消息给它的父窗口。
在这方面,树型视图和其它的ii用控制没什么两样。
当有事件发生时,树型视图发送一个阳NOTIFY消息个父窗口,并在消息中附带传递一些附加信息。
WMNOTIFY
wParam二二控件的ID。
因为该值不是唯一的,故我们不用它。
我们使用NMHDR结构体中
的hwndFrom或IDFrom成员变量。
lParam二二指向NMHDR结构体的指针。
有一些控件可能传递一个指向更大一点的结构体
的指针。
但该结构体必须保证它的第一个成员变量是一个NMHDR型的变量。
这样,您在
处理lParam变量时,至少可以得到一个NMHDR型的变量。
下面我们来看NMHDR:
N阳IDRstructDWORD
hwndFromDWORD?
idFromDWORD?
codeDWORD?
N阳DRends
hwndFrom是发送阳NOTIFY消息的控件的窗口句柄。
idFrom是发送阳NOTIFY消息的控件的ID。
code是控件发送给父窗口的数据。
树型视图发送给父窗口的通知消息以TVN打头。
树型视图接收到的消息以TVM打头,譬如:
TVMCREATEDRAGlMAGE。
树型视图发送TVNXXX消息时在code变量中放入NMHDR型变量。
父窗
口发送TVM消息来控制树型视图。
在树型视图中加入项目
在创建完树型视图后可以通过发送TVMINSERTITEM消息往其中加入项目了。
TVMINSERTITEM
wParam二
lParam二
。
指向结构体TVINSERTSTRUCT的指针,
fg应当知道些关于树型视图中的项目之间关系的些术语。
个项目可能是个父亲、儿子或两者都是。
父项目下含有子项目,而该父项目又有可能是其它项目的子项目。
个没有父项目的项目叫根项目。
在树型视图中可能有多个根项目。
现在我们来看看TVINSERTSTRUCT结构体:
TVINSERTSTRUCTSTRUCTDWORDhParentDWORD?
hlnsertAfterDWORD?
ITEMTYPE<>
TVINSERTSTRUCTENDS
hParent二父项目的句柄。
如果该值为TVIROOTvalue或NULL,该项目插在树型视图的根
部。
hlnsertAfter二应该插入在起后面的项目的。
--O0-0···句柄或下面的值:
•TVIFIRST二二〉插在列表的头部。
•TVILAST二〉插在列表的尾部。
•TVISORT二〉按字母顺序插入。
ITE阳'YPEUNION
itemexTVITE脏X<>
itemTVITEM<>
ITE阳'YPE四DS
我们仅使用TVITEM。
TVITEMSTRUCT
imaskhltemstatestateMaskpszText
cchTextMax
ilmage
DWORD
DWORDDWORDDWORDDWORDDWORDDWORDDWORD
iSelectedlmagecChildrenlPar础
TVITEMENDS
DWORDDWORDDWORD
该结构体根据消息类型,用来发送或接收关于个树型视图的项目的有关信息。
譬如:
对于消息TVMINSERT口EM,它用来指定插入树型视图控件的项目的属性。
而对于消息
TVMGETITEM,该结构体用来填充关于选定项目的信息。
imask用来指定TVITEM的那些成员变量有效。
譬如,如果指定了TVIFTEXT,这意味着
pszText成员变量是有效的。
您可以同时指定几个标志位。
hltem是树型视图项目的句柄。
每个项目都有它自己的句柄,就像窗口样。
如果您想要
操作个项目,就必须选择它的句柄。
pszText是个字符串指针。
它是项目的标签名。
cchTextMax仅在查询项目的名称时使用。
由于在pszText中指定了指针,WINDOWS还要知道该缓冲去的大小。
所以您必须给出该值。
ilmage和iSelectedlmage用来指定图象列表以及个索引号。
这样就知道当项目被选中或没被选中时用哪个图象来表示该项目。
像资源管理器中左边窗口中的文件夹等小图表就是有这两个参数来决定的。
为了在树型视图中插入一个项目,您必须至少设定hParent,hlnsertAfter,另外您还要设定
imask和pszText值。
把图形加到图形视图中
如果您想要在项目的名称左边显示图标的话,您必须创建个图形列表,并且把它和树形视图相关联起来。
您可以调用ImageListCreate来创建个图形列表。
ImageList_CreatePROTOcx:
DWORD,cy:
DWORD,flags:
DWORD,\
clnitial:
DWORD,cGrow:
DWORD
如果创建成功的话,该函数返回个空的图象列表的句柄。
cx二以像素为单位的图象的宽度。
cy二以像素为单位的图象的高度。
图象列表中的每幅的高度都必须相同。
否则WINDOWS会
对您的图象进行裁剪,如果过大的话就可能裁剪成几小块。
所以您必须指定相同大小的图象。
flags二二指定图象列表的图象的颜色深度。
详细情况请参考WIN32API指南。
cInitial二指定包含的图象的数目。
WINDWOS将依此来分配合适的内存。
cGrow二在增加新图象是次增加的数目。
图象列表不是窗口。
仅仅是保存在那给其它的窗口使用的种资源。
在图象列表产生后,您可以调用ImageList_Add来向其中加入图象。
ImageListAddPROTOhiml:
DWORD,hbmlmage:
DWORD,hbmMask:
DWORD
如果该函数调用失败的话,返回10
himl二图象列表的句柄。
它是调用ImageListCreate时返回的值。
hbmlmage二二加入图象列表的位图的句柄。
您通常把位图保存在资源中,然后调用
LoadBitmap来把它加载进来。
注意您没有必要指定该位图中包含的图象的数目。
WINDOWS会
根据它的大小,自动计算。
hbmMask二二掩码位图的句柄。
如果没有使用掩码位图,可以忽略该值。
通常我们加入两种图象到图象列表中。
一种时被选中时显示的图象,另一种时没被选中时显示的。
当图象列表准备就绪后,您可以发送消息TVMSETlMAGELIST给树型视图来让图象列表和树型
视图联系起来。
TVMSETlMAGELIST
wParam二图象列表的状态,一共有两种:
oTVSILNORMAL包含被选中和没有被选中两种状态的图象。
oTVSILSTATE包含了用户自定义的状态的图象。
lParam二图象列表的句柄。
检索树型视图的信息
您可以通过发送消息TVMGETITEM来检索图形视图的信息。
二。
TVMGETITEM
wParam
lParam二指向结构体TVITEM的指针。
该结构体将用来得到相关的信息。
在发送该消息前必须设置成员变量imask的值,以便WINDOWS能告诉相关的信息。
当然,最重要的是,您必须传递您想得到信息的项目的句柄。
这就引起了个问题,您如何得到项目的句柄?
要保存所有项目的句柄吗?
答案是很简单的:
没有必要。
您可以发送消息TVMGETNEXTITEM到树型视图以检索您想要得到其属性的项目的句柄。
譬如:
您可以查询第个子项目的句柄、根目录的句柄、选中的项目的句柄等等。
TVMGETNEXTITEM
wParam二标志
lParam二树型视图的句柄(仅仅当wParam的值是某些标志位时才是必须的)。
wParam中的值非常重要,我解释如下:
。
oTVGNCARET选中的项目
。
TVGNCHILDhitem参数指定项目的第个子项目
。
TVGNDROPHILITE拖拉操作的目的项目
。
TVGNFIRSTVISIBLE第个可见项目
。
TVGNNEXT下个同级项目
TVGNNEXTVISIBLE下个可见项目,指定的项目必须可见。
发送消息
。
TVMGETITEMRECT来决定项目是否可见
。
TVGNPARENT指定项目的父项目
。
TVGNPREVIOUS前个同级项目
TVGNPREVIOUSVISIBLE前个可见项目,指定的项目必须可见。
发送消息
。
TVMGETITEMRECT来决定项目是否可见
TVGNROOT根工页目
由此您可以通过发送该消息来得到项目的句柄,然后在发送消息TVMGETITEM时在结构体变量
TVITEM的成员变量hltem中放入该项目的句柄就可以得到关于该项目的有关信息了。
在树型视图中进行拖拉操作
也就是因为这部分我才决定写这课教稽。
当我按照InPrise公司的WIN32帮助来运行例子时,发现它的帮助中缺少真正重要的信息。
我只有通过自己做实验,最后总算弄明白来个中来自。
希望您不要和我样再去走这些弯路,下面我把我所知的在树型视图中进行拖拉操作的步骤描述如下:
1.当用户要拖动个项目时,树型视图控件会给它的父窗口发送TVNBEGINDRAG通知消息。
您可以在此处创建表示项目处在拖动操作中的图象,这可以通过发送
TVMCREATEDRAGlMAGE消息给树型视图,让其为目前使用的图象产生副缺省的图象来实现。
树型视图控件将创建个图象列表,其中仅包含副在拖动中显示的图象,图象列表创建后,您可以得到它的句柄。
2.在拖拉的图象生成后,您可以通过调用ImageList_BeginDrag来指定拖动图象的热点位置。
ImageListBeginDragPROTOhimlTrack:
DWORD,\
\
himlTrack是包含了拖拉时显示的图象的图象列表的句柄
iTrack是选中的图象在图象列表中的索引号。
iTrack:
DWORD,\
dxHotspot:
DWORD,
dyHotspot:
DWORD
dxHotspot因为在拖动中该图象被用来取代光标,所以我们必须指定图象中的
哪点是光标的左上角的位置。
dxHotspot是水平相对位置。
dyHotspot是垂直相对位置。
iTrack等于0。
如果您要想光标的热点在拖拉中显示的图象的左上角,把
dxHotspot和dyHotspot部设成0。
3.当拖拉的图象要显示时,我们调用ImageList_DragEnter在树型视图中显示该图象。
ImageList_DragEnterPROTOhwndLock:
DWORD,x:
DWORD,y:
DWORD
hwndLock是进行拖拉中的窗口的句柄,拖拉的动作限制在该窗口中。
x和y是在拖拉时显示图象的初始位置的坐标值。
这些值是相对于窗口的左上角而不是客户区的左上角。
4.既然可以显示拖动中的图象了,我们就要处理拖动操作了。
在这里有个小问题。
我们监视拖动是通过监视鼠标光标的移动来实现的,譬如在移动时我们通过捕获
阳MOUSEMOVE消息来得到移动中的坐标位置,通过捕获阳LBUTTONUP消息来获知用户的放下操作。
但这时如果鼠标光标移过子窗口时父窗口就无法再得到鼠标光标的移动以及鼠标的按键消息了。
解决办法是调用SetCapture函数了锁定鼠标事件,这样无论鼠标移到那里和有什么动作,我们的窗口都可以知道了。
5.在处理阳MOUSEMOVE消息时,您可以调用ImageListDragMove来更新图象移动的轨迹。
该函数可以移动拖放操作中的图象位置。
另外,如果您想让移动中的图象经过某些项目时高量度显示,可以调用TVMHITTEST来确定是否经过某个项目的上面。
如果是的话,您可以发送TVMSELECTITEM消息并设置TVGNDROPHILITE标志位使得那个项目高亮度显示。
注意:
在发送消息TVMSELECTITEM前,您必须先隐藏图象列表,否则会留下非常难看的轨迹。
要隐藏拖动中的图象可以调用ImageList_DragShowNolock,在显示完高亮度的图象后再调用该函数以让拖动中的图象再正常显示。
6.当用户释放主键后,您必须做几件事。
如果您在高亮度显示的时候释放鼠标主键(表示您想把该项目加到此处),您必须使该项目变成正常地显示,这可以通过发送消息TVMSELECTITEM消息并设置标志位TVGNDROPHILITE来实现,只是这时lParam必须为0。
如果您不让高亮度显示的项目恢复正常,那就会发生个奇怪的现象:
当您再选择另外的项目时,那个项目的图象会包含在个正方形中,当时高亮度显示的项目依旧是上个项目。
接下来必须调用ImageList_EndDrag和ImageListDragLeaveo还有调用ReleaseCapture来释放捕获的鼠标。
如果您创建了个图象列表,那还要调用callingImageList来将它销毁,在拖放操作结束后您可以进行另外其它的操作。
例子代码:
.386
.modelflat,stdcall
optioncasemap:
none
include\masm32\include\windows.incinclude\masm32\include\user32.incinclude\masm32\include\kerne132.incinclude\masm32\include\comct132.incinclude\masm32\include\gdi32.incincludelib\masm32\lib\gdi32.1ibincludelib\masm32\lib\comct132.1ibincludelib\masm32\lib\user32.libincludelib\masm32\lib\kerne132.1ib
Win蜘inPROTO:
DWORD,:
DWORD,:
DWORD,:
DWORD
.const
IDBTREEequ4006;IDofthebitmapresource
.data
ClassNamedb"TreeView啊inClass",OAppNamedb"TreeViewDemo",。
TreeViewClassdb"SysTreeView32",0
Parentdb"ParentItem",。
Childldb"childl",OChild2db"child2",0
DragModeddFALSE;aflagtodetermineifweareindragmode
.data?
hlnstanceHINSTANCE?
hwndTreeViewdd?
hParentdd?
hlmageListdd?
viewcontrol
handleofthetreeviewcontrol
;handleoftheroottreeviewitem
handleoftheimagelistusedinthetree
hDraglmageListdd?
lmage
;handleoftheimagelistusedtostorethedrag
.codestart:
invokeGetModuleHandle,NULL
movhlnstance,eax
invokeWinMain,hlnstance,NULL,NULL,SWSHOWDEFAULT
invokeExitProcess,eaxinvokeInitCommonControls
WinMainprochlnst:
HINSTANCE,hPrevlnst:
HINSTANCE,CmdLine:
LPSTR,CmdShow:
DWORDLOCALwc:
WNDCLASSEX
LOCALmsg:
MSG
LOCALhwnd:
HWND
movwc.cbSize,SIZEOFWNDCLASSEX
movwc.style,CS_HREDRAWorCS_VREDRAW
movwc.lpfnWndProc,OFFSETWndProc
movwc.cbClsExtra,NULL
movwc.cbWndExtra,NULL
pushhlnst
popwc.hlnstance
movwc.hbrBackgrounCOLOR_APPWORKSPACE
movwc.lpszMenuName,NULL
movwc.lpszClassName,OFFSETClassNameinvokeLoadlcon,NULL,IDI_APPLICATION
movwc.hlcon,eaxmovwc.hlconSm,eax
invokeLoadCursor,NULL,IDC_ARROW
movwc.hCursor,eax
invokeRegisterClassEx,addrwc
invokeCreateWindowEx,WS_EX_CLI四TEDGE,ADDRClassN田ne,ADDRAppName,\
WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_U
CWUSEDEFAULT,200,400,NULL,NULL,\
hlnst,NULL
movhwnd,eax
.whileTRUE
invokeGetMessage,ADDRmsg,NULL,O,O
.BREAK.IF(!
eax)
invokeTranslateMessage,ADDRmsginvokeDispatchMessage,ADDRmsg
.endw
moveax,皿g.wParamret
WinMainendp
WndProcprocusesedihWnd:
HWND,uMsg:
UINT,wParam:
WPARAM,lPar础:
LPARAMLOCALtvinsert:
TVINSERTSTRUCT
LOCALhBitmap:
DWORD
LOCALtvhit:
TVHITTESTINFO
.ifuMsg二二WMCREATE
invokeCreateWindowEx,NULL,ADDRTreeViewC1ass,NULL,\
WSCHILD+WSVISIBLE+TVSHASLlNES+TVSHASBUTTONS+TVSLINESATROOT,O,\
O,200,400,hWnNULL,\
hlnstance,NULL;Createthetreeviewcontro1movhwndTreeView,eax
invokeImageListCreate,16,16,ILCCOLOR16,2,lO;createtheassociatedimagelist
movhlmageList,eax
invokeLoadBitmap,hlnstance,IDBTREE10adthebitmapfromthe
resource
movhBitmap,eax
invokeImageListAdd,hlmageList,hBitmap,NULL;Addthebitmapintothe
imagelist
invokeDe1eteObject,hBitmap;a1waysde1etethebitmapreso盯ce
invokeSendMessage,hwndTreeView,TVMSETlMAGELIST,O,hlmageList
movtvinsert.hParent,NULL
movtvinsert.hlnsertAfter,TVIROOT
movtvinsert.item.imask,TVIFTEXT+TVIFlMAGE+TVIFSELECTEDlMAGE
movtvinsert.item.pszText,offsetParentmovtvinsert.item.ilmage,。
movtvinsert.item.iSe1ectedlmage,1
invokeSendMessage,hwndTreeView,TVM_INSERTITEM,O,addrtvinsert
movhParent,eax
movtvinsert.hParent,eax
movtvinsert.hlnsertAfter,TVILAST
movtvinsert.item.pszText,offsetChi1d1
invokeSendMessage,hwndTreeView,TVM_INSERTITEM,O,addrtvinsert
movtvinsert.item.pszText,offsetChi1d2
invokeSendMessage,hwndTreeView,TVM_INSERTITEM,O,addrtvinsert
.e1seifuMsg二二WMMOUSEMOVE
.ifDragMode二二TRUE
moveax,lP盯am田ldeax,Offffhmovecx,lP盯amshrecx,16
movtvhit.pt.x,eaxmovtvhit.pt.y,ecx
invokeImageList_DragMove,eax,ecxinvokeImageList_DragShowNo1ock,FALSE
invokeSendMessage,hwndTreeView,TVM_HITTEST,NULL,addrtvhit
.ifeax!
二NULL
invoke
SendMessage,hwndTreeView,TVMSELECTITE盹TVGNDROPHILITE,eax
.endif
invokeImageListDragShowNo1ock,TRUE
.endif
.e1seifuMsg二二WMLBUTTONUP
.ifDragMode二二TRUE
invokeImageListDragLeave,hwndTreeViewinvokeImageListEndDrag
invokeImageListDestroy,hDraglmageList
invokeSendMessage,hwndTreeVi酬,TVMGETNEXTITEM,TVGNDROPHILITE,0
invokeSendMessage,hwndTreeView,TVMSELECTITETVG