?? vcc77.htm
字號:
<html>
<head>
<title>c++系列</title>
<meta content="text/html; charset=gb2312" http-equiv=Content-Type>
</head>
<p align="center"><script src="../../1.js"></script></a>
<body bgcolor="#ffffff" leftmargin="5" topmargin="1" marginheight="5" marginwidth="5">
<div align=center>
<table border=0 cellpadding=0 cellspacing=0 width=680 align="center">
<tbody>
<tr>
<td width=200 height="59">
</tr>
</tbody>
</table>
<table border=1 bordercolordark=#ffffff bordercolorlight=#ffffff cellpadding=0
cellspacing=0 width=685 align="center" height="70">
<tbody>
<tr>
<td bgcolor=#F9D23C height=14>
<div align=center class=H1><font color="#FFFFFF">Tree Ctrl</font></div>
</td>
</tr>
<tr valign=top>
<td class=H1 height=51>
<p align="left">樹形控件TreeCtrl和下節(jié)要講的列表控件 ListCtrl在系統(tǒng)中大量被使用,例如Windows資源管理器就是一個典型的例子。</p>
<p class="unnamed1">樹形控件可以用于樹形的結(jié)構(gòu),其中有一個根接點(Root)然后下面有許多子結(jié)點,而每個子結(jié)點上有允許有一個或多個或沒有子結(jié)點。MFC中使用CTreeCtrl類來封裝樹形控件的各種操作。通過調(diào)用<br>
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
UINT nID );創(chuàng)建一個窗口,dwStyle中可以使用以下一些樹形控件的專用風(fēng)格:
<ul>
<li class="unnamed1"><b>TVS_HASLINES</b> 在父/子結(jié)點之間繪制連線
<li class="unnamed1"><b>TVS_LINESATROOT</b> 在根/子結(jié)點之間繪制連線
<li class="unnamed1"><b>TVS_HASBUTTONS</b> 在每一個結(jié)點前添加一個按鈕,用于表示當(dāng)前結(jié)點是否已被展開
<li class="unnamed1"><b>TVS_EDITLABELS</b> 結(jié)點的顯示字符可以被編輯
<li class="unnamed1"><b>TVS_SHOWSELALWAYS</b> 在失去焦點時也顯示當(dāng)前選中的結(jié)點
<li class="unnamed1"><b>TVS_DISABLEDRAGDROP</b> 不允許Drag/Drop
<li class="unnamed1"><b>TVS_NOTOOLTIPS</b> 不使用ToolTip顯示結(jié)點的顯示字符 </li>
</ul>
<span class="unnamed1">在樹形控件中每一個結(jié)點都有一個句柄(HTREEITEM),同時添加結(jié)點時必須提供的參數(shù)是該結(jié)點的父結(jié)點句柄,(其中根Root結(jié)點只有一個,既不可以添加也不可以刪除)利用<br>
HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT,
HTREEITEM hInsertAfter = TVI_LAST );可以添加一個結(jié)點,pszItem為顯示的字符,hParent代表父結(jié)點的句柄,當(dāng)前添加的結(jié)點會排在hInsertAfter表示的結(jié)點的后面,返回值為當(dāng)前創(chuàng)建的結(jié)點的句柄。下面的代碼會建立一個如下形式的樹形結(jié)構(gòu):
+--- Parent1 +--- Child1_1 +--- Child1_2 +--- Child1_3 +--- Parent2 +---
Parent3 <font
color=green>/*假設(shè)m_tree為一個CTreeCtrl對象,而且該窗口已經(jīng)創(chuàng)建*/</font> HTREEITEM
hItem,hSubItem; hItem = m_tree.InsertItem("Parent1",TVI_ROOT);<font
color=green> 在根結(jié)點上添加Parent1</font> hSubItem = m_tree.InsertItem("Child1_1",hItem);<font color=green>
//在Parent1上添加一個子結(jié)點</font> hSubItem = m_tree.InsertItem("Child1_2",hItem,hSubItem);<font
color=green>//在Parent1上添加一個子結(jié)點,排在Child1_1后面</font> hSubItem = m_tree.InsertItem("Child1_3",hItem,hSubItem);
hItem = m_tree.InsertItem("Parent2",TVI_ROOT,hItem); hItem = m_tree.InsertItem("Parent3",TVI_ROOT,hItem);
如果你希望在每個結(jié)點前添加一個小圖標,就必需先調(diào)用CImageList* SetImageList( CImageList * pImageList,
int nImageListType );指明當(dāng)前所使用的ImageList,nImageListType為TVSIL_NORMAL。在調(diào)用完成后控件中使用圖片以設(shè)置的ImageList中圖片為準。然后調(diào)用<br>
HTREEITEM InsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage,
HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);添加結(jié)點,nImage為結(jié)點沒被選中時所使用圖片序號,nSelectedImage為結(jié)點被選中時所使用圖片序號。下面的代碼演示了ImageList的設(shè)置。
<font color=green>/*m_list 為CImageList對象 IDB_TREE 為16*(16*4)的位圖,每個圖片為16*16共4個圖標*/</font>
m_list.Create(IDB_TREE,16,4,RGB(0,0,0)); m_tree.SetImageList(&m_list,TVSIL_NORMAL);
m_tree.InsertItem("Parent1",0,1);<font color=green>//添加, 選中時顯示圖標1,未選中時顯示圖標0</font>
</span>
<p></p>
<p class="unnamed1">此外CTreeCtrl還提供了一些函數(shù)用于得到/修改控件的狀態(tài)。 <br>
HTREEITEM GetSelectedItem( );將返回當(dāng)前選中的結(jié)點的句柄。BOOL SelectItem( HTREEITEM
hItem );將選中指明結(jié)點。 <br>
BOOL GetItemImage( HTREEITEM hItem, int& nImage, int& nSelectedImage
) / BOOL SetItemImage( HTREEITEM hItem, int nImage, int nSelectedImage
)用于得到/修改某結(jié)點所使用圖標索引。 <br>
CString GetItemText( HTREEITEM hItem ) /BOOL SetItemText( HTREEITEM
hItem, LPCTSTR lpszItem );用于得到/修改某一結(jié)點的顯示字符。 <br>
BOOL DeleteItem( HTREEITEM hItem );用于刪除某一結(jié)點,BOOL DeleteAllItems( );將刪除所有結(jié)點。
</p>
<p class="unnamed1">此外如果想遍歷樹可以使用下面的函數(shù): <br>
HTREEITEM GetRootItem( );得到根結(jié)點。 <br>
HTREEITEM GetChildItem( HTREEITEM hItem );得到子結(jié)點。 <br>
HTREEITEM GetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem );得到指明結(jié)點的上/下一個兄弟結(jié)點。
<br>
HTREEITEM GetParentItem( HTREEITEM hItem );得到父結(jié)點。 </p>
<p class="unnamed1">樹形控件的消息映射使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode,
id, memberFxn ),wNotifyCode為通知代碼,id為產(chǎn)生該消息的窗口ID,memberFxn為處理函數(shù),函數(shù)的原型如同void
OnXXXTree(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR為一數(shù)據(jù)結(jié)構(gòu),在具體使用時需要轉(zhuǎn)換成其他類型的結(jié)構(gòu)。對于樹形控件可能取值和對應(yīng)的數(shù)據(jù)結(jié)構(gòu)為:
<ul>
<li class="unnamed1">TVN_SELCHANGED 在所選中的結(jié)點發(fā)生改變后發(fā)送,所用結(jié)構(gòu):NMTREEVIEW
<li class="unnamed1">TVN_ITEMEXPANDED 在某結(jié)點被展開后發(fā)送,所用結(jié)構(gòu):NMTREEVIEW
<li class="unnamed1">TVN_BEGINLABELEDIT 在開始編輯結(jié)點字符時發(fā)送,所用結(jié)構(gòu):NMTVDISPINFO
<li class="unnamed1">TVN_ENDLABELEDIT 在結(jié)束編輯結(jié)點字符時發(fā)送,所用結(jié)構(gòu):NMTVDISPINFO
<li class="unnamed1">TVN_GETDISPINFO 在需要得到某結(jié)點信息時發(fā)送,(如得到結(jié)點的顯示字符)所用結(jié)構(gòu):NMTVDISPINFO
</li>
</ul>
關(guān)于ON_NOTIFY有很多內(nèi)容,將在以后的內(nèi)容中進行詳細講解。 </span>
<p></p>
<p class="unnamed1"><strong>關(guān)于動態(tài)提供結(jié)點所顯示的字符</strong>:首先你在添加結(jié)點時需要指明lpszItem參數(shù)為:LPSTR_TEXTCALLBACK。在控件顯示該結(jié)點時會通過發(fā)送TVN_GETDISPINFO來取得所需要的字符,在處理該消息時先將參數(shù)pNMHDR轉(zhuǎn)換為LPNMTVDISPINFO,然后填充其中item.pszText。但是我們通過什么來知道該結(jié)點所對應(yīng)的信息呢,我的做法是在添加結(jié)點后設(shè)置其lParam參數(shù),然后在提供信息時利用該參數(shù)來查找所對應(yīng)的信息。下面的代碼說明了這種方法:
char szOut[8][3]={"No.1","No.2","No.3"}; //添加結(jié)點 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; }
<p></p>
<p class="unnamed1"><strong>關(guān)于編輯結(jié)點的顯示字符</strong>:首先需要設(shè)置樹形控件的TVS_EDITLABELS風(fēng)格,在開始編輯時該控件將會發(fā)送TVN_BEGINLABELEDIT,你可以通過在處理函數(shù)中返回TRUE來取消接下來的編輯,在編輯完成后會發(fā)送TVN_ENDLABELEDIT,在處理該消息時需要將參數(shù)pNMHDR轉(zhuǎn)換為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的所有消息都需要在父窗口中處理)。
<p></p>
<div align="left"> </div>
</td>
</tr>
</tbody>
</table>
</div>
<p align="center"><script src="../../2.js"></script></a>
</body>
</html>
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -