轉自:http://www.jizhuomi.com/software/200.html
前面兩節講了列表視圖控件List Control,這一節開始介紹一種特殊的列表--樹形控件Tree Control。
樹形控件簡介
樹形控件在Windows系統中是很常見的,例如資源管理器左側的窗口中就有用來顯示目錄的樹形視圖。樹形視圖中以分層結構顯示數據,每層的縮進不同,層次越低縮進越多。樹形控件的節點一般都由標簽和圖標兩部分組成,圖標用來抽象的描述數據,能夠使樹形控件的層次關系更加清晰。
樹形控件在插入新的樹節點時會稍麻煩些,回顧之前的列表框,插入新列表項時調用AddString成員函數就可以了,而對於樹形控件則需要指定新節點與已有節點的關系。另外,樹形控件與列表視圖控件一樣,可以在每一個節點的左邊加入圖標。這些都使得樹形控件給人一種復雜的感覺,但我們在使用它一兩次后會發現其實樹形控件用起來還是很方便的。
樹形控件的通知消息
下面列出樹形控件特有的通知消息中比較常用的幾個:
TVN_SELCHANGING和TVN_SELCHANGED:在用戶改變了對樹節點的選擇時,控件會發送這兩個消息。消息會附帶一個指向NMTREEVIEW結構的指針,程序可從該結構中獲得必要的信息。兩個消息都會在該結構的itemOld成員中包含原來的選擇項信息,在itemNew成員中包含新選擇項的信息,在action成員中表明是用戶的什么行為觸發了該通知消息(若是TVC_BYKEYBOARD則表明是鍵盤,若是TVC_BYMOUSE則表明是鼠標,若是TVC_UNKNOWN則表示未知)。兩個消息的不同之處在於,如果TVN_SELCHANGING的消息處理函數返回TRUE,那么就阻止選擇的改變,如果返回FALSE,則允許改變。
TVN_KEYDOWN:該消息表明了一個鍵盤事件。消息會附帶一個指向NMTVKEYDOWN結構的指針,通過該結構程序可以獲得按鍵的信息。
TVN_BEGINLABELEDIT和TVN_ENDLABELEDIT:分別在用戶開始編輯和結束編輯節點的標簽時發送。消息會附帶一個指向NMTVDISPINFO結構的指針,程序可從該結構中獲得必要的信息。在前者的消息處理函數中,可以調用GetEditControl()成員函數返回一個指向用於編輯標題的編輯框的指針。如果處理函數返回FALSE,則允許編輯,如果返回TRUE,則禁止編輯。在后者的消息處理函數中,NMTVDISPINFO結構中的item.pszText指向編輯后的新標題,如果pszText為NULL,那么說明用戶放棄了編輯,否則,程序應負責更新節點的標簽,這可以由SetItem()或SetItemText()函數來完成。
樹形控件的相關數據結構
1. HTREEITEM句柄
樹形控件中的每個節點都可以由一個HTREEITEM類型的句柄表示。我們通過CTreeCtrl類的成員函數對樹進行訪問和操作時,很多時候都要用到HTREEITEM句柄。
2. TVITEM結構體
TVITEM結構體描述了樹形控件節點的屬性,定義如下:
typedef struct tagTVITEM { UINT mask; // 包含一些掩碼位(下面的括號中列出)的組合,用來表明結構的哪些成員是有效的
HTREEITEM hItem; // 樹節點的句柄(TVIF_HANDLE)
UINT state; // 樹節點的狀態(TVIF_STATE)
UINT stateMask; // 狀態的掩碼組合(TVIF_STATE)
LPTSTR pszText; // 樹節點的標簽文本(TVIF_TEXT)
int cchTextMax; // 標簽文本緩沖區的大小(TVIF_TEXT)
int iImage; // 樹節點的圖像索引(TVIF_IMAGE)
int iSelectedImage; // 選中項的圖像索引(TVIF_SELECTEDIMAGE)
int cChildren; // 表明節點是否有子節點,為1則有,為0則沒有(TVIF_CHILDREN)
LPARAM lParam; // 一個32 位的附加數據(TVIF_PARAM)
} TVITEM, *LPTVITEM;
此結構體中多個元素涉及到了圖像和狀態等,有必要具體解釋下。
樹形控件節點需要顯示圖標時,就要為樹形控件關聯一個圖像序列,上面的iImage成員就代表了該結構體對應的樹節點的圖標在圖像序列中的索引,iSelectedImage則代表該樹節點被選中時顯示的圖標在圖像序列中的索引。對於如何為樹形控件關聯圖像序列,雞啄米將在后面的實例中講到。
stateMask用來說明要獲取或設置樹節點的哪些狀態。下面是state和stateMask的一些常用值及含義:
state 對應的stateMask 含義
TVIS_CUT TVIS_CUT 節點被選擇用來進行剪切和粘貼操作
TVIS_DROPHILITED TVIS_DROPHILITED 節點成為拖動操作的目標
TVIS_EXPANDED TVIS_EXPANDED 節點的子節點被展開
TVIS_EXPANDEDONCE TVIS_EXPANDEDONCE 節點的子節點曾經被展開過
TVIS_SELECTED TVIS_SELECTED 節點被選中
lParam在實際開發中常用來存放與樹節點有關的附加數據。
3. NMTREEVIEW結構體
NMTREEVIEW結構體中包含了樹形控件通知消息的相關信息。樹形控件的大多數通知消息都會帶有指向該結構體的指針。NMTREEVIEW結構體的定義如下:
typedef struct tagNMTREEVIEW { NMHDR hdr; // 標准的NMHDR結構
UINT action; // 表明是用戶的什么行為觸發了該通知消息
TVITEM itemOld; // 原節點的屬性
TVITEM itemNew; // 新節點的屬性
POINT ptDrag; // 事件發生時鼠標的客戶區坐標
} NMTREEVIEW, *LPNMTREEVIEW;
4. TVINSERTSTRUCT結構體
向樹形控件中插入新節點時需要用到TVINSERTSTRUCT結構體,它常與TVM_INSERTITEM消息一起使用。定義如下:
typedef struct tagTVINSERTSTRUCT { HTREEITEM hParent; // 父節點的句柄
HTREEITEM hInsertAfter; // 指明插入到同層中哪一項的后面
#if (_WIN32_IE >= 0x0400) union { TVITEMEX itemex; TVITEM item; } DUMMYUNIONNAME; #else TVITEM item; // 要添加的新節點的屬性
#endif } TVINSERTSTRUCT, *LPTVINSERTSTRUCT;
若hParent成員為TVI_ROOT或NULL,那么新節點將被作為樹的根節點插入。hInsertAfter除了可以是某個節點的句柄,還可以有四種取值:TVI_FIRST(插入到樹形控件的最前面)、TVI_LAST(插入到樹形控件的最后面)、TVI_ROOT(作為根節點插入)和TVI_SORT(按字母順序插入)。
5. NMTVDISPINFO結構體
NMTVDISPINFO結構體中包含了與樹節點的顯示有關的信息。定義如下:
typedef struct tagNMTVDISPINFO { NMHDR hdr; TVITEM item; } NMTVDISPINFO, *LPNMTVDISPINFO;
關於樹形控件的使用本節先講這么多,在下節將繼續講解CTreeCtrl類的相關知識和實例。
