轉自:http://www.vckbase.com/index.php/wv/1352
首先,我們要創(chuàng)建一個基本對話框的MFC工程MFC_TreeCRTL(名字隨便給一個)。然后在資源視圖中插入兩個Dialog,ID分別為IDD_DIALOG11和IDD_DIALOG211,都更改Style屬性為Child,Border屬性為None,為它們建立兩個類,分別命名為Cdialog11和Cdialog211,并在MFC_TreeCRTLDlg.CPP文件中包含dialog11.h和dialog211.h兩個頭文件。再導入幾個資源圖標作為樹形控件節(jié)點的圖標及裝飾面板。最后在主面板上添加一個CTreeCtrl控件,ID為默認,并在ClassWizard中添加它的一個變量,命名為m_mytree。
接著,我們進行具體代碼編寫。
我們必須在CMFC_TreeCRTLDlg類中加入這些變量和函數(shù)
樹形控件TreeCtrl和下節(jié)要講的列表控件
關于創(chuàng)建及風格:
樹形控件可以用于樹形的結構,其中有一個根接點(Root)然后下面有許多子結點,而每個子結點上有允許有一個或多個或沒有子結點。MFC中使用CTreeCtrl類來封裝樹形控件的各種操作。通過調用Create創(chuàng)建一個窗口:
BOOL
dwStyle中可以使用以下一些樹形控件的專用風格:
在5.80版中,即使沒有圖片,也會顯示復選框。
這種風格一旦創(chuàng)建,將不能移除。只能destroy后再create一個新的。
TVS_DISABLEDRAGDROP
TVS_EDITLABELS
TVS_FULLROWSELECT
TVS_HASBUTTONS
TVS_HASLINES
TVS_INFOTIP
TVS_LINESATROOT
TVS_NOHSCROLL
TVS_NONEVENHEIGHT
TVS_NOSCROLL
TVS_NOTOOLTIPS
TVS_RTLREADING
TVS_SHOWSELALWAYS
TVS_SINGLEEXPAND
關于增加/刪除
HTREEITEM
pszItem為顯示的字符
hParent代表父結點的句柄,當前添加的結點會排在hInsertAfter表示的結點的后面,返回值為當前創(chuàng)建的結點的句柄。
下面的代碼會建立一個如下形式的樹形結構:
+---
+---
+---
HTREEITEM
//在根結點上添加Parent1
hItem
//在Parent1上添加一個子結點
hSubItem
//在Parent1上添加一個子結點,排在Child1_1后面
hSubItem
hSubItem
hItem
hItem
關于添加圖標
如果你希望在每個結點前添加一個小圖標,就必需先調用
CImageList*
指明當前所使用的ImageList,nImageListType為TVSIL_NORMAL。在調用完成后控件中使用圖片以設置的ImageList中圖片為準。然后調用InsertItem添加結點:
HTREEITEM
nImage為結點沒被選中時所使用圖片序號,nSelectedImage為結點被選中時所使用圖片序號。下面的代碼演示了ImageList的設置。
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
關于插入標記
這是拖曳時經常用到的函數(shù)。
BOOL SetInsertMark( HTREEITEM hItem, BOOL fAfter = TRUE );
TRUE表示在hItem下面顯示橫杠,而FALSE則表示在上面。
同類函數(shù)還有:
SetInsertMarkColor,GetInsertMarkColor
關于得到/修改控件狀態(tài)
此外CTreeCtrl還提供了一些函數(shù)用于得到/修改控件的狀態(tài)。
HTREEITEM
BOOL
BOOL
BOOL
CString
BOOL
BOOL
BOOL
如何展開/收縮一個父節(jié)點?
hItem | 要被擴展的tree項的句柄。 | ||||||||||||
nCode | 用來指示要被進行的動作的標志。這個標志可以是下列值之一:
|
關于遍歷:
此外如果想遍歷樹可以使用下面的函數(shù):
HTREEITEM
HTREEITEM
HTREEITEM
HTREEITEM
<后面有兩個遍歷例程>
關于消息映射:
樹形控件的消息映射使用ON_NOTIFY宏,形式如同:
ON_NOTIFY(
wNotifyCode為通知代碼,id為產生該消息的窗口ID
memberFxn為處理函數(shù),函數(shù)的原型如同void
TVN_SELCHANGED
TVN_ITEMEXPANDED
TVN_BEGINLABELEDIT
TVN_ENDLABELEDIT
TVN_GETDISPINFO
關于ON_NOTIFY有很多內容,將在以后的內容中進行詳細講解。
消息處理例程:
響應NM_RCLICK消息
void CLayerDialog::OnRclick(NMHDR* pNMHDR, LRESULT* pResult)
{
}
如何響應checkbox被單擊?
響應NM_CLICK消息(checkbox就是分支前面的復選框,可從資源中修改屬性添加)
void CLayerDialog::OnLclick(NMHDR *pNMHDR,LRESULT *pResult)
{
}
設置和獲取checkbox的狀態(tài)函數(shù)
GetCheck( )
SetCheck( )
如何知道某個點在CTreeCtrl上的位置
CTreeCtrl::HitTest
HTREEITEM HitTest( CPoint pt, UINT* pFlags );
返回值:
參數(shù):
pt | in |
pFlags | out 其中flags測試結果可以是如下值: TVHT_BELOW 在客戶區(qū)域下面 TVHT_NOWHERE 在客戶區(qū)域中并在最后一項下面 TVHT_ONITEM 在與樹項關聯(lián)的位圖或標簽內 TVHT_ONITEMBUTTON 在與樹項關聯(lián)的按鈕上 TVHT_ONITEMICON 在與樹項關聯(lián)的位圖上 TVHT_ONITEMINDENT 在與樹項關聯(lián)的聯(lián)線上 TVHT_ONITEMLABEL 在與樹項關聯(lián)的標簽上 TVHT_ONITEMRIGHT 在樹項的右側區(qū)域中 TVHT_ONITEMSTATEICON 在用戶定義的狀態(tài)圖標上 TVHT_TOLEFT 在客戶區(qū)域的左側 TVHT_TORIGHT 在客戶區(qū)域的右側 |
pHitTestInfo | in/out 一個包含點擊測試的位置并接收測試結果的信息的TVHITTESTINFO結構的地址。 typedef struct _TVHITTESTINFO { |
說明:
此成員函數(shù)用來確定相對于一個tree view控件的客戶區(qū)的指定點的定位。
當調用這個函數(shù)時,pt參數(shù)指定要測試的點的坐標。此函數(shù)返回位于指定點的項的句柄,或者如果沒有項位于該點則返回NULL。另外,pFlags參數(shù)包含了指明指定點的定位的值。
關于動態(tài)提供結點所顯示的字符
char
//添加結點
HTREEITEM
m_tree.SetItemData(hItem,
hItem
m_tree.SetItemData(hItem,
//處理消息
void
{
TV_DISPINFO*
pTVDI-> item.pszText=szOut[pTVDI-> item.lParam];//通過lParam得到需要顯示的字符在數(shù)組中的位置
*pResult
}
關于編輯結點的顯示字符
首先需要設置樹形控件的TVS_EDITLABELS風格,在開始編輯時該控件將會發(fā)送TVN_BEGINLABELEDIT,你可以通過在處理函數(shù)中返回TRUE來取消接下來的編輯,在編輯完成后會發(fā)送TVN_ENDLABELEDIT,在處理該消息時需要將參數(shù)pNMHDR轉換為LPNMTVDISPINFO,然后通過其中的item.pszText得到編輯后的字符,并重置顯示字符。如果編輯在中途中取消該變量為NULL。下面的代碼說明如何處理這些消息:
//處理消息
void
{
TV_DISPINFO*
if(pTVDI-> item.lParam==0);//判斷是否取消該操作
*pResult
else
*pResult
}
//處理消息
void
{
TV_DISPINFO*
if(pTVDI-> item.pszText==NULL);//判斷是否已經取消取消編輯
m_tree.SetItemText(pTVDI-> item.hItem,pTVDI-> pszText);//重置顯示字符
*pResult
}
上面講述的方法所進行的消息映射必須在父窗口中進行(同樣WM_NOTIFY的所有消息都需要在父窗口中處理)。
關于修改樹控件的背景位圖
BOOL CMyTreeCtrl::SetBKImage(LPCTSTR LpszResource)
void CMyTreeCtrl::OnPaint()
void CMyTreeCtrl::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
void CMyTreeCtrl::OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult)
BOOL CMyTreeCtrl::OnEraseBkgnd(CDC* pDC)
我的實踐代碼:
MFC:
關于變量:
在資源文件的主對話框上添加一個CTreeCtrl控件,選中此控件點擊右鍵->CalassWizard->Member Variables 在這項中雙擊CTreeCtrl控件的ID,關聯(lián)這個控件與一個CTreeCtrl變量(eg m_TreeCtrl)
關于屬性設置:
增加 TreeCtrl 的 TVS_HASBUTTONS,TVS_HASLINES、TVS_LINESATROOT Style,代碼如下:
如何插入一個節(jié)點:
HTREEITEM hRoot,hItem,hItem1,hItem2,hSubItem,hSubItem1;
hRoot = m_TreeCtrl.InsertItem("我的電腦");//并不是不是真正意義上的根節(jié)點,只是在視覺效果上看起來是
hItem = m_TreeCtrl.InsertItem( "Parent1 ",hRoot);
hSubItem = m_TreeCtrl.InsertItem("child1",hItem);
hSubItem1 = m_TreeCtrl.InsertItem("child2",hItem,hSubItem);
hItem1 = m_TreeCtrl.InsertItem( "Parent2 ",hRoot,hItem);
hItem2 = m_TreeCtrl.InsertItem( "Parent3 ",hRoot,hItem1);
效果圖:
現(xiàn)在我想往child1和child2前加上圖標:
首先,構造出來ImageList :
CImageList* imageList=new CImageList();
imageList->Create(19, 19, ILC_COLOR24|ILC_MASK, 20, 1);
//參數(shù)意義:參看:http://blog.sina.com.cn/s/blog_4b3c1f950100b0eh.html
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL,"D:\Project\TEMP\1.bmp",IMAGE_BITMAP,
19,19,LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
CBitmap* m_bitmap = new CBitmap();
m_bitmap->Attach(hBitmap);
imageList->Add(m_bitmap,RGB(0, 0, 0));//參數(shù)意義,下面有解釋
然后,把ImageList和TreeCtrl關聯(lián)起來:
m_TreeCtrl.SetImageList(imageList,TVSIL_NORMAL);
注:這個關聯(lián)必須在m_TreeCtrl插入節(jié)點之前。
然后,在插入子節(jié)點時這樣:
hSubItem = m_TreeCtrl.InsertItem("child1",0,1,hItem);
//添加節(jié)點 "child1",未選中時圖標為imageList的第0個,選中后圖標為imageList的第1個.
效果圖:
待解答.....
?????有什么方法能在子節(jié)點的位置上不是只是一個字符串,而是插入一個其他的控件呢????
待解答.....
pbmImage | 指向包含一個或多個圖象的位圖的指針。圖象數(shù)由位圖寬推斷。 |
pbmMask | 指向包含掩碼的位圖的指針。如果無掩碼與圖象列表一起使用,則此參數(shù)被忽略。 |
crMask | 生成掩碼的顏色。指定位圖中的此顏色的每個像素被改為黑色,掩碼中的相應位數(shù)被設置為1。 |
hIcon | 包含新圖象的位圖和掩碼的圖標的句柄。 |
遍歷例程:
以下是采用遞歸完成的遍歷樹的函數(shù):
遍歷樹
//hitem:待遍歷樹的根節(jié)點
void TreeVisit(HTREEITEM hItem)
{
if(ItemHasChildren(hItem))
{
HTREEITEM hChildItem = GetChildItem(hItem);
while(hChildItem!=NULL)
{
hChildItem = GetNextItem(hChildItem, TVGN_NEXT);
}
}
}
如何根據(jù)名稱查找樹中的某個節(jié)點(必須是節(jié)點名稱是唯一的)
//item:待遍歷樹的根節(jié)點,strtext:待查找節(jié)點名稱
HTREEITEM finditem(HTREEITEM item, CString strtext)
{