本文转载自:VC驿站
https://www.cctry.com/thread-297465-1-1.html
1、控件简介:
Tree树形控件也是我们编程过程中比较常用的一个控件,而且在其他软件中也经常能看到,比如Windows系统中的资源管理器:
所以,接下来我就教大家如何来使用这个控件!
2、控件的使用:
a、拖拽Tree树形控件到对话框模版上;
b、一些常用的属性:
Check Boxes:结点前是否带有复选框;
Edit Labels:结点名字是否可编辑;
Has Buttons:父节点是否有+号可供展开;
Has Lines:父子结点之间是否有连接线;
Lines At Root:是否从根节点开始就带有虚线;
等等吧,大家可以根据自己的需要设置相关的属性。
c、为Tree树形控件绑定一个 CTreeCtrl 控件类型变量m_Tree;
3、控件的操作:
在树形控件中每一个结点都有一个句柄(HTREEITEM),同时插入结点时必须提供父结点句柄,(其中根Root结点只有一个,既不可以添加也不可以删除)利用
HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );
可以插入一个结点,pszItem为显示的字符,hParent代表父结点的句柄,当前添加的结点会排在hInsertAfter表示的结点的后面,返回值为当前创建的结点的句柄。
a、添加结点(有多种重载方式,先介绍第一种):
HTREEITEM hRoot = m_Tree.InsertItem(_T("父1"));
HTREEITEM hSub1 = m_Tree.InsertItem(_T("子1"), hRoot);
HTREEITEM hSub2 = m_Tree.InsertItem(_T("子2"), hRoot);
HTREEITEM hSub3 = m_Tree.InsertItem(_T("子子1"), hSub2);
就这样,可以一层一层的向树形控件中插入节点。
b、获得节点的文本:m_Tree.GetItemText(hSub3);
c、设置节点的文本:m_Tree.SetItemText(hSub3, _T("abc"));
d、获得当前选中的节点:HTREEITEM hSelItem = m_Tree.GetSelectedItem();
e、设置当前选中的节点:m_Tree.SelectItem(hTreeItem);
f、默认上面的情况都是针对单选,那么Tree树形控件支不支持多选呢?答案是:默认不支持
不过可以通过给节点前面加上 CheckBox 复选框来解决!下个知识点举例讲解!
备注:那么不通过CheckBox 能不能实现多选呢?答案也是可以的,不过要写很多自定义代码,大家感兴趣的话可以看看这几篇文章,课堂上咱们就不讲解了:
http://www.codeguru.com/cpp/cont ... d/article.php/c629/
http://www.codeguru.com/cpp/cont ... d/article.php/c723/
http://www.codeguru.com/cpp/cont ... /article.php/c9219/
g、遍历子节点:
需要用到的相关函数:
HTREEITEM GetRootItem( ); //得到根结点。
HTREEITEM GetChildItem(HTREEITEM hItem); //得到子结点。
HTREEITEM GetPrevSiblingItem/GetNextSiblingItem(HTREEITEM hItem); //得到指明结点的上/下一个兄弟结点。
HTREEITEM GetParentItem(HTREEITEM hItem); //得到父结点。
从根节点开始遍历所有节点,判断 CheckBox 是否勾选:
void CMFCTestDlg::EnumTreeItem(HTREEITEM hItem)
{
if (!hItem) return;
//先检测自己是否被勾选
if (m_Tree.GetCheck(hItem))
{
CString strText = m_Tree.GetItemText(hItem);
MessageBox(strText + _T("##勾选了!"));
}
//再遍历所有的子节点
if (m_Tree.ItemHasChildren(hItem))
{
HTREEITEM hChildItem = m_Tree.GetChildItem(hItem);
while (hChildItem)
{
EnumTreeItem(hChildItem);
HTREEITEM hNextItem = m_Tree.GetNextItem(hChildItem, TVGN_NEXT);
hChildItem = hNextItem;
}
}
}
void CMFCTestDlg::OnBnClickedBtnTree()
{
HTREEITEM hRootItem = m_Tree.GetRootItem(); //从根节点开始遍历
EnumTreeItem(hRootItem);
}
h、删除节点、删除所有节点:
m_Tree.DeleteItem(hSub2); //删除节点
m_Tree.DeleteAllItems(); //删除所有节点
i:展开/收起所有节点:
void CMFCTestDlg::ExpandTree(HTREEITEM hItem, UINT nCode)
{
if (!hItem) return;
m_Tree.Expand(hItem, nCode);
if (m_Tree.ItemHasChildren(hItem))
{
HTREEITEM hChildItem = m_Tree.GetChildItem(hItem);
while (hChildItem)
{
ExpandTree(hChildItem, nCode);
HTREEITEM hNextItem = m_Tree.GetNextItem(hChildItem, TVGN_NEXT);
hChildItem = hNextItem;
}
}
}
void CMFCTestDlg::OnBnClickedBtnTree()
{
HTREEITEM hRootItem = m_Tree.GetRootItem(); //从根节点开始遍历
static UINT nCode = TVE_EXPAND;
ExpandTree(hRootItem, nCode);
nCode = (nCode == TVE_EXPAND) ? TVE_COLLAPSE : TVE_EXPAND;
}
j:编辑节点文本:
①、控件的 Edit Labels 属性设置为 True;
②、响应控件的 TVN_BEGINLABELEDIT 事件:
void CMFCTestDlg::OnTvnBeginlabeleditTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast
CEdit *pEdit = m_Tree.GetEditControl();
if (pEdit) pEdit->LimitText(5);//设置编辑框文本长度为5个字符串
*pResult = 0; //继续
//*pResult = 1; //取消,不继续编辑,也不触发 TVN_ENDLABELEDIT
}
③、响应控件的 TVN_ENDLABELEDIT 事件:
void CMFCTestDlg::OnTvnEndlabeleditTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast
if (pTVDispInfo && pTVDispInfo->item.pszText && _tcslen(pTVDispInfo->item.pszText))
{
m_Tree.SetItemText(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
}
*pResult = 0;
}
k、插入带图标的节点:
这里面给大家准备几个ico图标,供程序使用: ico.zip
①、将几个ico图标文件添加到工程资源中,ID分别为:IDI_ICON1、IDI_ICON2、IDI_ICON3
②、在对话框类类的头文件中加入对象声明:CImageList m_TreeImage;
③、在对话框的初始化函数中创建图像列表:BOOL bRet = m_TreeImage.Create(16, 16, ILC_MASK | ILC_COLOR32, 1, 1);
④、添加图标资源到图像列表:
int iret = m_TreeImage.Add(AfxGetApp()->LoadIcon(IDI_ICON1));
iret = m_TreeImage.Add(AfxGetApp()->LoadIcon(IDI_ICON2));
iret = m_TreeImage.Add(AfxGetApp()->LoadIcon(IDI_ICON3));
⑤、关联Tree树形控件和图像列表:m_Tree.SetImageList(&m_TreeImage, TVSIL_NORMAL);
⑥、将InsertItem插入节点的代码改为:
HTREEITEM hRoot = m_Tree.InsertItem(_T("根"), 0, 1);
HTREEITEM hSub1 = m_Tree.InsertItem(_T("子1"), 0, 1, hRoot);
HTREEITEM hSub2 = m_Tree.InsertItem(_T("子2"), 0, 1, hRoot);
HTREEITEM hSub3 = m_Tree.InsertItem(_T("子子3"), 0, 1, hSub2);
这样就可以啦~!
其中 InsertItem 的第二个参数0和第三个参数1是ico图标在ImageList中的索引,第二个参数是节点默认的图标,第三个参数是节点被选中后的图标。
4、开源控件类:
codeproject 上面关于 Tree树形控件 的开源控件类可谓是很多啊,这里面给大家分享一下,需要哪种自己直接拿过去用就行了:
https://www.codeproject.com/Arti ... port-for-HTML-XML-S
https://www.codeproject.com/Arti ... -Supports-Transpare
https://www.codeproject.com/Articles/6597/CDeviceTree
https://www.codeproject.com/Arti ... -select-folders-and
https://www.codeproject.com/Articles/2243/COptionTree
https://www.codeproject.com/Arti ... operty-Tree-Control
https://www.codeproject.com/Arti ... gImage-in-CTreeCtrl
https://www.codeproject.com/Arti ... heckboxes-Supported
https://www.codeproject.com/Arti ... esque-Owner-Drawn-C
https://www.codeproject.com/Arti ... l-that-has-Open-Clo
https://www.codeproject.com/Arti ... Millers-COptionTree
https://www.codeproject.com/Articles/768/CNetworkTreeCtrl
https://www.codeproject.com/Arti ... FX-and-CHourglassFX
https://www.codeproject.com/Articles/2913/A-Tree-List-Control
https://www.codeproject.com/Arti ... wn-TreeList-Control
https://www.codeproject.com/Arti ... th-ToolTip-Based-On
https://www.codeproject.com/Arti ... ontrol-with-Columns
5、小作业:
①、给Tree树形控件添加右键弹出菜单,菜单中有个复制的菜单项,点击可以复制结点的文本;
②、点选控件的 CheckBox 后,实际上当前选中的结点不是我点击的结点,能否做到勾选CheckBox 之后,就选中该结点;
③、实现三态CheckBox,可以直接找开源类来实现:https://www.codeproject.com/Articles/847799/CQuadStateTree
具体操作细节见视频教程的演示和讲解!
第15课免费试看,下载地址:
https://www.cctry.com/thread-297465-1-1.html