樹視圖控件具有層次分明、結(jié)構(gòu)化強(qiáng)、美觀、靈活等特點(diǎn),在各種操作系統(tǒng)中廣為應(yīng)用,是人們最熟悉、最常應(yīng)用的控件。
從樹視圖控件出現(xiàn)到現(xiàn)在,它們一直被認(rèn)為非常復(fù)雜并難于編程,與其它如編輯框、單選鈕、復(fù)選框等控件進(jìn)行比較,要使其正常運(yùn)行,開發(fā)人員需要多做一些工作。然而,在使用復(fù)雜的同時(shí),樹視圖控件又提供給開發(fā)人員更多的能力與空間。這里筆者就VC++中樹視圖控件的編程使用作一些介紹。
MFC提供的樹視圖控件CTreeCtrl類用于封裝樹視圖控件的功能,同時(shí)它只是一個(gè)很“瘦”的包裝器。它應(yīng)用在對話框中或視圖窗體中,同其他控件一樣,可直接拖放到窗口中,改變其位置、大小和一些基本屬性。
下面開始建立一個(gè)CTreeCtrl,步驟如下:
1.將CtreeCtrl拖到視圖窗口中,調(diào)整位置、大小,并定義其對象標(biāo)識為IDC_TREE。
2.改變其屬性,選中Has buttons、Has lines復(fù)選框,這樣用起樹視圖控件就同Windows中資源管理器中的一樣了。
3.定義一個(gè)從CtreelCtrl繼承的類CNewTree,在MFC ClassWizard中建立對新定義類的成員變量為m_MyTree,以后程序中對該控件的控制通過此成員變量來實(shí)現(xiàn)。這么做是為了以后方便對其添加其他用戶自定義的功能。
做完以上幾步,我們就可以開始編寫代碼了。首先,初始化樹視圖控件,為其關(guān)聯(lián)一個(gè)圖像列表;然后,用InsertItem函數(shù)增加節(jié)點(diǎn)。在視圖窗口CMyFormView中的OnInitialUpdate()事件中加入下面代碼:
同CtreeView相比,CtreeCtrl是CtreeView的一個(gè)“輕巧”版本,編程也相對簡單。
void CMyFormView::OnInitialUpdate() { HICON hIcon[7]; CImageList m_imagelist; m_imagelist.Create(16,16,0,7,7); //建立一個(gè)圖像列表 m_imagelist.SetBkColor (RGB(255,255,255));hIcon[0]=AfxGetApp()-〉LoadIcon (IDI_ BMP0); hIcon[1]=AfxGetApp()-〉LoadIcon (IDI_ BMP1); …… hIcon[6]=AfxGetApp()-〉LoadIcon (IDI_ BMP6); for(int i=0;i〈=6;i++) { m_imagelist.Add (hIcon[i]); } m_MyTree.SetImageList (&&m_imagelist,TVSIL_NORMAL) //為m_MyTree設(shè)置一個(gè)圖像列表,使CtreeCtrl的不同節(jié)點(diǎn)顯示不同的圖標(biāo) HTREEITEM m_item m_item=m_MyTree.InsertItem ("Root",0,0,0,0); //根節(jié)點(diǎn)的圖標(biāo)為IDI_BMP0 if (m_item!=NULL) //根節(jié)點(diǎn)建立成功 { m_MyTree.InsertItem("SubItem1",1,1,m_item) //在根節(jié)點(diǎn)下建立一個(gè)子節(jié)點(diǎn)名為SubItem1,所顯示的圖標(biāo)為IDI_BMP1。同理,可建立其它節(jié)點(diǎn),同一層次的節(jié)點(diǎn)顯示相同的圖標(biāo) } …… } |
CtreeCtrl類沒有提供節(jié)點(diǎn)查找的函數(shù),所以要求程序員自己編寫特定條件的查找函數(shù)。
通常點(diǎn)擊不同節(jié)點(diǎn)所觸發(fā)的事件是不同的,此時(shí),要增加OnSelchangedTree事件。在ClassWiard窗口中,選擇CmyFormView類,對象標(biāo)識為IDC_TREE,消息為TVN_SELCHANGED,添加函數(shù),然后編輯代碼。
void CMyFormView::OnSelchangedTree(NMHDR pNMHDR, LRESULT pResult) { HTREEITEM SelItem; MyStructure ItemData; //MyStructure為用戶定義的結(jié)構(gòu)類型 SelItem=m_MyTree.GetSelectedItem (); ItemData=GetItemData(SelItem); //獲得該節(jié)點(diǎn)的數(shù)據(jù)指針 Switch (ItemData-〉value1) { case 0:{……} //用戶指定的操作 case 1:{……} …… } } |
在實(shí)際編程中,可能不僅僅是為了顯示,樹視圖控件上的每一個(gè)節(jié)點(diǎn)都對應(yīng)特定的值,所以要將指向具體數(shù)據(jù)的指針賦給對應(yīng)的節(jié)點(diǎn)。具體做法是在用戶自定義類CNewTree中新增一過程SetValue(HTREEITEM)。具體代碼如下:
void CNewTree::SetValue(HTREEITEM Item_parm,int Value1,int value2…..) { MyStructure ItemData ItemData= new MyStructure;; ItemData-〉value1=value1; ItemData-〉value2=value2; …… SetItemData(Item_parm ,(DWORD)ItemData); } |
調(diào)用時(shí),傳入對應(yīng)的參數(shù),即可對給定的節(jié)點(diǎn)賦值。當(dāng)然這里用了動態(tài)分配地址new,因此,在程序結(jié)束前,一定不要忘記刪除這些空間。
void CNewTree::DeleteData(HTREEITEM Item) { MyStructure ItemData; ItemData=GetItemData(Item); //獲得該節(jié)點(diǎn)的數(shù)據(jù)指針 if (ItemData!=NULL){ delete[] (char)ItemData;} //刪除所占用的空間 …… } |
根據(jù)樹視圖的結(jié)構(gòu)特點(diǎn),我們采用遞歸遍歷的方法來查找節(jié)點(diǎn),當(dāng)然你可根據(jù)條件縮小遍歷的范圍。這里筆者以節(jié)點(diǎn)值匹配為條件,編寫自定義的函數(shù)FindNode(),返回第一個(gè)符合條件的節(jié)點(diǎn)的句柄,具體代碼如下:
HTREEITEM CNewTree::FindNode(HTREEITEM NodeItem, int &&NodeValue) { MyStructure ItemData; HTREEITEM NextItem; if(NodeItem= =NULL) return NULL; //遞歸出口 else { while(NodeItem!=NULL) { ItemData=GetItemData(NodeItem); If (ItemData-〉value1= =NodeValue) return NodeItem; NodeItem=GetChildItem(NodeItem); //得到當(dāng)前節(jié)點(diǎn)的第一個(gè)子節(jié)點(diǎn)的句柄 If(FindNode(NodeItem, NodeValue)= =NULL); //遞歸查找 NodeItem=GetNextSiblingItem(NodeItem); //得到當(dāng)前節(jié)點(diǎn)的兄弟節(jié)點(diǎn)的句柄 } } } |
到此為止,筆者介紹了一些樹視圖控件編程方法,包括樹視圖控件的建立、節(jié)點(diǎn)值的賦予和刪除、查找。當(dāng)然,它應(yīng)用的方面很廣,使用方法也很多。這里提供了構(gòu)建樹視圖控件的基本框架,在此基礎(chǔ)上,可進(jìn)行擴(kuò)展,從而完成更強(qiáng)大的功能,如同列表視圖控件結(jié)合,為其加上彈出式選單等等。感興趣的讀者不妨自己擴(kuò)展該控件試試。
|