CTreeCtrl保存与读取(完整功能)

原创 2007年10月12日 14:32:00

-

CTreeCtrl树型控件的确是一个很复杂的控件 特别是在VC++6.0中 它基本上完全靠我们手动写代码来完成它的主要功能.无论新手老手 我相信 要重新写个对CTreeCtrl的操作 一定要看以前自己写的代码才能完成 因为它的操作并不是完全能记住的.

其中 对控件中所有节点的操作 是最主要的.遍历每个节点 取得信息 这是非常重要的 我有在.net中使用过树控件操作很是方便.这里我将我使用树控件的方法写下来 它虽然不完美 但很完整 完成了从新增到删除 到保存到读取的全部操作过程.它将保存的结果存于程序目录下的x.ini文件中 你可以打开它来查看保存的信息.这里不但保存了重新构造树结构的信息也保存了附加信息 可以自由修改.最重要的是 这个示例 能够支持树结构的任何操作 包括换顺序 增加 删除 这些操作不会影响任何节点的ID顺序.节点ID 也许或许需要重点说一下 它保存了你构造的树结构的节点顺序 这并不指序号顺序如果你另一个程序读取了这个结构 引用了序号为2的节点 然后你在程序中 在这个节点之前新增一个节点的话 这个节点的序号就变成3了等到另一个程序再读取的话 就变成引用3了.但在这个示例中 并不是根据序号保存的 而是另一个ID编号 你可以随意操作它的顺序 位置实际的ID并不会改变.


源代码下载

源码中已经有非常详细的注释 这里 我主要说下方法.
新增与删除都是非常简单的 唯一要说的是 新增的方法 我使用了取最小空值的方法 也就是 循环所有节点 取出没有值的序号 新增的节点就使用那个序号也就是说 如果你之前有4个节点 你删除了2号节点 你再新增的时候 ID就为2 而不是5.保存的方法与读取相关联 所以怎么保存决定了如何读取.保存的时候我使用了递归遍历所有节点 每个节点需要保存结构信息 以便以后读取重新构造树结构 否则 你保存为了文件如何能还原以前树的结构?
这里还保存了节点名称 节点序号 节点ID(重要).


保存从这里开始

    UINT fileSum=0;//列表总数
    int layer=1;//层次

    queryTreeNode(m_tree,m_tree.GetRootItem(),fileSum,layer);

    最后还要保存总数

    CString _str;
    _str.Format("%d",fileSum);
    WritePrivateProfileString("INFO","filesum",_str,appPathFile);

 


递归保存m_tree所有节点的操作
void   queryTreeNode(CTreeCtrl& m_tree,HTREEITEM   hTreeItem,UINT& fileSum,int& layer) 

    CString   strNode,_str,_id,_layer;  
    _str.Format("%d",1+fileSum++);
    strNode   =   m_tree.GetItemText(hTreeItem);
    _id.Format("%d",m_tree.GetItemData(hTreeItem));
    _layer.Format("%d",layer);
    WritePrivateProfileString("NODE"+_str,"name",strNode,appPathFile);//保存了节点名称
    WritePrivateProfileString("NODE"+_str,"index",_str,appPathFile);//保存了节点序号
    WritePrivateProfileString("NODE"+_str,"id",_id,appPathFile);//保存了节点编号ID
    WritePrivateProfileString("NODE"+_str,"layer",_layer,appPathFile);//保存了节点结构信息(层)
  
//--------------
    //获取子项
    HTREEITEM hFirstChild   =  m_tree. GetChildItem(hTreeItem);
    //如果子项不为空
    if(hFirstChild!=NULL) 
    {
        layer++;
        queryTreeNode(m_tree,hFirstChild,fileSum,layer);
        layer--;
    }
//--------------
    //获取兄项
    hFirstChild   =  m_tree. GetNextItem(hTreeItem,TVGN_NEXT);
    //如果兄项不为空
    if(hFirstChild!=NULL) 
        queryTreeNode(m_tree,hFirstChild,fileSum,layer); 


}


这是我所试验出最优的保存结构方法 速度与信息的全面性也算是较高的.

 

最存好了结构就像下面这样的 相信能看懂

[NODE1]
name=节点序号:1|节点编号ID:1
index=1
id=1
layer=1
[NODE2]
name=节点序号:2|节点编号ID:2
index=2
id=2
layer=2
[NODE3]
name=节点序号:6|节点编号ID:6
index=3
id=6
layer=3
[NODE4]
name=节点序号:7|节点编号ID:7
index=4
id=7
layer=4
[NODE5]
name=节点序号:3|节点编号ID:3
index=5
id=3
layer=2
[NODE6]
name=节点序号:5|节点编号ID:5
index=6
id=5
layer=3
[NODE7]
name=节点序号:8|节点编号ID:8
index=7
id=8
layer=3
[NODE8]
name=节点序号:4|节点编号ID:4
index=8
id=4
layer=2
[NODE9]
name=最后一个9编号
index=9
id=9
layer=2
[INFO]
filesum=9

 

 

然后就是读取了

 


    char buff[255];
    CString   _layer,strNode,_str;  
    int currLayer=0;//当前层
    int _id=0;
    HTREEITEM m_htreeItem=TVI_ROOT;

//------------------

    int _fileSum=GetPrivateProfileInt("INFO","filesum",NULL,appPathFile);

    for (int i=1;i<=_fileSum;i++)
    {
        _str.Format("%d",i);
        //取得节点信息
        _layer.Format("%d",i);
        GetPrivateProfileString("NODE"+_str,"layer",NULL,buff,256,appPathFile);      
        _layer=atoi(buff);
        GetPrivateProfileString("NODE"+_str,"name",NULL,buff,256,appPathFile);
        strNode=buff;
        //GetPrivateProfileString("NODE"+_str,"index",NULL,buff,256,appPathFile);
        GetPrivateProfileString("NODE"+_str,"id",NULL,buff,256,appPathFile);
        _id=atoi(buff);

 

        //如果在下层
        if (_layer>currLayer)
        {

            m_htreeItem = m_tree.InsertItem(strNode,0,1,m_htreeItem,TVI_LAST);
            m_tree.SetItemData(m_htreeItem,_id);//设置附加数据也就是编号

            currLayer++;
            //如果在同层
        }else if (_layer==currLayer)
        {

            m_htreeItem = m_tree.GetParentItem(m_htreeItem);      
            m_htreeItem = m_tree.InsertItem(strNode,0,1,m_htreeItem,TVI_LAST);
            m_tree.SetItemData(m_htreeItem,_id);//设置附加数据也就是编号

            //如果在上层
        }else if (_layer<currLayer)
        {
            //查找上层节点
            while(_layer!=currLayer)
            {
                m_htreeItem = m_tree.GetParentItem(m_htreeItem);
                currLayer--;
            }


            m_htreeItem =m_tree.GetParentItem(m_htreeItem);
            m_htreeItem=m_tree.InsertItem(strNode,0,1,m_htreeItem,TVI_LAST);
            m_tree.SetItemData(m_htreeItem,_id);//设置附加数据也就是编号

        }

      

    }
  

保存递归的思路应该是这样的 传递节点对象 如果为空 则表示没有节点 直接返回 如果有
1.则判断它接下来是否有子节点 如果有的话 再调用递归查找下面的子节点
2.然后子节点又判断有没有子子节点 如果有 则重覆上面的步骤 如果没有
3.则执行下面的判断是否有兄节点 如果有 则递归 重覆1步骤.
4.如果没有 则返回刚刚的调用 则再执行下面的3步骤判断兄节点
5.如果没有 返回上次调用


读取主要是依靠layer来实现的 先读取节点总数 然后进入循环 循环所有节点
1.从文件中读取第i个记录 然后判断这个记录的层是否大于当前的层(第一层总是0)所以一定大于 更新当前节点对象为新增对象
2.如果等于的话 则在当前节点对象的父节点对象上新增节点 这样 就是与当前节点为同一级了 再更新当前节点对象为新增对象
3.如果大于的话 则需要寻找到与之对应的层节点对象上 这里使用循环判断 然后再重覆2步骤.
4.完成一次判断 就返回再从1开始执行

 


最后还是要说下 下面这些信息 是我认为必要保存的 这才是一个能完成基本功能的结构
name--名称
index--序号(可以没有)
id--数据索引支持
layer--读取结构信息

-

CTreeCtrl项目的保存与读取

     VC++树控件是较为复杂的控件之一 也许读取它的项目相对来说比较容易 但保存它的结构信息再读取出来也许要花更多的时间.问题是如果保存结构信息?下面代码完全做到了这一点 可能算法有些笨笨 不知...
  • smallfishff
  • smallfishff
  • 2006-12-21 09:33:00
  • 1241

获取CTreeCtrl所有结点的附加数据(ItemData)

vector GetTreeCtrlAllNodeItemData(CTreeCtrl& _ctrl) { vector lstItmData; HTREEITEM hItem=_ctrl.Get...
  • Mr_warm
  • Mr_warm
  • 2016-10-17 16:21:53
  • 783

MFC树形控件(CTreeCtrl)用法(下)

前面一节讲了树形控件Tree Control的简介、通知消息以及相关数据结构,本节继续讲下半部分,包括树形控件的创建、CTreeCtrl类的主要成员函数和应用实例。        树形控件的...
  • wang15061955806
  • wang15061955806
  • 2016-07-04 13:51:14
  • 2428

动态创建控件保存与读取(VC++6.0)

-下载源码   VC++6.0中创建动态控件是比较偏离基础的知识 也有一定的难度.它的完整功能是要动态创建控件后再动态响应控件中的事件 两者全部做到才算完整.  这里 我将展示一个完整的动态控件示例 ...
  • smallfishff
  • smallfishff
  • 2007-11-14 15:15:00
  • 4442

用文件流的形式读写xml文件到MFC的树控件中

这是在工作时用到的问题,,,,主要就是通过读取xml中的一部分到树控件中,但是保存的时候必须是完整的、读取时的xml。 1,就是读取xml文件,成为文件流。 定义一个字符串,其大小就是你读取文件的...
  • qq_17070205
  • qq_17070205
  • 2015-08-06 12:29:22
  • 1077

mfc ctreectrl遍历所有节点

遍历节点,并取得节点文本: 其中  m_vecTreeNode是CDlgTree成员变量(vector  m_vecTreeNode),将所有节点文本保存。 由于使用多字符集,所以可以strTem...
  • XuePiaoFei1
  • XuePiaoFei1
  • 2015-07-27 23:20:32
  • 5668

MFC中树控件CTreeCtrl的用法

不错不错 原文地址:MFC中树控件CTreeCtrl的用法作者:hoarn 【转至】 http://hi.baidu.com/jjzhang166/home    树形控件可以用于树形...
  • gongluck93
  • gongluck93
  • 2016-09-21 09:22:32
  • 855

MFC学习之CTreeCtrl控件的使用

树状控件CTreeCtrl主要用于树状结构的功能使用,其中树状结构有一个根接点(Root),一个根接点下可以有多个子接点或者不设置子接点,子接点也可以作为父节点,使其下也包含若干的子接点,总是可以根据...
  • haitunxiaomo
  • haitunxiaomo
  • 2014-04-28 23:42:47
  • 3247

CTreeCtrl变量的遍历

树是一种十分重要的数据结构。在程序设计中,我们经常用树来组织数据。对于树的遍历也是一种常规的运算,下面提供了两个算法。前面一个只是简单的遍历了所有的结点,后面一个则可以根据传入条件返回相应的结点。 ...
  • woddle
  • woddle
  • 2014-06-10 17:43:57
  • 1045

一步一步教你实现CTreeCtrl 自绘

一步一步教你实现CTreeCtrl 自绘   -------BY wojiushi3344    QQ:513670524  转载请说明出处                源代码下载     最近因工...
  • wojiushi3344
  • wojiushi3344
  • 2012-04-15 22:31:10
  • 16449
收藏助手
不良信息举报
您举报文章:CTreeCtrl保存与读取(完整功能)
举报原因:
原因补充:

(最多只允许输入30个字)