对于TreeControl常用操作,做如下介绍。

1. TreeControl添加节点

  1. 在界面种选择TreeControl控件,点击右键,在弹出的菜单种选择【添加变量】,在弹出的界面中输入变量名 "m_list”

  2. 点击界面右键,在弹出的菜单中选择【类向导】,选中“虚函数”选项卡,选择其中的“OnInitDialog”函数,然后点击【添加函数按钮】,然后点击确定。

  3. 将TreeControl控件中的属性“Has Buttons”、”Line at root“和“Has Line”后改为 “True”,如果相实现双击更改其值的功能,则将”Edit Labels“改为”True“

  4. 如果想要在树节点前添加图标,则需要导入*.icon的图标文件。具体方法为:

    选择资源视图,在资源视图中点击右键,在弹出的菜单中选择【添加资源】,在弹出的界面中点击【导入】按钮,然后选择.icon的文件。此图标导入后的名称为”IDI_ICON1“

  5. 在初始化函数中添加节点代码

//在.h文件中添加如下代码
CImageList m_imageList1;
//修改初始化函数
BOOL TreeTest::OnInitDialog()
{
CDialogEx::OnInitDialog(); m_list.SetBkColor(RGB(230,230,230));//设置树的颜色 m_imageList1.Create(16,16,ILC_COLOR8|ILC_MASK,0,4);//第五个参数为图标的总数
m_imageList1.Add(AfxGetApp()->LoadIconW(IDI_ICON1));//将图标添加到imageList中 m_list.SetImageList(&m_imageList1,TVSIL_NORMAL);//将图标进行加载 HTREEITEM root = m_list.InsertItem(_T("root"));//插入根节点
HTREEITEM hChild1 = m_list.InsertItem(_T("child1"),root);//在根节点下插入子节点
HTREEITEM hChild2 = m_list.InsertItem(_T("child2"),root);//在根节点下插入子节点
HTREEITEM hChild3 = m_list.InsertItem(_T("child3"),root);//在根节点下插入子节点 m_list.SetItemImage(root,0,0);//设置根节点图标
m_list.SetItemImage(hChild1,0,0);
m_list.SetItemImage(hChild2,0,0);
m_list.SetItemImage(hChild3,0,0);//设置子节点图标,注意:第一个参数为要设置的节点、第二个参数为默认状态下的图标、第三个值为选中后的图标。 return TRUE; // return TRUE unless you set the focus to a control }

2. TreeControl菜单

  1. 新建一个菜单,内容为”增加“、”删除“、”重命名“
  2. 选中Tree控件,点击右键,在弹出的菜单中选择”类向导“;在弹出的界面中选择【命令】、对象下选择”IDC_TREE1“,在消息中选择右键消息”NM_RCLICK“,然后点击【添加处理程序】按钮。
  3. 选中节点后才可以加载菜单,具体代码如下:
void TreeTest::OnRclickTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
CPoint ScreenPt;
GetCursorPos(&ScreenPt); CPoint pt =GetCurrentMessage()->pt;//获取当前鼠标点击消息的坐标点
m_list.ScreenToClient(&pt);//将鼠标的屏幕坐标,转换成树控件的客户区域坐标
UINT uFlags = 0;
HTREEITEM hItem = m_list.HitTest(pt,&uFlags);//然后做点击测试 /**判断右键是否在节点上**/
if ((hItem != NULL)&&(TVHT_ONITEM & uFlags))//如果点击位置在界面位置上面
{ CMenu menu;
menu.LoadMenuW(IDR_MENU1);//装载第一个子菜单,即我们菜单的第一列
CMenu* pPopup = menu.GetSubMenu(0);
pPopup->TrackPopupMenu(TPM_LEFTALIGN, ScreenPt.x, ScreenPt.y, this);//弹出菜单 2 }
*pResult = 0;
}

3. TreeControl修改节点

参考链接

实现双击修改节点名称,双击时速度需要慢一些,快速双击为展开和折叠节点

  1. 属性设置:将”Edit Labels“改为”True“
  2. 选中Tree控件,在弹出的菜单中选择【类向导】,添加消息函数”TVN_BEGINLABELEDIT“ 和 ”TVN_ENDLABELEDIT“
  3. 添加全局变量CString g_sSelectStr
  4. 修改两个消息函数,,如下:
void TreeTest::OnBeginlabeleditTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR); g_sSelectStr = m_list.GetItemText(m_list.GetSelectedItem());//得到修改前的数据
*pResult = 0;
} void TreeTest::OnEndlabeleditTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR); CString strName; //修改后的数据
CString rootstr;
m_list.GetEditControl()->GetWindowText(strName);
if (strName.IsEmpty())
{
AfxMessageBox(_T("数据项不能为空,请重新输入"));
return;
}
if (strName.Compare(g_sSelectStr) == 0)//名字未做修改
{
return;
}
//判断是否由重复的名字
HTREEITEM hRoot = m_list.GetRootItem();
HTREEITEM hFind = FindItem(hRoot,strName);
if (hFind == NULL)//如果没有重名,则修改
{
CString strText;
m_list.GetEditControl()->GetWindowText(strText);
m_list.SetItemText(m_list.GetSelectedItem(),strText);
}
*pResult = 0;
}

4. TreeControl查找节点

//根据名称来查找节点
HTREEITEM TreeTest::FindItem(HTREEITEM item,CString strText)
{
HTREEITEM hFind;
if (item == NULL)//修改数据与根数据不同,遍历时使用
{
return NULL;
}
while(item != NULL)
{
if (strText.Compare(m_list.GetItemText(item)) == 0)//名字相同
{
return item;
}
if (m_list.ItemHasChildren(item))//如果有子节点,则继续判断
{
item = m_list.GetChildItem(item);
hFind = FindItem(item,strText);
if (hFind)
{
return hFind;
}
else
{
item = m_list.GetNextSiblingItem(m_list.GetParentItem(item));
}
}
else
{
item = m_list.GetNextSiblingItem(item);
return FindItem(item,strText);
}
}
return item;
}

5. TreeControl折叠展开节点

//折叠所有的树节点
void TreeTest::mFoldTree(HTREEITEM hTreeItem)
{
if(!m_list.ItemHasChildren(hTreeItem))
{
return;
}
HTREEITEM hNextItem = m_list.GetChildItem(hTreeItem);
while (hNextItem != NULL)
{
ExpandTree(hNextItem);
hNextItem = m_list.GetNextItem(hNextItem, TVGN_NEXT);
}
m_list.Expand(hTreeItem,TVE_COLLAPSE);
} //展开所有的树节点
void TreeTest::ExpandTree(HTREEITEM hTreeItem)
{
if(!m_list.ItemHasChildren(hTreeItem))
{
return;
}
HTREEITEM hNextItem = m_list.GetChildItem(hTreeItem);
while (hNextItem != NULL)
{
ExpandTree(hNextItem);
hNextItem = m_list.GetNextItem(hNextItem, TVGN_NEXT);
}
HTREEITEM hchild = m_list.GetChildItem(hTreeItem);
CString NodeData,NodeName;
NodeName = m_list.GetItemText(hchild);
if (NodeData.Compare(_T("2")) == 0 )
{
return;
}
m_list.Expand(hTreeItem,TVE_EXPAND);
} //展开单独的树节点
void TreeTest::ExpandTree2(HTREEITEM hTreeItem)
{
if(!m_list.ItemHasChildren(hTreeItem))
{
return;
}
HTREEITEM hNextItem = m_list.GetChildItem(hTreeItem);
while (hNextItem != NULL)
{
ExpandTree(hNextItem);
hNextItem = m_list.GetNextItem(hNextItem, TVGN_NEXT);
}
m_list.Expand(hTreeItem,TVE_EXPAND);
} void TreeTest::OnClickTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
hTreeItem = m_list.GetSelectedItem();
*pResult = 0;
} //折叠树按钮
void TreeTest::OnBnClickedButton1()
{
HTREEITEM hItem = m_list.GetSelectedItem();
if (hItem == NULL)
{
HTREEITEM hroot = m_list.GetRootItem();
mFoldTree(hroot);
}
else
{
mFoldTree(hItem);
}
} //展开树按钮
void TreeTest::OnBnClickedButton7()
{
HTREEITEM hItem = m_list.GetSelectedItem();
if (hItem == NULL)
{
HTREEITEM hroot = m_list.GetRootItem();
ExpandTree(hroot);
}
else
{
ExpandTree2(hItem);
}
}

6. TreeControl拖动树

参考网址1

参考网址2

参考网址3

参考网址4

创建树的时候,使用继承类TreeControl进行创建。例如:

注意:此方法目前具有一定的局限性,即节点下必须有子节点,才可以完成拖动。后期进行优化

CXtreeCtrl m_list;
HTREEITEM root = m_list.InsertItem(_T("root"));
HTREEITEM parent1 = m_list.InsertItem(_T("1"),root);
m_list.InsertItem(_T("11"),parent1); HTREEITEM parent2 = m_list.InsertItem(_T("2"),root);
m_list.InsertItem(_T("21"),parent2); HTREEITEM parent3 = m_list.InsertItem(_T("3"),root);
m_list.InsertItem(_T("31"),parent3); HTREEITEM parent4 = m_list.InsertItem(_T("4"),root);
m_list.InsertItem(_T("41"),parent4);

7. 继承类TreeControl

XTreeCtrl.cpp

// XtreeCtrl.cpp : implementation file
// #include "stdafx.h"
#include "Drag.h"
#include "XtreeCtrl.h"
#define DRAG_DELAY 60 // CXtreeCtrl IMPLEMENT_DYNAMIC(CXtreeCtrl, CTreeCtrl) CXtreeCtrl::CXtreeCtrl()
{
m_bDragging = FALSE;
//m_hSelectItem = NULL;
m_hItemDragS = NULL;
m_nHoverTimerID = 0;
m_nScrollTimerID = 0;
m_bInsertAbove = FALSE;
m_hItemDragD = NULL; } CXtreeCtrl::~CXtreeCtrl()
{
} BEGIN_MESSAGE_MAP(CXtreeCtrl, CTreeCtrl)
ON_NOTIFY_REFLECT(TVN_BEGINDRAG, &CXtreeCtrl::OnTvnBegindrag)
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_TIMER()
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP() // CXtreeCtrl message handlers void CXtreeCtrl::OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: Add your control notification handler code here *pResult = 0;
if( (GetTickCount() - m_dwDragStart) < DRAG_DELAY )
return; m_hItemDragS = pNMTreeView->itemNew.hItem;
if (!ItemHasChildren(m_hItemDragS)) //子节点不能被拖拽,注释后可以随意拖拽
{
return;
}
m_hItemDragD = NULL;
m_bDragging = true;
m_nScrollTimerID = SetTimer( 2,40,NULL );
}
HTREEITEM CXtreeCtrl::GetDragTarget(HTREEITEM hItem, POINT point, BOOL& bInsertAbove)
{
ASSERT(hItem != NULL);
HTREEITEM hDragTarget;
CRect rectItem;
GetItemRect(hItem, &rectItem, FALSE);
if (point.y < rectItem.CenterPoint().y)
{
hDragTarget = hItem;
bInsertAbove = TRUE;
}
else
{
if (ItemHasChildren(hItem) && (GetItemState(hItem, TVIS_EXPANDED) & TVIS_EXPANDED))
{
hDragTarget = GetChildItem(hItem);
bInsertAbove = TRUE;
}
else
{
hDragTarget = hItem;
bInsertAbove = FALSE;
}
}
ASSERT(hDragTarget != NULL);
return hDragTarget;
} void CXtreeCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default HTREEITEM hItem;
UINT flags;
if (m_nHoverTimerID > 0)
{
KillTimer(m_nHoverTimerID);
m_nHoverTimerID = 0;
}
if( m_bDragging )
{
m_nHoverTimerID = SetTimer(1, 800, NULL);
m_HoverPoint = point;
//鼠标经过时高亮显示
CImageList::DragShowNolock( false ); //避免鼠标经过时留下难看的痕迹
HTREEITEM m_hNextDragTarget;
BOOL m_bNextInsertAbove;
if( (hItem = HitTest(point,&flags)) != NULL )
{
m_hNextDragTarget = GetDragTarget(hItem, point, m_bNextInsertAbove);
if ((m_hNextDragTarget != m_hItemDragD) || (m_bInsertAbove != m_bNextInsertAbove))
{
SelectDropTarget(m_hNextDragTarget);
m_hItemDragD = m_hNextDragTarget;
m_bInsertAbove = m_bNextInsertAbove;
EnsureVisible(m_hItemDragD);
RedrawWindow();
}
}
if ((GetScrollPos(SB_HORZ) > 0) && (GetScrollLimit(SB_VERT) > 0))
{
Invalidate();
}
}
CTreeCtrl::OnMouseMove(nFlags, point);
}
HTREEITEM CXtreeCtrl::CopyItem(HTREEITEM hItem1, HTREEITEM htiNewParent, HTREEITEM htiAfter) //拷贝条目
{
TV_ITEM tvSrc;
tvSrc.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
tvSrc.hItem = hItem1;
if (!GetItem(&tvSrc))
return htiNewParent; tvSrc.hItem = htiNewParent;
SetItem(&tvSrc);
SetItemText(htiNewParent,GetItemText(hItem1));
SetCheck(htiNewParent,GetCheck (hItem1)); if (tvSrc.state & TVIS_EXPANDED)
Expand(htiNewParent,TVE_EXPAND);
}
HTREEITEM CXtreeCtrl::CopyBranch(HTREEITEM htiBranch, HTREEITEM htiNewParent, HTREEITEM htiAfter) //拷贝分支
{
ASSERT((htiNewParent != NULL) && (htiBranch != NULL));
HTREEITEM hChild;
hChild = GetChildItem( htiBranch );
while ( hChild != NULL )
{
HTREEITEM hChildDest = InsertItem(_T("dest child"), htiNewParent);
CopyBranch( hChild,hChildDest,htiAfter );
CopyItem(hChild,hChildDest,htiAfter);
hChild = GetNextSiblingItem( hChild );
}
return htiNewParent;
} HTREEITEM CXtreeCtrl::InsertItemAndSubtree(HTREEITEM hParent)
{
if ((m_hItemDragD == NULL) || (m_hItemDragS == NULL))
{
ASSERT(FALSE);
return NULL;
}
HTREEITEM hRoot = GetRootItem();
if (!ItemHasChildren(m_hItemDragD)) //如果注释可以随意拖拽父节点到子节点(自己看效果)
{
return NULL;
} else if (hRoot == m_hItemDragD) //如果注释可以随意拖拽父节点至根节点(自己看效果)
{
return NULL;
}
if (hParent == NULL)
hParent = GetParentItem(m_hItemDragD);
if (hParent == NULL)
hParent = TVI_ROOT; HTREEITEM hInsertAfter; if (m_bInsertAbove)
hInsertAfter = GetPrevSiblingItem(m_hItemDragD);
else
hInsertAfter = m_hItemDragD; if ((hInsertAfter == hParent) || (hInsertAfter == NULL))
hInsertAfter = TVI_FIRST; HTREEITEM hNew = InsertItem(_T("dummy"), hParent, hInsertAfter);
if (hNew == NULL)
return NULL; CopyBranch(m_hItemDragS,hNew,m_hItemDragD);
CopyItem(m_hItemDragS,hNew,m_hItemDragD); return hNew;
} void CXtreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CTreeCtrl::OnLButtonUp(nFlags, point);
if(m_bDragging)
{
m_bLeftBtnUp = TRUE;
KillTimer(m_nScrollTimerID);
m_nScrollTimerID = 0;
KillTimer(m_nHoverTimerID);
m_nHoverTimerID = 0;
ReleaseCapture();
ShowCursor(true);
m_bDragging = false;
SelectDropTarget(NULL);
if (m_bLeftBtnUp)
{
if (m_hItemDragD != NULL)
m_bGoingOK = TRUE;
HTREEITEM m_hParentNew = m_hItemDragD;
while (m_hParentNew != NULL)
{ if(m_hParentNew == m_hItemDragS)
{
//AfxMessageBox(_T("禁止此操作!"), MB_ICONEXCLAMATION);
m_bGoingOK = FALSE;
break;
}
m_hParentNew = GetParentItem(m_hParentNew);
}
HTREEITEM m_hParent;
if (m_bGoingOK)
{
SetRedraw(FALSE);
m_hParent = GetParentItem(m_hItemDragD);
if (m_hParent == NULL)
m_hParent = TVI_ROOT;
if (m_bGoingOK)
{
// We're finally ready to insert the actual item.
HTREEITEM hNew = InsertItemAndSubtree(m_hParent);
if (hNew != NULL)
{
SelectItem(hNew);
DeleteItem(m_hItemDragS);
}
}
}
// Regardless of what happens, we need to reset the tree.
SetRedraw(TRUE);
Invalidate();
}
else
{
// The User chose to abort the drag
EnsureVisible(m_hItemDragS);
// Refresh the screen to get rid of any remnants of the drag drawing
Invalidate();
} }
CTreeCtrl::OnLButtonUp(nFlags, point);
} void CXtreeCtrl::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
if( nIDEvent == m_nHoverTimerID)
{
KillTimer( m_nHoverTimerID);
m_nHoverTimerID = 0;
HTREEITEM trItem = 0;
UINT uFlag = 0;
trItem = HitTest(m_HoverPoint,&uFlag);
if( trItem && m_bDragging)
{
SelectItem(trItem);
//Expand( trItem,TVE_EXPAND );
}
}
else if(nIDEvent == m_nScrollTimerID)
{
m_TimerTicks++;
CPoint pt;
GetCursorPos(&pt);
CRect rect;
GetClientRect(&rect);
ClientToScreen(&rect);
HTREEITEM hItem = GetFirstVisibleItem();
if( pt.y < rect.top +10)
{
int slowscroll = 6 - (rect.top + 10 - pt.y )/20;
if( 0 == (m_TimerTicks % ((slowscroll > 0) ? slowscroll : 1)))
{
CImageList::DragShowNolock (false);
SendMessage( WM_VSCROLL,SB_LINEUP);
SelectDropTarget(hItem);
m_hItemDragD = hItem;
CImageList::DragShowNolock (true);
}
}
else if(pt.y > rect.bottom - 10)
{
int slowscroll = 6 - (pt.y - rect.bottom + 10)/20; if( 0 == (m_TimerTicks % ((slowscroll > 0) ? slowscroll : 1)))
{
CImageList::DragShowNolock (false);
SendMessage(WM_VSCROLL,SB_LINEDOWN);
int nCount = GetVisibleCount();
for( int i=0 ; i<nCount-1 ; i++ )
hItem = GetNextVisibleItem( hItem);
if( hItem)
SelectDropTarget(hItem); m_hItemDragD = hItem;
CImageList::DragShowNolock (true);
}
}
}
else
CTreeCtrl::OnTimer(nIDEvent);
} void CXtreeCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//m_dwDragStart = GetTickCount();
//m_hSelectItem = GetSelectedItem();
//UINT nHitFlags = 0;
//HTREEITEM hClickedItem = HitTest( point, &nHitFlags );
CTreeCtrl::OnLButtonDown(nFlags, point);
}

XTreeCtrl.h

#pragma once

// CXtreeCtrl

class CXtreeCtrl : public CTreeCtrl
{
DECLARE_DYNAMIC(CXtreeCtrl) public:
CXtreeCtrl();
virtual ~CXtreeCtrl(); protected:
DECLARE_MESSAGE_MAP() public:
afx_msg void OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
protected:
DWORD m_dwDragStart;
UINT m_nScrollTimerID;
UINT m_nHoverTimerID;
UINT m_TimerTicks;
POINT m_HoverPoint;
BOOL m_bDragging;
BOOL m_bInsertAbove;
BOOL m_bLeftBtnUp;
BOOL m_bGoingOK;
CImageList* m_pDragImage;
HTREEITEM m_hItemDragS;
HTREEITEM m_hItemDragD;
HTREEITEM m_hSelectItem;
HTREEITEM CopyBranch(HTREEITEM htiBranch,HTREEITEM htiNewParent,HTREEITEM htiAfter);
HTREEITEM CopyItem(HTREEITEM hItem,HTREEITEM htiNewParent,HTREEITEM htiAfter);
HTREEITEM GetDragTarget(HTREEITEM hItem, POINT point, BOOL& bInsertAbove);
HTREEITEM InsertItemAndSubtree(HTREEITEM hParent = NULL);
};

最新文章

  1. 动手做第一个Chrome插件
  2. ios 开发之单例模式
  3. java编程题
  4. spring mvc拦截器
  5. Lost connection to MySQL server at 'reading initial communication packet' 错误解决
  6. Substrings
  7. deepin系统下部署Python3.5的开发及运行环境
  8. Apache、Lighttpd、Nginx 三种web服务器对比
  9. Unity3D UGUI强制刷新Layout(布局)组件
  10. Vmware虚拟机不能使用键盘的解决方法
  11. 根据IO流源码深入理解装饰设计模式使用
  12. 关于微信内置浏览器在ios上播放提示音的经验分享
  13. C#对接----韵达开发平台--取电子面单
  14. Oracle Instant Client(即时客户端) 安装与配置
  15. Linux内核学习期末总结(网课)
  16. 一次webapck4 配置文件无效的解决历程
  17. 《FPGA全程进阶---实战演练》第七章 让按键恢复平静
  18. sqler sql 转rest api 源码解析(一)应用的启动入口
  19. Appium自动化部署及连接Appium服务
  20. python yaml文件读写

热门文章

  1. 其他 - 阻塞 &amp; 同步 的基本认识
  2. Linux list_head
  3. * ./common/http.js in ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-opt
  4. mac 电脑安装express、npm…… 报 ‘Missing write access to /usr/local/lib/node_modules’错误解决办法
  5. vue去掉地址栏# 方法
  6. IIS-7.5 第一次加载慢的 解决办法
  7. P2141
  8. windows 下安装chrome 调试iphone插件 ios-webkit-debug-proxy
  9. Vue入门学习总结一:Vue定义
  10. ETCD监控