树形控件Tree Control
?
樹形控件Tree Control
?
前面兩節(jié)為大家講了列表視圖控件List Control,這一節(jié)開始介紹一種特殊的列表--樹形控件Tree Control。
???????樹形控件簡(jiǎn)介
???????樹形控件在Windows系統(tǒng)中是很常見的,例如資源管理器左側(cè)的窗口中就有用來顯示目錄的樹形視圖。樹形視圖中以分層結(jié)構(gòu)顯示數(shù)據(jù),每層的縮進(jìn)不同,層次越低縮進(jìn)越多。樹形控件的節(jié)點(diǎn)一般都由標(biāo)簽和圖標(biāo)兩部分組成,圖標(biāo)用來抽象的描述數(shù)據(jù),能夠使樹形控件的層次關(guān)系更加清晰。
?????? 樹形控件在插入新的樹節(jié)點(diǎn)時(shí)會(huì)稍麻煩些,回顧之前的列表框,插入新列表項(xiàng)時(shí)調(diào)用AddString成員函數(shù)就可以了,而對(duì)于樹形控件則需要指定新節(jié)點(diǎn)與已有節(jié)點(diǎn)的關(guān)系。另外,樹形控件與列表視圖控件一樣,可以在每一個(gè)節(jié)點(diǎn)的左邊加入圖標(biāo)。這些都使得樹形控件給人一種復(fù)雜的感覺,但我們?cè)谑褂盟粌纱魏髸?huì)發(fā)現(xiàn)其實(shí)樹形控件用起來還是很方便的。
???????樹形控件的通知消息
?????? 下面列出樹形控件特有的通知消息中比較常用的幾個(gè):
?????? TVN_SELCHANGING和TVN_SELCHANGED:在用戶改變了對(duì)樹節(jié)點(diǎn)的選擇時(shí),控件會(huì)發(fā)送這兩個(gè)消息。消息會(huì)附帶一個(gè)指向NMTREEVIEW結(jié)構(gòu)的指針,程序可從該結(jié)構(gòu)中獲得必要的信息。兩個(gè)消息都會(huì)在該結(jié)構(gòu)的itemOld成員中包含原來的選擇項(xiàng)信息,在itemNew成員中包含新選擇項(xiàng)的信息,在action成員中表明是用戶的什么行為觸發(fā)了該通知消息(若是TVC_BYKEYBOARD則表明是鍵盤,若是TVC_BYMOUSE則表明是鼠標(biāo),若是TVC_UNKNOWN則表示未知)。兩個(gè)消息的不同之處在于,如果TVN_SELCHANGING的消息處理函數(shù)返回TRUE,那么就阻止選擇的改變,如果返回FALSE,則允許改變。
???????TVN_KEYDOWN:該消息表明了一個(gè)鍵盤事件。消息會(huì)附帶一個(gè)指向NMTVKEYDOWN結(jié)構(gòu)的指針,通過該結(jié)構(gòu)程序可以獲得按鍵的信息。
?????? TVN_BEGINLABELEDIT和TVN_ENDLABELEDIT:分別在用戶開始編輯和結(jié)束編輯節(jié)點(diǎn)的標(biāo)簽時(shí)發(fā)送。消息會(huì)附帶一個(gè)指向NMTVDISPINFO結(jié)構(gòu)的指針,程序可從該結(jié)構(gòu)中獲得必要的信息。在前者的消息處理函數(shù)中,可以調(diào)用GetEditControl()成員函數(shù)返回一個(gè)指向用于編輯標(biāo)題的編輯框的指針。如果處理函數(shù)返回FALSE,則允許編輯,如果返回TRUE,則禁止編輯。在后者的消息處理函數(shù)中,NMTVDISPINFO結(jié)構(gòu)中的item.pszText指向編輯后的新標(biāo)題,如果pszText為NULL,那么說明用戶放棄了編輯,否則,程序應(yīng)負(fù)責(zé)更新節(jié)點(diǎn)的標(biāo)簽,這可以由SetItem()或SetItemText()函數(shù)來完成。
???????樹形控件的相關(guān)數(shù)據(jù)結(jié)構(gòu)
???????1. HTREEITEM句柄
?????? 樹形控件中的每個(gè)節(jié)點(diǎn)都可以由一個(gè)HTREEITEM類型的句柄表示。我們通過CTreeCtrl類的成員函數(shù)對(duì)樹進(jìn)行訪問和操作時(shí),很多時(shí)候都要用到HTREEITEM句柄。
???????2. TVITEM結(jié)構(gòu)體
?????? TVITEM結(jié)構(gòu)體描述了樹形控件節(jié)點(diǎn)的屬性,定義如下:
C++代碼 typedef struct tagTVITEM { UINT mask; // 包含一些掩碼位(下面的括號(hào)中列出)的組合,用來表明結(jié)構(gòu)的哪些成員是有效的 HTREEITEM hItem; // 樹節(jié)點(diǎn)的句柄(TVIF_HANDLE) UINT state; // 樹節(jié)點(diǎn)的狀態(tài)(TVIF_STATE) UINT stateMask; // 狀態(tài)的掩碼組合(TVIF_STATE) LPTSTR pszText; // 樹節(jié)點(diǎn)的標(biāo)簽文本(TVIF_TEXT) int cchTextMax; // 標(biāo)簽文本緩沖區(qū)的大小(TVIF_TEXT) int iImage; // 樹節(jié)點(diǎn)的圖像索引(TVIF_IMAGE) int iSelectedImage; // 選中項(xiàng)的圖像索引(TVIF_SELECTEDIMAGE) int cChildren; // 表明節(jié)點(diǎn)是否有子節(jié)點(diǎn),為1則有,為0則沒有(TVIF_CHILDREN) LPARAM lParam; // 一個(gè)32 位的附加數(shù)據(jù)(TVIF_PARAM) } TVITEM, *LPTVITEM;?
?????? 此結(jié)構(gòu)體中多個(gè)元素涉及到了圖像和狀態(tài)等,有必要具體解釋下。
?????? 樹形控件節(jié)點(diǎn)需要顯示圖標(biāo)時(shí),就要為樹形控件關(guān)聯(lián)一個(gè)圖像序列,上面的iImage成員就代表了該結(jié)構(gòu)體對(duì)應(yīng)的樹節(jié)點(diǎn)的圖標(biāo)在圖像序列中的索引,iSelectedImage則代表該樹節(jié)點(diǎn)被選中時(shí)顯示的圖標(biāo)在圖像序列中的索引。對(duì)于如何為樹形控件關(guān)聯(lián)圖像序列,雞啄米將在后面的實(shí)例中講到。
?????? stateMask用來說明要獲取或設(shè)置樹節(jié)點(diǎn)的哪些狀態(tài)。下面是state和stateMask的一些常用值及含義:
????????? state??????????????????????????? 對(duì)應(yīng)的stateMask?????????????????????? 含義?????????
?????? TVIS_CUT????????????????????????? TVIS_CUT??????????????????????? 節(jié)點(diǎn)被選擇用來進(jìn)行剪切和粘貼操作
?????? TVIS_DROPHILITED?????????? TVIS_DROPHILITED???????? 節(jié)點(diǎn)成為拖動(dòng)操作的目標(biāo)
?????? TVIS_EXPANDED???????????????TVIS_EXPANDED????????????? 節(jié)點(diǎn)的子節(jié)點(diǎn)被展開
?????? TVIS_EXPANDEDONCE????? TVIS_EXPANDEDONCE???? 節(jié)點(diǎn)的子節(jié)點(diǎn)曾經(jīng)被展開過
?????? TVIS_SELECTED?????????????? ?TVIS_SELECTED?????????????? 節(jié)點(diǎn)被選中
?????? lParam在實(shí)際開發(fā)中常用來存放與樹節(jié)點(diǎn)有關(guān)的附加數(shù)據(jù)。
???????3. NMTREEVIEW結(jié)構(gòu)體
?????? NMTREEVIEW結(jié)構(gòu)體中包含了樹形控件通知消息的相關(guān)信息。樹形控件的大多數(shù)通知消息都會(huì)帶有指向該結(jié)構(gòu)體的指針。NMTREEVIEW結(jié)構(gòu)體的定義如下:
C++代碼 typedef struct tagNMTREEVIEW { NMHDR hdr; // 標(biāo)準(zhǔn)的NMHDR結(jié)構(gòu) UINT action; // 表明是用戶的什么行為觸發(fā)了該通知消息 TVITEM itemOld; // 原節(jié)點(diǎn)的屬性 TVITEM itemNew; // 新節(jié)點(diǎn)的屬性 POINT ptDrag; // 事件發(fā)生時(shí)鼠標(biāo)的客戶區(qū)坐標(biāo) } NMTREEVIEW, *LPNMTREEVIEW;?
???????4. TVINSERTSTRUCT結(jié)構(gòu)體
?????? 向樹形控件中插入新節(jié)點(diǎn)時(shí)需要用到TVINSERTSTRUCT結(jié)構(gòu)體,它常與TVM_INSERTITEM消息一起使用。定義如下:
C++代碼 typedef struct tagTVINSERTSTRUCT { HTREEITEM hParent; // 父節(jié)點(diǎn)的句柄 HTREEITEM hInsertAfter; // 指明插入到同層中哪一項(xiàng)的后面 #if (_WIN32_IE >= 0x0400) union { TVITEMEX itemex; TVITEM item; } DUMMYUNIONNAME; #else TVITEM item; // 要添加的新節(jié)點(diǎn)的屬性 #endif } TVINSERTSTRUCT, *LPTVINSERTSTRUCT;?
?? ??? 若hParent成員為TVI_ROOT或NULL,那么新節(jié)點(diǎn)將被作為樹的根節(jié)點(diǎn)插入。hInsertAfter除了可以是某個(gè)節(jié)點(diǎn)的句柄,還可以有四種取值:TVI_FIRST(插入到樹形控件的最前面)、TVI_LAST(插入到樹形控件的最后面)、TVI_ROOT(作為根節(jié)點(diǎn)插入)和TVI_SORT(按字母順序插入)。
???????5. NMTVDISPINFO結(jié)構(gòu)體
?????? NMTVDISPINFO結(jié)構(gòu)體中包含了與樹節(jié)點(diǎn)的顯示有關(guān)的信息。定義如下:
C++代碼?
?? ??? 關(guān)于樹形控件的使用本節(jié)先講這么多,在下節(jié)將繼續(xù)講解CTreeCtrl類的相關(guān)知識(shí)和實(shí)例。雞啄米謝謝大家能一直跟隨著我學(xué)習(xí)VS2010/MFC,繼續(xù)加油!
?
前面一節(jié)講了樹形控件Tree Control的簡(jiǎn)介、通知消息以及相關(guān)數(shù)據(jù)結(jié)構(gòu),本節(jié)繼續(xù)講下半部分,包括樹形控件的創(chuàng)建、CTreeCtrl類的主要成員函數(shù)和應(yīng)用實(shí)例。
???????樹形控件的創(chuàng)建
???????MFC為樹形控件提供了CTreeCtrl類,它封裝了樹形控件的所有操作。
?????? 樹形控件的創(chuàng)建也是有兩種方式,一種是在對(duì)話框模板中直接拖入Tree Control控件創(chuàng)建,另一種就是通過CTreeCtrl類的Create成員函數(shù)創(chuàng)建。下面主要講后者。
?????? CTreeCtrl類的Create成員函數(shù)的原型如下:
virtual BOOL Create(DWORD dwStyle,const RECT& rect,CWnd* pParentWnd,UINT nID );?
?
?????? 此函數(shù)的原型與前面講到的所有控件類的Create函數(shù)都類似。dwStyle指定樹形控件風(fēng)格的組合,rect指定樹形控件窗口的位置和大小,pParentWnd為指向樹形控件父窗口的指針,nID指定樹形控件的ID。下面還是主要講講樹形控件的主要風(fēng)格以及含義。
?????? TVS_DISABLEDRAGDROP:禁止樹形控件發(fā)送TVN_BEGINDRAG通知消息,即不支持拖動(dòng)操作
?????? TVS_EDITLABELS:用戶可以編輯節(jié)點(diǎn)的標(biāo)簽文本
?????? TVS_HASBUTTONS:顯示帶有"+"或"-"的小方框來表示某項(xiàng)能否被展開或已展開
?????? TVS_HASLINES:在父節(jié)點(diǎn)與子節(jié)點(diǎn)間連線以更清晰地顯示樹的結(jié)構(gòu)
?????? TVS_LINESATROOT:在根節(jié)點(diǎn)處連線
?????? TVS_SHOWSELALWAYS:即使控件失去輸入焦點(diǎn),仍顯示出項(xiàng)的選擇狀態(tài)
?????? 同樣,動(dòng)態(tài)創(chuàng)建樹形控件時(shí),除了能夠指定上述風(fēng)格的組合外,一般還要指定WS_CHILD和WS_VISIBLE風(fēng)格。
?????? 在對(duì)話框模板中直接拖入Tree Control創(chuàng)建樹形控件時(shí),可以在樹形控件的屬性頁中設(shè)置其風(fēng)格,與上面的風(fēng)格是對(duì)應(yīng)的,例如,屬性Has Lines對(duì)應(yīng)的就是TVS_HASLINES風(fēng)格。
???????CTreeCtrl類的主要成員函數(shù)
???????CImageList* SetImageList(CImageList * pImageList,int nImageListType);
?????? 如果樹節(jié)點(diǎn)需要顯示圖標(biāo)時(shí),則必須先創(chuàng)建一個(gè)CImageList類的對(duì)象,并為其添加多個(gè)圖像組成一個(gè)圖像序列,然后調(diào)用SetImageList函數(shù)為樹形控件設(shè)置圖像序列,在用InsertItem插入節(jié)點(diǎn)時(shí)傳入所需圖像在圖像序列中的索引即可。后面的例子中會(huì)演示。參數(shù)pImageList為指向圖像序列類CImageList的對(duì)象的指針,若為NULL則刪除樹形控件的所有圖像。參數(shù)nImageListType指定圖像序列的類型,可以是TVSIL_NORMAL(普通圖像序列)或TVSIL_STATE(狀態(tài)圖像序列,用圖像表示節(jié)點(diǎn)的狀態(tài))。
???????UINT GetCount( ) const;
?????? 獲取樹形控件中節(jié)點(diǎn)的數(shù)量。
???????DWORD_PTR GetItemData(HTREEITEM hItem) const;
?????? 獲取樹形控件中某個(gè)指定節(jié)點(diǎn)的附加32位數(shù)據(jù)。參數(shù)hItem為指定的樹節(jié)點(diǎn)的句柄。
???????BOOL SetItemData(HTREEITEM hItem,DWORD_PTR dwData);
?????? 為樹形控件中某個(gè)指定節(jié)點(diǎn)設(shè)置附加的32位數(shù)據(jù)。參數(shù)hItem同上,dwData為要設(shè)置的32位數(shù)據(jù)。
???????CString GetItemText(HTREEITEM hItem) const;
?????? 獲取樹形控件中某個(gè)指定節(jié)點(diǎn)的標(biāo)簽文本。參數(shù)hItem同上。返回值是包含標(biāo)簽文本的字符串。
???????BOOL SetItemText(HTREEITEM hItem,LPCTSTR lpszItem);
?????? 為樹形控件中某個(gè)指定節(jié)點(diǎn)設(shè)置標(biāo)簽文本。參數(shù)hItem同上,lpszItem為包含標(biāo)簽文本的字符串的指針。
???????HTREEITEM GetNextSiblingItem(HTREEITEM hItem) const;
?????? 獲取樹形控件中某個(gè)指定節(jié)點(diǎn)的下一個(gè)兄弟節(jié)點(diǎn)。參數(shù)hItem同上。返回值是下一個(gè)兄弟節(jié)點(diǎn)的句柄。
???????HTREEITEM GetPrevSiblingItem(HTREEITEM hItem) const;
?????? 獲取樹形控件中某個(gè)指定節(jié)點(diǎn)的上一個(gè)兄弟節(jié)點(diǎn)。參數(shù)hItem同上。返回值是上一個(gè)兄弟節(jié)點(diǎn)的句柄。
???????HTREEITEM GetParentItem(HTREEITEM hItem) const;
?????? 獲取樹形控件中某個(gè)指定節(jié)點(diǎn)的父節(jié)點(diǎn)。參數(shù)hItem同上。返回值是父節(jié)點(diǎn)的句柄。
???????HTREEITEM GetRootItem( ) const;
?????? 獲取樹形控件根節(jié)點(diǎn)的句柄。
???????HTREEITEM GetSelectedItem( ) const;
?????? 獲取樹形控件當(dāng)前選中節(jié)點(diǎn)的句柄。
???????BOOL DeleteAllItems( );
?????? 刪除樹形控件中的所有節(jié)點(diǎn)。刪除成功則返回TRUE,否則返回FALSE。
???????BOOL DeleteItem(HTREEITEM hItem);
?????? 刪除樹形控件中的某個(gè)節(jié)點(diǎn)。參數(shù)hItem為要?jiǎng)h除的節(jié)點(diǎn)的句柄。刪除成功則返回TRUE,否則返回FALSE。
???????HTREEITEM InsertItem(LPCTSTR lpszItem,int nImage,int nSelectedImage,HTREEITEM hParent = TVI_ROOT,HTREEITEM hInsertAfter = TVI_LAST);
?????? 在樹形控件中插入一個(gè)新節(jié)點(diǎn)。參數(shù)lpszItem為新節(jié)點(diǎn)的標(biāo)簽文本字符串的指針,參數(shù)nImage為新節(jié)點(diǎn)的圖標(biāo)在樹形控件圖像序列中的索引,參數(shù)nSelectedImage為新節(jié)點(diǎn)被選中時(shí)的圖標(biāo)在圖像序列中的索引,參數(shù)hParent為插入節(jié)點(diǎn)的父節(jié)點(diǎn)的句柄,參數(shù)hInsertAfter為新節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)的句柄,即新節(jié)點(diǎn)將被插入到hInsertAfter節(jié)點(diǎn)之后。
???????BOOL SelectItem(HTREEITEM hItem);
?????? 選中指定的樹節(jié)點(diǎn)。參數(shù)hItem為要選擇的節(jié)點(diǎn)的句柄。若成功則返回TRUE,否則返回FALSE。
???????樹形控件的應(yīng)用實(shí)例
???????最后雞啄米還是給大家寫一個(gè)簡(jiǎn)單的實(shí)例,說明CListCtrl類的幾個(gè)成員函數(shù)及樹形控件通知消息等的使用方法。
?????? 此實(shí)例實(shí)現(xiàn)的功能:在一個(gè)樹形控件中顯示雞啄米網(wǎng)站的簡(jiǎn)單結(jié)構(gòu)分層,共有三層,分別為雞啄米網(wǎng)站、各個(gè)分類和文章。用鼠標(biāo)左鍵單擊改變選中節(jié)點(diǎn)后,將選中節(jié)點(diǎn)的文本顯示到編輯框中。另外,還要實(shí)現(xiàn)一個(gè)常見的效果,就是鼠標(biāo)劃過除根節(jié)點(diǎn)外的某個(gè)樹節(jié)點(diǎn)時(shí),顯示相應(yīng)的Tip提示信息。下面是具體實(shí)現(xiàn)步驟:
?????? 1. 創(chuàng)建一個(gè)基于對(duì)話框的MFC工程,名稱設(shè)置為“Example31”。
?????? 2. 在自動(dòng)生成的對(duì)話框模板IDD_EXAMPLE31_DIALOG中,刪除“TODO: Place dialog controls here.”靜態(tài)文本框、“OK”按鈕和“Cancel”按鈕。添加一個(gè)Tree Control控件,ID設(shè)置為IDC_WEB_TREE,屬性Has Buttons、Has Lines和Lines At Root都設(shè)為True,為了在鼠標(biāo)劃過某個(gè)節(jié)點(diǎn)時(shí)顯示提示信息還需要將Info Tip屬性設(shè)為True。再添加一個(gè)靜態(tài)文本框和一個(gè)編輯框,靜態(tài)文本框的Caption屬性設(shè)為“您選擇的節(jié)點(diǎn):”,編輯框的ID設(shè)為IDC_ITEM_SEL_EDIT,Read Only屬性設(shè)為True。此時(shí)的對(duì)話框模板如下圖: ??
? ? ? ??
?????? 3. 導(dǎo)入需要為樹形控件的節(jié)點(diǎn)添加的圖標(biāo)。雞啄米在這里找了三個(gè)32x32的Icon圖標(biāo),保存到工程的res目錄下。然后在Resource View資源視圖中,右鍵點(diǎn)擊Icon節(jié)點(diǎn),在右鍵菜單中選擇“Add Resource...”,彈出“Add Resource”對(duì)話框,再從左邊“Resource type”列表中選擇“Icon”,點(diǎn)擊右邊的“Import...”按鈕,就可以選擇三個(gè)圖標(biāo)文件進(jìn)行導(dǎo)入了。導(dǎo)入成功后,分別修改它們ID為IDI_WEB_ICON、IDI_CATALOG_ICON和IDI_ARTICLE_ICON。
?????? 4. 為樹形控件IDC_WEB_TREE添加CTreeCtrl類型的控件變量m_webTree。并在Example31Dlg.h文件中為CExample31Dlg類添加成員對(duì)象:CImageList m_imageList;。
?????? 5. 在對(duì)話框初始化時(shí),我們?cè)跇湫慰丶刑砑与u啄米網(wǎng)站的樹形結(jié)構(gòu),那么需要修改CExample31Dlg::OnInitDialog()函數(shù)為:
C++代碼?
?????? 6. 我們希望在選中節(jié)點(diǎn)改變時(shí),將最新的選擇項(xiàng)實(shí)時(shí)顯示到編輯框中,那么可以響應(yīng)TVN_SELCHANGED通知消息。為樹形控件IDC_WEB_TREE的通知消息TVN_SELCHANGED添加消息處理函數(shù)CExample31Dlg::OnTvnSelchangedWebTree,并修改函數(shù)體如下:
C++代碼?
???????? 7. 還有一個(gè)功能需要實(shí)現(xiàn),那就是鼠標(biāo)劃過除根節(jié)點(diǎn)外的某個(gè)樹節(jié)點(diǎn)時(shí),顯示相應(yīng)的Tip提示信息,本實(shí)例中提示信息為節(jié)點(diǎn)的編號(hào)。這需要響應(yīng)TVN_GETINFOTIP通知消息。為樹形控件IDC_WEB_TREE的通知消息TVN_GETINFOTIP添加消息處理函數(shù)CExample31Dlg::OnTvnGetInfoTipWebTree,并修改函數(shù)體如下:
C++代碼?
?????? 8. 運(yùn)行程序,彈出結(jié)果對(duì)話框。效果如下圖:
??
???????樹形控件的知識(shí)就講到這里了,相比之前的控件可能稍有復(fù)雜。不過用的多了,就會(huì)覺得得心應(yīng)手了。雞啄米歡迎大家繼續(xù)關(guān)注后面的VS2010/MFC編程入門教程。
轉(zhuǎn)載于:https://www.cnblogs.com/Dageking/archive/2013/03/14/2959070.html
總結(jié)
以上是生活随笔為你收集整理的树形控件Tree Control的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 好文转载——追求卓越之旅
- 下一篇: poj 3398 (树上的最小支配集)