MFC应用技术之CTreeControl的使用
一丶MFC添加树控件.添加父节点跟子节点.
MFC上面放一个树控件.并未这个树控件绑定变量.然后添加一个按钮.按钮的作用就是添加父节点跟子节点.
PS: 关于MFC如果添加控件.这里不做讲解.此篇只用于应用.所以常用的都会列举出来.
树控件添加结点注意用的 方法是 InsertItem()
这个方法是重载的有很多种. 这里只讲解自己常用的一种.其余的查询MSDN即可.
添加父节点跟子节点.
void CTreeControlDlg::OnBnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 HTREEITEM Root = m_RootControl.InsertItem(_T("父节点")); 返回一个句柄 m_RootControl.InsertItem(_T("子节点5"), Root,TVI_SORT); 继续调用这个方法添加的时候.参数二是父节点返回的句柄.则添加结点到父节点下面. 参数三是排序的意思.可以默认不加. m_RootControl.InsertItem(_T("子节点4"), Root, TVI_SORT); m_RootControl.InsertItem(_T("子节点3"), Root, TVI_SORT); m_RootControl.InsertItem(_T("子节点2"), Root, TVI_SORT); m_RootControl.InsertItem(_T("子节点1"), Root, TVI_SORT); }
应用截图:
二丶获取树控件父节点以及子节点
获取树控件父节点 方法是 GetRootItem() 返回的Item句柄就是父节点. GetChildItem() 则是获取子节点.传入父节点.返回子节点.
GetItemText(句柄) 返回这个句柄的字符串. GetParentItem() 获取子节点的父节点.
看如下代码:
void CTreeControlDlg::OnBnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 HTREEITEM Root = m_RootControl.GetRootItem(); //获取顶层结点. HTREEITEM ChildItem = m_RootControl.GetChildItem(Root); CString strText = m_RootControl.GetItemText(ChildItem); AfxMessageBox(strText); }
应用截图:
三丶根据根节点获取兄弟结点
获取根节点我们知道了.就是GetRootItem(); 那么获取兄弟结点是什么意思?
意思就是兄弟的意思. 假设我们有三个父结点.
父结点0
父节点1
父节点2
我们首先获取父节点0的Item 然后继续获取他的兄弟结点.兄弟结点就是父节点1
方法: GetNextSiblingItem() 获取指定结点的下一个兄弟
方法: GetPrevSiblingItem(); 获取指定结点的上一个兄弟.
具体代码例子:
void CTreeControlDlg::OnBnClickedButton3() { // TODO: 在此添加控件通知处理程序代码 HTREEITEM Root = m_RootControl.GetRootItem(); //获取根节点 HTREEITEM BrothorItem = m_RootControl.GetNextSiblingItem(Root);//获取跟结点的下一个兄弟结点 CString strText = m_RootControl.GetItemText(BrothorItem); //获取兄弟结点的文本穿 AfxMessageBox(strText); }
应用截图:
获取上一个兄弟结点
void CTreeControlDlg::OnBnClickedButton4() { // TODO: 在此添加控件通知处理程序代码 HTREEITEM Root = m_RootControl.GetRootItem(); HTREEITEM BrothorItem1 = m_RootControl.GetNextSiblingItem(Root); //获取下一个兄弟结点 这里我们要先获取下一个兄弟.因为根节点的上一个兄弟没有了. HTREEITEM BrothorItem2 = m_RootControl.GetPrevSiblingItem(BrothorItem1); //获取上一个兄弟 这里就是获取第二个节点的上一个兄弟,也就是父节点0 CString strText = m_RootControl.GetItemText(BrothorItem2); AfxMessageBox(strText); }
应用截图:
四丶根据指定结点.递归遍历下面所有子节点.
上面都是简单的使用. 所以真正使用我们要遍历结点. 比如遍历父节点下面的所有子节点.
递归遍历:
1.递归遍历指定结点下面所有的子节点
void CTreeControlDlg::OnBnClickedButton5() { // TODO: 在此添加控件通知处理程序代码 //1.获取根节点 HTREEITEM RootItem = m_RootControl.GetRootItem(); IteratorTreeChild(RootItem); } void CTreeControlDlg::IteratorTreeChild(HTREEITEM item) { CString strText = m_RootControl.GetItemText(item); //获取字符串.并且弹出. AfxMessageBox(strText); //定义两个结点.一个当前结点.一个下一个结点. HTREEITEM CurItem; HTREEITEM NextItem; CurItem = m_RootControl.GetChildItem(item); //当前结点是子节点. while (CurItem != NULL) { //继续遍历集结点. NextItem = CurItem; IteratorTreeChild(NextItem); CurItem = m_RootControl.GetNextSiblingItem(NextItem); } }
代码只打印了.
1.传入根节点.
2.定义两个结点.
3.当前结点是子节点的Item
4.下一个结点也是Item
5.递归遍历.
6.如果没有.则获取下一个子节点.也就是子节点的兄弟结点.
实现截图:
2.循环遍历指定结点下面的一层子节点
上图是递归遍历所有子节点.但是有的时候我们只需要遍历一层即可.
例如下图: 我们只需要遍历到子节点5.
实现代码:
void CTreeControlDlg::IteratorTreeChild2(HTREEITEM item) //循环遍历当前父节点的子节点.不深层遍历 { HTREEITEM CurrItem = m_RootControl.GetChildItem(item); // 获取子节点句柄 CString strText; while (CurrItem) { strText = m_RootControl.GetItemText(CurrItem); AfxMessageBox(strText); CurrItem = m_RootControl.GetNextSiblingItem(CurrItem); //获取子节点的兄弟结点即可. } } void CTreeControlDlg::OnBnClickedButton6() { // TODO: 在此添加控件通知处理程序代码 HTREEITEM RootItem = m_RootControl.GetRootItem(); //根据根节点遍历根节点下面的一层子节点. IteratorTreeChild2(RootItem); }
3.递归遍历所有父节点下面的所有子节点
如果我们要遍历所有父节点.跟他的子节点. 则需要稍微更改下代码即可.也就是第一种代码的改进.
实现代码:
void CTreeControlDlg::OnBnClickedButton7() { // TODO: 在此添加控件通知处理程序代码 HTREEITEM RootItem = m_RootControl.GetRootItem(); do { IteratorTreeChild1(RootItem); //递归方法是第一种里面的.所以不再重复写了 } while ((RootItem = m_RootControl.GetNextSiblingItem(RootItem)) != NULL); //主要就是这里.循环遍历父节点的兄弟结点. }
4.循环遍历所有父节点下的第一层子节点.
上面的是遍历父节点下的子节点. 所有的子节点. 子节点的子节点也遍历.但是我们只需要遍历一层
void CTreeControlDlg::OnBnClickedButton7() { // TODO: 在此添加控件通知处理程序代码 HTREEITEM RootItem = m_RootControl.GetRootItem(); HTREEITEM CurItem; CString strText; do { CurItem = m_RootControl.GetChildItem(RootItem); //双层循环.第一层遍历父节点.第二层遍历子节点的兄弟结点. while (CurItem) { strText = m_RootControl.GetItemText(CurItem); AfxMessageBox(strText); CurItem = m_RootControl.GetNextSiblingItem(CurItem); } } while ((RootItem = m_RootControl.GetNextSiblingItem(RootItem)) != NULL); }
常用的遍历差不多就这些了.我们看下响应时间消息
五丶事件消息
树控件的消息有如下.
通知消息说明
TVN_BEGINDRAG指示拖放操作的开始。
TVN_BEGINLABELEDIT将通知开始就地编辑标签
TVN_BEGINRDRAG使用鼠标右键,终止拖放操作的开始,
TVN_DELETEITEM标志着特定中删除项
TVN_ENDLABELEDIT信号的结束编辑标签
TVN_GETDISPINFO请求树控件需要显示的项的信息。
TVN_ITEMEXPANDED子项父项的列表展开或折叠的信号
TVN_ITEMEXPANDING子项的父项列表会展开或折叠的信号
TVN_KEYDOWN信号键盘事件
TVN_SELCHANGE信号从中选择一项更改为另一个架构
TVN_SELCHANGING指示选定项即将从一项变为另一项
TVN_GETDISPINFO更新的信息通知为维护项
具体可以查询MSDN
MSDN 链接: https://technet.microsoft.com/zh-cn/library/38x8htxs.aspx/
关于我们主要讲解 TVN_SELCHANGE 也就是当选择则会改变.
如果添加事件消息.那么会有如下代码.
void CTreeControlDlg::OnTvnSelchangedTree1(NMHDR *pNMHDR, LRESULT *pResult) { LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); // TODO: 在此添加控件通知处理程序代码 *pResult = 0; }
这个是给我们默认添加的. 而返回值是微软已经给我们转好的.所以我们需要的信息就在里面.我们可以看下结构内容.
LPNMTREEVIEW 这是一个宏.宽版本还是A版本. 熟悉Windows的都应该知道.
看下对应的结构
typedef struct tagNMTREEVIEWW { NMHDR hdr; UINT action; TVITEMW itemOld; 旧的Item TVITEMW itemNew; 当前点击的Item POINT ptDrag; 坐标 } NMTREEVIEWW, *LPNMTREEVIEWW;
里面有一个新的结构体.也就是 TVITEMW
看下这个结构里面内容.
typedef struct tagTVITEMW { UINT mask; HTREEITEM hItem; 当前的hitem结构 UINT state; 状态. UINT stateMask; LPWSTR pszText; 文本. int cchTextMax; int iImage; 图像 int iSelectedImage; 选择图形 int cChildren; LPARAM lParam; 附加参数 } TVITEMW, *LPTVITEMW;
当然上面是我自己理解的然后加的注释.不过没有错误. 而我们常用的就是 hitem结构.
所以如果我们要获取选择项的item文本就用如下代码.
void CTreeControlDlg::OnTvnSelchangedTree1(NMHDR *pNMHDR, LRESULT *pResult) { LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); // TODO: 在此添加控件通知处理程序代码 HTREEITEM Root = pNMTreeView->itemNew.hItem; CStringW str = m_RootControl.GetItemText(Root); AfxMessageBox(str); *pResult = 0; }
或者是点击子节点.获取她的父节点.
void CTreeControlDlg::OnTvnSelchangedTree1(NMHDR *pNMHDR, LRESULT *pResult) { LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); // TODO: 在此添加控件通知处理程序代码 HTREEITEM Child = pNMTreeView->itemNew.hItem; HTREEITEM Root = m_RootControl.GetParentItem(Child); CString str = m_RootControl.GetItemText(Root); AfxMessageBox(str); *pResult = 0; }