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

-

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--读取结构信息

-

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值