TreeView 控件使用
5614 点击·0 回帖
![]() | ![]() | |
![]() | TreeView控件是最常用的控件之一,最近研究了一下,一开始是一点头绪都没有,不过多研究一下就越来越清晰了.呵呵.这篇文章也算是我自己的拾遗吧. 虽然windows里的TreeView控件不像java的MVC结构那样让人感觉很清晰,但是它还是提供了一系列的消息来对TreeView本身的数据结构的处理,所以用熟了的话,也不是很麻烦.其实也有很多相关的宏,但是这些宏好像windows汇编无法使用.但是用宏的话就没有意思了,自己去实现一下也是很不错的嘛.呵呵. 说到树型视图控件,要提到的就是TVITEM(TVITEMEX)结构体,这个结构体是一个项目(元素),它是TreeView的重要组成部分.它的定义为: typedef struct tagTVITEM{ UINT mask; HTREEITEM hItem; UINT state; UINT stateMask; LPTSTR pszText; int cchTextMax; int iImage; int iSelectedImage; int cChildren; LPARAM lParam; } TVITEM, FAR *LPTVITEM; 创建TreeView可以简单地用createwindowex函数.而对它的操作,主要是对ITEM的操作,这里简单列一些操作. 插入,删除和修改ITEM 插入一个ITEM,需要填写TVINSERTSTRUCT结构体.这个结构体包含一个Parent句柄,一个插入位置标志和一个TVITEM结构体.我们并不用全部填写.先看TVINSERTSTRUCT结构体,然后再说明 typedef struct tagTVINSERTSTRUCT { HTREEITEM hParent; HTREEITEM hInsertAfter; #if (_WIN32_IE >= 0x0400) union { TVITEMEX itemex; TVITEM item; } DUMMYUNIONNAME; #else TVITEM item; #endif } TVINSERTSTRUCT, FAR *LPTVINSERTSTRUCT; hParent是指定这个ITEM的父节点,如果它是根节点,可以为TVI_ROOT或NULL. hInsertAfter是插入到哪个节点之后,是一个ITEM的句柄,可以用TVI_FIRST等常量 TVITEM里指定要加入项目的属性,并不是所有的都要设定,而是看mask和statemask.如果设置mask为TVIF_TEXT,那么说明这个ITEM是纯TEXT型的,我们只要指定pszText和cchTextMax就行了.可以多种mask值或起来作为参数.如果是TVIF_IMAGE的,必须要为这个TreeView设置一个ImageList. 下面是一个插入ITEM的片段: local u:USER push hTreeWindow pop hTreeWin invoke SendMessage,hTreeWindow,TVM_SETITEMHEIGHT,26,0 invoke ImageList_Create,24,24,ILC_COLOR24,5,2 mov hImageList,eax invoke LoadBitmap,hInstance,IDC_STATEBIT push eax invoke ImageList_Add,hImageList,eax,NULL pop eax invoke DeleteObject,eax invoke SendMessage,hTreeWindow,TVM_SETIMAGELIST,NULL,hImageList invoke RtlZeroMemory,addr insertTNode.item,sizeof TVITEM mov insertTNode.hParent,NULL mov insertTNode.hInsertAfter,TVI_ROOT mov insertTNode.item.imask,TVIF_TEXT+TVIF_IMAGE+TVIF_SELECTEDIMAGE+TVIF_STATE mov insertTNode.item.pszText,offset parentText mov insertTNode.item.iImage,3 mov insertTNode.item.iSelectedImage,3 mov insertTNode.item.state,TVIS_BOLD mov insertTNode.item.stateMask,TVIS_OVERLAYMASK invoke SendMessage,hTreeWindow,TVM_INSERTITEM,0,addr insertTNode mov hRootNode,eax 处理NOTIFY消息 个人还是觉得重新写一个类继承TreeView,然后自己处理它的NOTIFY消息是最好的了.呵呵,常用的处理消息就是双击(NM_DBLCLK),正展开(TVN_ITEMEXPANDING)等等消息.这里说说NM_DBLCLK消息,收到这个消息时,肯定是在一个ITEM上发生了双击.想想qq之类的程序,用户列表都是树型的,双击后就会触发事件,其实就是处理了这个消息.那么怎样得到双击的项目呢,这儿就必须通过HITTEST来取得这个ITEM了(TreeView_SelectItem这个宏应该就是用HITTEST实现的),HITTEST就是看当前鼠标是不是在某个ITEM上,上的话就返回这个ITEM的句柄.那么怎样通过句柄得到这个ITEM的其它属性呢?例如这个元素的文字?方法就是再次填充TVITEM的部分元素,然后通过TVM_GETITEM消息来取得它.TVM_GETITEM会读出TVITEM里的hItem,用它来找到指定元素,然后根据mask里指定的要读取的值,填入TVITEM.所以在发送TVM_GETITEM消息前要填充好mask和hItem!!!mask可以是TVIF_TEXT 等等.这里要非常注意!!!如果你要取得Text,你必须指定pszText指向一个缓冲空间(把pszText设为一个缓冲空间的首地址)和 cchTextMax.这是显然的,因为这个结构体里没有可放字符串的地方.下面这个代码处理了NM_DBLCLK消息: SelfNotify proc hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD local TVI:TV_ITEM local TVHINFO:TV_HITTESTINFO local textBuf[50]:BYTE mov esi,lParam assume esi:ptr NMHDR .if [esi].code==NM_DBLCLK invoke GetCursorPos,addr TVHINFO.pt invoke ScreenToClient,hTreeWin,addr TVHINFO.pt mov TVHINFO.flags,TVHT_ONITEM or TVHT_ONITEMICON invoke SendMessage,hTreeWin,TVM_HITTEST,0,addr TVHINFO mov eax,TVHINFO.hItem .if eax==NULL || eax==hRootNode jmp @F .endif mov TVI.hItem,eax mov TVI.imask,TVIF_IMAGE or TVIF_SELECTEDIMAGE or TVIF_TEXT invoke GetStrAddr,addr textBuf mov TVI.pszText,eax mov TVI.cchTextMax,50 invoke SendMessage,hTreeWin,TVM_GETITEM,0,addr TVI invoke MessageBox,NULL,TVI.pszText,addr textBuf,0 .endif @@: invoke DefWindowProc,hWin,uMsg,wParam,lParam ;;;//注意这儿是必不可少的哦!!!!! ret SelfNotify endp | |
![]() | ![]() |