目录
对于TreeControl常用操作,做如下介绍。
如果想要在树节点前添加图标,则需要导入*.icon的图标文件。具体方法为:
选择资源视图,在资源视图中点击右键,在弹出的菜单中选择【添加资源】,在弹出的界面中点击【导入】按钮,然后选择.icon的文件。此图标导入后的名称为”IDI_ICON1“
//在.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 }
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; }
参考链接
实现双击修改节点名称,双击时速度需要慢一些,快速双击为展开和折叠节点
CString g_sSelectStr
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; }
//根据名称来查找节点 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; }
//折叠所有的树节点 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); } }
创建树的时候,使用继承类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);
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); };
推荐文章
package cn.itcast.datasource.jdbctemplate;import cn.itcast.utils.JDBCUtils;import org.springframework.jdbc.core.JdbcTemplate;import javax.sql.DataSource;/** * @author newcit
推荐文章
题目描述 如何设计一个好的数据库不仅仅是一个理论研究问题,也是一个实际应用问题。在关系数据库中不满足规范化理论的数据库设计会存在冗余、插入异常、删除异常等现象。 设R(U)是一个关系模式,U={ A1,A2, ……, An}。其中Ai是关系的属性,X,Y是U的子集。函数依赖 X-&g
推荐文章
功能简介: 在一个输入框中输入内容 ,当内容长度>1时向后发送ajax 从数据库中获取有关文本框中的内容在前台显示, 前台设计一些点击事件,以及jquery的应用 注意: request.getParameter("postData").trim() 放在判断之前可能会空指针异常 如果
推荐文章
nodejs进阶教程,小白绕道!!! npm使用技巧和最佳实践 前提:请确保安装了node.js npm的最佳实践 npm install是最常见的npm cli命令,但是它还有更多能力!接下来你会了解npm是如何在应用的整个生命周期帮助你的-从创建一个项目到开发和部署整个生命周期 认识npm 在开始之前,我们先来看看一些查看正在运
推荐文章
1. 命令收集版本信息 # 创建数据收集脚本文件 OPER_FILE=${EXECUTE_ID}_oper.sh if [[ "${OPER_USER}" = "${USER}" ]]; then echo "${PATCH_HOME}/opatch lsinventory > ${MODULE_OU
推荐文章
JSP总结 静态网页 在网站设计中,纯粹HTML(标准通用标记语言下的一个应用)格式的网页通常被称为“静态网页”,静态网页
推荐文章
nodejs应用转换png,jpg,gif为webp图片格式
本博客列表缩略图在支持webp格式的浏览器下,使用的是webp格式图片,不支持webp图片下使用的是原图片(如png,gif,jpg等) webp使用指南,请参考 https://www.imqianduan.com/browser/webp.html 如何转换webp? google官方有推出工具cwebp用来转换webp,可
推荐文章
推荐文章
Spring Boot:使用默认开发配置来实现快速开发 Spring XD:用来简化大数据应用开发 Spring Cloud:为分布式系统开发提供工具集 Spring Data:对主流的关系型和nosql数据库的支持 Spring Integration:通过消息机制对企业集成模式(EIP)的支持 Spring
推荐文章
首先一定要下载好驱动文件。然后记得一定要先加载到项目中!驱动文件下载连接:已经有写好的数据库文件以及前端页面了 例如我的是mysql驱动。就将mysql-connector-java-5.1.38-bin.jar添加到webcontent的web-inf下的lib中就可以了~ 遵循固定代码格式,不必多说: 最基本必经步骤(de
推荐文章
经典的入门小游戏,这里用quick-cocos2d-x3.2重新写一遍,以便熟悉下quick 首先,创建工程,如果不会自行百度啊。 1、编译效果如下: 2、将游戏背景设置为白色,同时我们也来看一下MainScene.lua的文件 local MainScene = class("MainScene", function(
推荐文章
题目 将 0001 题生成的 200 个激活码(或者优惠券)保存到 Redis 非关系型数据库中。 解题思路 难点是压根不知道redis怎么用。好在找到了一些文章快速学了些: 使用python操作redis python: redis介绍及简单应用 python(十一)下:Redis安装配置及使用详解 安装redis包,就可以开始用了。
推荐文章
Bash Shell中的特殊位置变量及其应用 众所周知bash shell中有许多特殊的位置变量
推荐文章
一、命令的别名——(自定义命令) alias alias - 定义或显示别名。 格式:alias [-p] [名称[=值] ... ] 注意:如果alias命令不带任何选项和参数,则表示显示所有已经定义并生效的别名设置; unalias unalias - 从别名定义列表中删除每一个"名字"。 格式
推荐文章
BeautifulSoup模板简单应用-提取html指定数据(api_name/api_method/api_path,请求body/请求header/pagam参数)
from bs4 import BeautifulSoup import re import os.path import itertools name=‘newcrm‘ source_file_path=‘./‘+name+‘.html‘ def get_apiInfo(): with open(sourc
推荐文章
转自https://www.cnblogs.com/dj3839/p/6580765.html 锁的简单应用 用lock来保证原子性(this.count++这段代码称为临界区) 什么是原子性,就是不可分,从头执行到尾,不能被其他线程同时执行。 可通过CAS来实现原子操作 CAS(Compare and Swap): CAS