本文实现了下面的功能:

  1. 当选中父节点时, 其所有子节点全部选中.
  2. 当取消选中父节点时, 其所以子节点全部取消选中.
  3. 点击子节点时, 根据子节点与其兄弟节点的选中状态, 自动设置父节点的选中状态.

通过继承CTreeCtrl实现, 代码如下(注释已经写得很清楚了):

CustomTreeCtrl.h


  1. #pragma once
  2. // CCustomTreeCtrl
  3. class CCustomTreeCtrl : public CTreeCtrl
  4. {
  5. DECLARE_DYNAMIC(CCustomTreeCtrl)
  6. public:
  7. CCustomTreeCtrl();
  8. virtual ~CCustomTreeCtrl();
  9. private:
  10. // 设置子结点选中状态
  11. void SetChildCheck(HTREEITEM hItem, BOOL bCheck);
  12. // 设置父结点选中状态
  13. void SetParentCheck(HTREEITEM hItem);
  14. // 自定义消息处理
  15. afx_msg LRESULT OnUserMsg(WPARAM wParam, LPARAM lParam);
  16. protected:
  17. DECLARE_MESSAGE_MAP()
  18. public:
  19. afx_msg void OnNMClick(NMHDR *pNMHDR, LRESULT *pResult);
  20. };

CustomTreeCtrl.cpp


  1. // CustomTreeCtrl.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "CustomTreeCtrl.h"
  5. #define UM_CHANGE_PARENT_CHECK_STATUS (WM_USER+1011)
  6. // CCustomTreeCtrl
  7. IMPLEMENT_DYNAMIC(CCustomTreeCtrl, CTreeCtrl)
  8. CCustomTreeCtrl::CCustomTreeCtrl()
  9. {
  10. }
  11. CCustomTreeCtrl::~CCustomTreeCtrl()
  12. {
  13. }
  14. BEGIN_MESSAGE_MAP(CCustomTreeCtrl, CTreeCtrl)
  15. ON_NOTIFY_REFLECT(NM_CLICK, &CCustomTreeCtrl::OnNMClick)
  16. ON_MESSAGE(UM_CHANGE_PARENT_CHECK_STATUS, &CCustomTreeCtrl::OnUserMsg)
  17. END_MESSAGE_MAP()
  18. // CCustomTreeCtrl message handlers
  19. void CCustomTreeCtrl::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
  20. {
  21. // 获取点击坐标
  22. CPoint pt;
  23. ::GetCursorPos(&pt);
  24. ::ScreenToClient(m_hWnd, &pt);
  25. UINT nFlags = 0;
  26. HTREEITEM hItem = HitTest(pt, &nFlags);
  27. if (hItem)
  28. {
  29. // 选中当前结点
  30. this->SelectItem(hItem);
  31. // 如果是点击的CheckBox
  32. if (TVHT_ONITEMSTATEICON == (nFlags & TVHT_ONITEMSTATEICON))
  33. {
  34. // 获取当前选中状态(点击完成后的状态相反)
  35. BOOL bChecked = GetCheck(hItem);
  36. // 设置子结点选中状态
  37. SetChildCheck(hItem, !bChecked);
  38. // 设置父结点的状态
  39. // 由于是当前点击的状态,而不是点击后的状态, 还未更新, 所以通过消息来设置
  40. ::PostMessage(m_hWnd, UM_CHANGE_PARENT_CHECK_STATUS, (WPARAM)hItem, 0);
  41. }
  42. }
  43. *pResult = 0;
  44. }
  45. // 设置子结点选中状态
  46. void CCustomTreeCtrl::SetChildCheck(HTREEITEM hItem, BOOL bCheck)
  47. {
  48. // 得到子结点
  49. HTREEITEM hChildItem = GetChildItem(hItem);
  50. while (hChildItem != NULL)
  51. {
  52. // 设置子结点选中状态
  53. SetCheck(hChildItem, bCheck);
  54. // 递归遍历孩子节点
  55. SetChildCheck(hChildItem, bCheck);
  56. // 对兄弟结点进行遍历
  57. hChildItem = GetNextItem(hChildItem, TVGN_NEXT);
  58. }
  59. }
  60. // 设置父结点选中状态
  61. void CCustomTreeCtrl::SetParentCheck(HTREEITEM hItem)
  62. {
  63. // 得到父节点
  64. HTREEITEM hParent = GetParentItem(hItem);
  65. if (NULL != hParent)
  66. {
  67. // 记录父结点的状态
  68. BOOL bParentIsChecked = TRUE;
  69. // 检查父结点的所有子结点
  70. HTREEITEM hChild = GetNextItem(hParent, TVGN_CHILD);
  71. while (hChild)
  72. {
  73. // 如有任一子结点为非选中状态, 父节点不满足全选条件,置为unchecked
  74. if (!GetCheck(hChild))
  75. {
  76. bParentIsChecked = FALSE;
  77. break;
  78. }
  79. hChild = GetNextSiblingItem(hChild);
  80. }
  81. // 设置父结点的状态
  82. SetCheck(hParent, bParentIsChecked);
  83. // 递归检查父节点
  84. SetParentCheck(hParent);
  85. }
  86. }
  87. // 自定义消息处理
  88. LRESULT CCustomTreeCtrl::OnUserMsg(WPARAM wParam, LPARAM lParam)
  89. {
  90. HTREEITEM hItem = (HTREEITEM)(wParam);
  91. if (hItem)
  92. {
  93. SetParentCheck(hItem);
  94. }
  95. return 0L;
  96. }

使用例子


  1. // 定义
  2. CCustomTreeCtrl m_wndTreeCtrl;
  3. BOOL CTreeCtrlTest::OnInitDialog()
  4. {
  5. CDialogEx::OnInitDialog();
  6. CRect rc;
  7. GetClientRect(&rc);
  8. // 在父/子结点之间绘制连线, 在根/子结点之间绘制连线, 在失去焦点时也显示当前选中的结点, 状态选择框, 在每一个结点前添加一个按钮用于表示当前结点是否已被展开
  9. m_wndTreeCtrl.Create(WS_CHILD | WS_VISIBLE | TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | TVS_CHECKBOXES | TVS_HASBUTTONS, rc, this, 123333);
  10. for (size_t i = 0; i < 3; i++)
  11. {
  12. CString strRoot;
  13. if (0 == i)
  14. {
  15. strRoot = _T("AA");
  16. }
  17. else if (1 == i)
  18. {
  19. strRoot = _T("BB");
  20. }
  21. else
  22. {
  23. strRoot = _T("CC");
  24. }
  25. HTREEITEM hRoot = m_wndTreeCtrl.InsertItem(strRoot);
  26. for (int j = 0; j < 5; j++)
  27. {
  28. CString strChild;
  29. strChild.Format(_T("%s_%02d"), strRoot.GetBuffer(), j);
  30. HTREEITEM hChild = m_wndTreeCtrl.InsertItem(strChild, hRoot);
  31. for (int k = 200; k < 210; k++)
  32. {
  33. CString strCSubChild;
  34. strCSubChild.Format(_T("%s_%03d"), strChild.GetBuffer(), k);
  35. HTREEITEM hSubChild = m_wndTreeCtrl.InsertItem(strCSubChild, hChild);
  36. }
  37. }
  38. }
  39. return TRUE; // return TRUE unless you set the focus to a control
  40. // EXCEPTION: OCX Property Pages should return FALSE
  41. }

实现CTreeCtrl父子节点的联动选择的更多相关文章

  1. 7.Android开源项目WheelView的时间和地址联动选择对话框

    类似WheelView的时间和地址联动选择对话框在现在App经常看到,今天小结下. 主布局界面: <LinearLayout xmlns:android="http://schemas ...

  2. Devexpress TreeList控件绑定显示父子节点对像

    今天一位同事咨询Devexpress TreeList控件绑定自动显示父子节点对像,但结果是不会显示带父子节点关系,而是将所有的节点作为父节点显示出来了,对像类的代码如下 public class I ...

  3. [js开源组件开发]js手机联动选择地区仿ios 开源git

    js手机联动选择地区 前言:由于网上找到了一个mobiscrool,比较全,但是不开源,只能试用15天,正式版竟然要三千块钱,穷人只能自己动手,写了个只针对弹窗地区选择的. 本站点所有的资源均在git ...

  4. [js开源组件开发]js手机联动选择日期 开源git

    js手机联动选择日期 这里在前面的<js手机联动选择地区>的基础上,改造数据源之后形成的一个日期的选择器,当然你可以使用之前的PC上模式的<日期控件>,它同时也支持手机端,ht ...

  5. 4个好用的JS联动选择插件

    jQuery City Select 一个简单的jQuery省市联动插件,可以自定义JSON字典实现其他内容的联动选择菜单. PCAS省.市.地区联动选择JS封装类 PCAS可能是国内使用人数最多的J ...

  6. JQUERY省、市、县城市联动选择

    JQUERY 插件开发——CITYLINKAGE(省.市.县城市联动选择) 第一部分:背景   开发源于需求,本次城市联动选择插件算是我写插件的一个特例吧,不是我目前工作需要些的,算是兴趣驱使吧.之前 ...

  7. Android学习小Demo(21)ListView的联动选择

    在日常的App开发中,尤其是在开发生活服务的应用上,非常多时候,我们会须要联动地展现省市区的数据等,需求大概例如以下: 1)展现全部省份 2)当点击某省份的时候,在二级菜单上展现此省份以下所属的城市列 ...

  8. ASP.NET MVC页面UI之联动下拉选择控件(省、市、县联动选择)

    地区选择操作在WEB应用中比较常见的操作,本文在.net mvc3下实现了省市县三级联动选择功能. 本文博客出处:http://www.kwstu.com/ArticleView/admin_2013 ...

  9. easyui Tree模拟级联勾选cascadeCheck,节点选择,父节点自动选中,节点取消,父节点自动取消选择,节点选择,所有子节点全部选择,节点取消,所有子节点全部取消勾选

    最近项目中用到easyui tree,发现tree控件的cascadeCheck有些坑,不像miniui 的tree控件,级联勾选符合业务需求,所以就自己重新改写了onCheck事件,符合业务需求.网 ...

随机推荐

  1. springmvc json 406

    spring 4.0 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="ht ...

  2. 数组filter()参数详解,巧用filter()数组去重

    数组方法挺多,但是用来用去可能也就foreach,splice以及slice接触较多,filter()说实话之前也没过多了解.其实filter()为数组提供过滤功能,它会遍历数组所有元素,并返回满足条 ...

  3. 百度全站 https FAQ:技术宅告诉你如何搜索更安全

    百度从 14 年开始对外开放了 https 的访问,并于 3 月初正式对全网用户进行了 https 跳转. 你也许会问,切换就切换呗,和我有啥关系?我平常用百度还不是照常顺顺当当的,没感觉到什么切换. ...

  4. 开源方案搭建可离线的精美矢量切片地图服务-5.Mapbox离线项目实现

    项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵). 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.ht ...

  5. 状态压缩·一(状态压缩DP)

    描述 小Hi和小Ho在兑换到了喜欢的奖品之后,便继续起了他们的美国之行,思来想去,他们决定乘坐火车前往下一座城市——那座城市即将举行美食节! 但是不幸的是,小Hi和小Ho并没有能够买到很好的火车票—— ...

  6. 并发编程之 Fork-Join 分而治之框架

    前言 "分而治之" 一直是一个有效的处理大量数据的方法.著名的 MapReduce 也是采取了分而治之的思想.简单来说,就是如果你要处理1000个数据,但是你并不具备处理1000个 ...

  7. Eclipse 4.3 Kepler最快汉化方法

    eclipse 4.3汉化 eclipse 4.3 ---kepler已经于2013年6月26日发布主要版本,详见:eclipse in wikipedia   1.上eclipse官网:http:/ ...

  8. C++标准模板库STL

    STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称.现然主要出现在C++中,但在被引入C++之前该技术就已经存在了很长的一段时间. STL的代码 ...

  9. SQL - 先安装SQL2008 R2后安装AD导致无法正常登陆数据库(无法启动MSSQLSERVER)

    分析原因:安装AD后,系统改为使用域用户登陆,原先安装SQL时设置的“本地用户”信息已经修改,当前(域)用户没有权限访问MSSQLSERVER实例文件夹或整个SQL文件夹. 解决方法: 1.打开“服务 ...

  10. [android] 手机卫士输入框抖动和手机震动

    查看apiDemos,找到View/Animation/shake找到对应的动画代码,直接拷贝过来 当导入一个项目的时候,报R文件不存在,很多情况是xml文件出错了 Animation shake = ...