樹形控件可以用于樹形的結構,其中有一個根接點(Root)然后下面有許多子結點,而每個子結點上有允許有一個或多個或沒有子結點。MFC中使用CTreeCtrl類來封裝樹形控件的各種操作。通過調(diào)用BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );創(chuàng)建一個窗口,dwStyle中可以使用以下一些樹形控件的專用風格:
TVS_HASLINES 在父/子結點之間繪制連線
TVS_LINESATROOT 在根/子結點之間繪制連線
TVS_HASBUTTONS 在每一個結點前添加一個按鈕,用于表示當前結點是否已被展開
TVS_EDITLABELS 結點的顯示字符可以被編輯
TVS_SHOWSELALWAYS 在失去焦點時也顯示當前選中的結點
TVS_DISABLEDRAGDROP 不允許Drag/Drop
TVS_NOTOOLTIPS 不使用ToolTip顯示結點的顯示字符 在樹形控件中每一個結點都有一個句柄(HTREEITEM),同時添加結點時必須提供的參數(shù)是該結點的父結點句柄,(其中根Root結點只有一個,既不可以添加也不可以刪除)利用HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );可以添加一個結點,pszItem為顯示的字符,hParent代表父結點的句柄,當前添加的結點會排在hInsertAfter表示的結點的后面,返回值為當前創(chuàng)建的結點的句柄。下面的代碼會建立一個如下形式的樹形結構: +--- Parent1 +--- Child1_1 +--- Child1_2 +--- Child1_3 +--- Parent2 +--- Parent3 /*假設m_tree為一個CTreeCtrl對象,而且該窗口已經(jīng)創(chuàng)建*/ HTREEITEM hItem,hSubItem; hItem = m_tree.InsertItem("Parent1",TVI_ROOT); 在根結點上添加Parent1 hSubItem = m_tree.InsertItem("Child1_1",hItem); //在Parent1上添加一個子結點 hSubItem = m_tree.InsertItem("Child1_2",hItem,hSubItem);//在Parent1上添加一個子結點,排在Child1_1后面 hSubItem = m_tree.InsertItem("Child1_3",hItem,hSubItem); hItem = m_tree.InsertItem("Parent2",TVI_ROOT,hItem); hItem = m_tree.InsertItem("Parent3",TVI_ROOT,hItem); 如果你希望在每個結點前添加一個小圖標,就必需先調(diào)用CImageList* SetImageList( CImageList * pImageList, int nImageListType );指明當前所使用的ImageList,nImageListType為TVSIL_NORMAL。在調(diào)用完成后控件中使用圖片以設置的ImageList中圖片為準。然后調(diào)用
HTREEITEM InsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);添加結點,nImage為結點沒被選中時所使用圖片序號,nSelectedImage為結點被選中時所使用圖片序號。下面的代碼演示了ImageList的設置。 /*m_list 為CImageList對象 IDB_TREE 為16*(16*4)的位圖,每個圖片為16*16共4個圖標*/ m_list.Create(IDB_TREE,16,4,RGB(0,0,0)); m_tree.SetImageList(&m_list,TVSIL_NORMAL); m_tree.InsertItem("Parent1",0,1);//添加, 選中時顯示圖標1,未選中時顯示圖標0
此外CTreeCtrl還提供了一些函數(shù)用于得到/修改控件的狀態(tài)。
HTREEITEM GetSelectedItem( );將返回當前選中的結點的句柄。BOOL SelectItem( HTREEITEM hItem );將選中指明結點。
BOOL GetItemImage( HTREEITEM hItem, int& nImage, int& nSelectedImage ) / BOOL SetItemImage( HTREEITEM hItem, int nImage, int nSelectedImage )用于得到/修改某結點所使用圖標索引。
CString GetItemText( HTREEITEM hItem ) /BOOL SetItemText( HTREEITEM hItem, LPCTSTR lpszItem );用于得到/修改某一結點的顯示字符。
BOOL DeleteItem( HTREEITEM hItem );用于刪除某一結點,BOOL DeleteAllItems( );將刪除所有結點。
此外如果想遍歷樹可以使用下面的函數(shù):
HTREEITEM GetRootItem( );得到根結點。
HTREEITEM GetChildItem( HTREEITEM hItem );得到子結點。
HTREEITEM GetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem );得到指明結點的上/下一個兄弟結點。
HTREEITEM GetParentItem( HTREEITEM hItem );得到父結點。
樹形控件的消息映射使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode為通知代碼,id為產(chǎn)生該消息的窗口ID,memberFxn為處理函數(shù),函數(shù)的原型如同void OnXXXTree(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR為一數(shù)據(jù)結構,在具體使用時需要轉換成其他類型的結構。對于樹形控件可能取值和對應的數(shù)據(jù)結構為:
TVN_SELCHANGED 在所選中的結點發(fā)生改變后發(fā)送,所用結構:NMTREEVIEW
TVN_ITEMEXPANDED 在某結點被展開后發(fā)送,所用結構:NMTREEVIEW
TVN_BEGINLABELEDIT 在開始編輯結點字符時發(fā)送,所用結構:NMTVDISPINFO
TVN_ENDLABELEDIT 在結束編輯結點字符時發(fā)送,所用結構:NMTVDISPINFO
TVN_GETDISPINFO 在需要得到某結點信息時發(fā)送,(如得到結點的顯示字符)所用結構:NMTVDISPINFO 關于ON_NOTIFY有很多內(nèi)容,將在以后的內(nèi)容中進行詳細講解。
關于動態(tài)提供結點所顯示的字符:首先你在添加結點時需要指明lpszItem參數(shù)為:LPSTR_TEXTCALLBACK。在控件顯示該結點時會通過發(fā)送TVN_GETDISPINFO來取得所需要的字符,在處理該消息時先將參數(shù)pNMHDR轉換為LPNMTVDISPINFO,然后填充其中item.pszText。但是我們通過什么來知道該結點所對應的信息呢,我的做法是在添加結點后設置其lParam參數(shù),然后在提供信息時利用該參數(shù)來查找所對應的信息。下面的代碼說明了這種方法: char szOut[8][3]={"No.1","No.2","No.3"}; //添加結點 HTREEITEM hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...) m_tree.SetItemData(hItem, 0 ); hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...) m_tree.SetItemData(hItem, 1 ); //處理消息 void CParentWnd::OnGetDispInfoTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; pTVDI->item.pszText=szOut[pTVDI->item.lParam];//通過lParam得到 需要顯示的字符在數(shù)組中的位置 *pResult = 0; }
關于編輯結點的顯示字符:首先需要設置樹形控件的TVS_EDITLABELS風格,在開始編輯時該控件將會發(fā)送TVN_BEGINLABELEDIT,你可以通過在處理函數(shù)中返回TRUE來取消接下來的編輯,在編輯完成后會發(fā)送TVN_ENDLABELEDIT,在處理該消息時需要將參數(shù)pNMHDR轉換為LPNMTVDISPINFO,然后通過其中的item.pszText得到編輯后的字符,并重置顯示字符。如果編輯在中途中取消該變量為NULL。下面的代碼說明如何處理這些消息: //處理消息 TVN_BEGINLABELEDIT void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; if(pTVDI->item.lParam==0);//判斷是否取消該操作 *pResult = 1; else *pResult = 0; } //處理消息 TVN_BEGINLABELEDIT void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; if(pTVDI->item.pszText==NULL);//判斷是否已經(jīng)取消取消編輯 m_tree.SetItemText(pTVDI->item.hItem,pTVDI->pszText);//重置顯示字符 *pResult = 0; } 上面講述的方法所進行的消息映射必須在父窗口中進行(同樣WM_NOTIFY的所有消息都需要在父窗口中處理)。
TVS_HASLINES 在父/子結點之間繪制連線
TVS_LINESATROOT 在根/子結點之間繪制連線
TVS_HASBUTTONS 在每一個結點前添加一個按鈕,用于表示當前結點是否已被展開
TVS_EDITLABELS 結點的顯示字符可以被編輯
TVS_SHOWSELALWAYS 在失去焦點時也顯示當前選中的結點
TVS_DISABLEDRAGDROP 不允許Drag/Drop
TVS_NOTOOLTIPS 不使用ToolTip顯示結點的顯示字符 在樹形控件中每一個結點都有一個句柄(HTREEITEM),同時添加結點時必須提供的參數(shù)是該結點的父結點句柄,(其中根Root結點只有一個,既不可以添加也不可以刪除)利用HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );可以添加一個結點,pszItem為顯示的字符,hParent代表父結點的句柄,當前添加的結點會排在hInsertAfter表示的結點的后面,返回值為當前創(chuàng)建的結點的句柄。下面的代碼會建立一個如下形式的樹形結構: +--- Parent1 +--- Child1_1 +--- Child1_2 +--- Child1_3 +--- Parent2 +--- Parent3 /*假設m_tree為一個CTreeCtrl對象,而且該窗口已經(jīng)創(chuàng)建*/ HTREEITEM hItem,hSubItem; hItem = m_tree.InsertItem("Parent1",TVI_ROOT); 在根結點上添加Parent1 hSubItem = m_tree.InsertItem("Child1_1",hItem); //在Parent1上添加一個子結點 hSubItem = m_tree.InsertItem("Child1_2",hItem,hSubItem);//在Parent1上添加一個子結點,排在Child1_1后面 hSubItem = m_tree.InsertItem("Child1_3",hItem,hSubItem); hItem = m_tree.InsertItem("Parent2",TVI_ROOT,hItem); hItem = m_tree.InsertItem("Parent3",TVI_ROOT,hItem); 如果你希望在每個結點前添加一個小圖標,就必需先調(diào)用CImageList* SetImageList( CImageList * pImageList, int nImageListType );指明當前所使用的ImageList,nImageListType為TVSIL_NORMAL。在調(diào)用完成后控件中使用圖片以設置的ImageList中圖片為準。然后調(diào)用
HTREEITEM InsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);添加結點,nImage為結點沒被選中時所使用圖片序號,nSelectedImage為結點被選中時所使用圖片序號。下面的代碼演示了ImageList的設置。 /*m_list 為CImageList對象 IDB_TREE 為16*(16*4)的位圖,每個圖片為16*16共4個圖標*/ m_list.Create(IDB_TREE,16,4,RGB(0,0,0)); m_tree.SetImageList(&m_list,TVSIL_NORMAL); m_tree.InsertItem("Parent1",0,1);//添加, 選中時顯示圖標1,未選中時顯示圖標0
此外CTreeCtrl還提供了一些函數(shù)用于得到/修改控件的狀態(tài)。
HTREEITEM GetSelectedItem( );將返回當前選中的結點的句柄。BOOL SelectItem( HTREEITEM hItem );將選中指明結點。
BOOL GetItemImage( HTREEITEM hItem, int& nImage, int& nSelectedImage ) / BOOL SetItemImage( HTREEITEM hItem, int nImage, int nSelectedImage )用于得到/修改某結點所使用圖標索引。
CString GetItemText( HTREEITEM hItem ) /BOOL SetItemText( HTREEITEM hItem, LPCTSTR lpszItem );用于得到/修改某一結點的顯示字符。
BOOL DeleteItem( HTREEITEM hItem );用于刪除某一結點,BOOL DeleteAllItems( );將刪除所有結點。
此外如果想遍歷樹可以使用下面的函數(shù):
HTREEITEM GetRootItem( );得到根結點。
HTREEITEM GetChildItem( HTREEITEM hItem );得到子結點。
HTREEITEM GetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem );得到指明結點的上/下一個兄弟結點。
HTREEITEM GetParentItem( HTREEITEM hItem );得到父結點。
樹形控件的消息映射使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode為通知代碼,id為產(chǎn)生該消息的窗口ID,memberFxn為處理函數(shù),函數(shù)的原型如同void OnXXXTree(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR為一數(shù)據(jù)結構,在具體使用時需要轉換成其他類型的結構。對于樹形控件可能取值和對應的數(shù)據(jù)結構為:
TVN_SELCHANGED 在所選中的結點發(fā)生改變后發(fā)送,所用結構:NMTREEVIEW
TVN_ITEMEXPANDED 在某結點被展開后發(fā)送,所用結構:NMTREEVIEW
TVN_BEGINLABELEDIT 在開始編輯結點字符時發(fā)送,所用結構:NMTVDISPINFO
TVN_ENDLABELEDIT 在結束編輯結點字符時發(fā)送,所用結構:NMTVDISPINFO
TVN_GETDISPINFO 在需要得到某結點信息時發(fā)送,(如得到結點的顯示字符)所用結構:NMTVDISPINFO 關于ON_NOTIFY有很多內(nèi)容,將在以后的內(nèi)容中進行詳細講解。
關于動態(tài)提供結點所顯示的字符:首先你在添加結點時需要指明lpszItem參數(shù)為:LPSTR_TEXTCALLBACK。在控件顯示該結點時會通過發(fā)送TVN_GETDISPINFO來取得所需要的字符,在處理該消息時先將參數(shù)pNMHDR轉換為LPNMTVDISPINFO,然后填充其中item.pszText。但是我們通過什么來知道該結點所對應的信息呢,我的做法是在添加結點后設置其lParam參數(shù),然后在提供信息時利用該參數(shù)來查找所對應的信息。下面的代碼說明了這種方法: char szOut[8][3]={"No.1","No.2","No.3"}; //添加結點 HTREEITEM hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...) m_tree.SetItemData(hItem, 0 ); hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...) m_tree.SetItemData(hItem, 1 ); //處理消息 void CParentWnd::OnGetDispInfoTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; pTVDI->item.pszText=szOut[pTVDI->item.lParam];//通過lParam得到 需要顯示的字符在數(shù)組中的位置 *pResult = 0; }
關于編輯結點的顯示字符:首先需要設置樹形控件的TVS_EDITLABELS風格,在開始編輯時該控件將會發(fā)送TVN_BEGINLABELEDIT,你可以通過在處理函數(shù)中返回TRUE來取消接下來的編輯,在編輯完成后會發(fā)送TVN_ENDLABELEDIT,在處理該消息時需要將參數(shù)pNMHDR轉換為LPNMTVDISPINFO,然后通過其中的item.pszText得到編輯后的字符,并重置顯示字符。如果編輯在中途中取消該變量為NULL。下面的代碼說明如何處理這些消息: //處理消息 TVN_BEGINLABELEDIT void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; if(pTVDI->item.lParam==0);//判斷是否取消該操作 *pResult = 1; else *pResult = 0; } //處理消息 TVN_BEGINLABELEDIT void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR; if(pTVDI->item.pszText==NULL);//判斷是否已經(jīng)取消取消編輯 m_tree.SetItemText(pTVDI->item.hItem,pTVDI->pszText);//重置顯示字符 *pResult = 0; } 上面講述的方法所進行的消息映射必須在父窗口中進行(同樣WM_NOTIFY的所有消息都需要在父窗口中處理)。