天天看點

TreeView 控件使用

  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

繼續閱讀