C++ N 叉树在 CLI 中的应用

这段代码展示了C++中实现的二叉树和N叉树类,包括节点数据结构、内存管理、文件保存和读取功能。类中包含了节点的键值、二进制数据、文本显示信息以及颜色和字体设置。此外,还有针对树的查找、添加、删除节点的方法,以及与WindowsFormsTreeView控件交互的函数。
摘要由CSDN通过智能技术生成

应用:

 

 

 _Tree.h

/*******************************************************************************************
文件名							: _Tree.h

作者								: 李锋

功能								: 树型数据结构

创建时间							: 2016年07月31日

最后一次修改时间				    :  2023年01月01日
********************************************************************************************/
#ifndef __TREE_H_
#define __TREE_H_

#ifdef _CLR_
    using namespace System::Windows::Forms;
#endif


#include "_List.h"
#include "_Color.h"
#include "_Font.h"
#include "_DataType.h"
#include "_KeyBinaryFile.h"

#define  _NTREENODE_DEBUG_
//#define _NTREE_DEBUG_

_LF_BEGIN_


/// <summary>
/// 二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,
/// 而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个节点最多只能有两棵子树,且有左右之分 [1]  。二叉树是n个
/// 有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合
/// 为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个节点
/// </summary>
class _BTreeNode : public _Object
{
public:

    /// <summary>
    /// 键值,在所有节点中都是唯一的
    /// </summary>
    __int64 KeyValue;


    /// <summary>
    /// 所带的二进制数据
    /// </summary>
    _ByteArray Data;


    /// <summary>
    /// 所带的二进制数据类型
    /// </summary>
    _DataType  DataType;


    /// <summary>
    /// 在树型控件中显示的文本
    /// </summary>
    _string DispalyText;


    /// <summary>
    /// 在树型控件中显示文本的字体颜色
    /// </summary>
    _Color DisplayForeColor;

    /// <summary>
    /// 在树型控件中显示显示文本的背景颜色
    /// </summary>
    _Color DisplayBackColor;


    /// <summary>
    /// 在树型控件中显示显示的字体
    /// </summary>
    _Font DispalyFont;


    __int64 LeftKeyValue;
    __int64 RightKeyValue;

    _BTreeNode* Left;
    _BTreeNode* Right;

};




class _BTree
{
private:
    _BTreeNode  _root;


};




/// <summary>
/// N叉树
/// </summary>
class _NTreeNode : public _Object
{
private:

    void InitData(const _string& sDispalyText = _t(""));

public:
    /// <summary>
    /// 分隔字符串
    /// </summary>
    static const _string SplitString;

public:
    /// <summary>
   /// 键值,在所有节点中都是唯一的
   /// </summary>
    __int64 KeyValue;


    /// <summary>
    /// 所带的二进制数据
    /// </summary>
    _ByteArray Data;
     

    /// <summary>
    /// 在树型控件中显示的文本
    /// </summary>
    _string DispalyText;


    /// <summary>
    /// 在树型控件中显示文本的字体颜色
    /// </summary>
    _Color DisplayForeColor;

    /// <summary>
    /// 在树型控件中显示显示文本的背景颜色
    /// </summary>
    _Color DisplayBackColor;


    /// <summary>
    /// 在树型控件中显示显示的字体
    /// </summary>
    _Font DispalyFont;


    /// <summary>
    /// 第一个子结点键值
    /// </summary>
    __int64 FirstChildKeyValue;
     
    /// <summary>
    /// 下一个兄弟结点键值
    /// </summary>
    __int64 NextSiblingKeyValue;



    /// <summary>
    /// 所带的二进制数据类型
    /// </summary>
    _DataType  DataType;

public:

    /// <summary>
    /// 第一个子结点
    /// </summary>
    _NTreeNode* FirstChild;

    /// <summary>
    /// 下一个兄弟结点
    /// </summary>
    _NTreeNode* NextSibling;

public:



    /// <summary>
    /// 判断 tnChild 是否 tnParent 的直系子结点,如果是,则返回 true
    /// </summary>
    /// <param name="tnChild"></param>
    /// <returns></returns>
    /// 创建时间:2022-07-18 最后一次修改时间:2022-07-18
    bool IsMyChild(const _NTreeNode* pChild);



    /// <summary>
    /// 判断 tnChild 是否父结点,如果是,则返回 true
    /// </summary>
    /// <param name="tnParent">父结点</param>
    /// <returns></returns>
    /// 创建时间:2022-07-18 最后一次修改时间:2022-07-18
    bool IsMyParent(const _NTreeNode* pParent);

public:


    _NTreeNode();
    _NTreeNode(const _string sDisplayText);

    _NTreeNode(const _NTreeNode&  Node);



    _string GetPackageDataAdd(const bool& IsOldVersion)const;


    /// <summary>
    /// 把其他八种数据打包进 Data 数据中
    /// </summary>
    /// <param name="IsOldVersion"></param>
    _ByteArray& PackageData(_ByteArray& baResult, const bool& IsOldVersion);

    /// <summary>
    /// 分拆打包后的数据
    /// </summary>
    /// <param name="IsOldVersion"></param>
    void SplitData(const bool &IsOldVersion);
};



/// <summary>
/// N叉树,此N叉树要求有且只有一个根节点
/// </summary>
class _NTree : public _Object
{
private:

    //固定名子,原来用控件名子,但是一旦控件名字更改,就是个bug,文件打不开了。
    static const _string ConstName;

private:
    /// <summary>
    /// 根节点
    /// </summary>
    _NTreeNode* _Root = null;

    /// <summary>
    /// 节点数
    /// </summary>
    int  _Count; 

     

    /// <summary>
    /// 当前操作的文件名
    /// </summary>
    _string _FullPathName = _t("");
 
private:
    int _DeleteSolitaryNode(const _NTreeNode* pDelete);
    void _GetNodeChildrenAll(const  _NTreeNode* pParent, _DList<_NTreeNode*>& dResult)const;


public:  //--------------------------------------------------------------属性

    /// <summary>
    /// 设置文件名
    /// </summary>
    /// <param name="sFullPathName"></param>
    inline void SetFullPathName(const _string& sFullPathName) { _FullPathName = sFullPathName; }

    /// <summary>
    /// 获取文件名
    /// </summary>
    /// <returns></returns>
    inline const _string& GetFullPathName()const { return _FullPathName; }

    /// <summary>
    /// 返回结点数
    /// </summary>
    /// <returns></returns>
    inline int Count() const { return _Count; }


    /// <summary>
    /// 返回根节点
    /// </summary>
    /// <returns></returns>
    inline  _NTreeNode* Root()const { return _Root; }
     
    /// <summary>
    /// 文件内容是否更改
    /// </summary>
    bool IsModify = false;

public:
    /// <summary>
    /// 清空内存
    /// </summary>
    /// <param name="pNode"></param>
    void ClearMemory();


    inline ~_NTree() {
#ifdef _NTREE_DEBUG_
        d.PrintError(_t("inline ~_NTree()"));
#endif
        ClearMemory(); 
    }


    inline _NTree() { 
#ifdef _NTREE_DEBUG_
        d.PrintError(_t("inline _NTree()"));
#endif
        _Count = 0;
        _Root = null; 
    }     

public:
    void _FindNode(const  _NTreeNode* pFindStart, const _NTreeNode* pNode, _DList<const _NTreeNode*>& dResult);
    _DList<_NTreeNode*> GetNodeAll() const;

public:

    _NTreeNode* FindIsFirstChild(const _NTreeNode* pFindStart, const _NTreeNode* pFind); 
    _NTreeNode* FindPrent(const _NTreeNode* pStart, const _NTreeNode* pChild);  
    _NTreeNode* FindPrevSibling(const _NTreeNode* pStart, const _NTreeNode* pNode);    
    _NTreeNode* GetLastSibling(const _NTreeNode* pFirstSibling);
    _DList<const _NTreeNode*> FindNode(const _NTreeNode* pNode);
    _NTreeNode* AddNode(_NTreeNode* pParent, const _NTreeNode* pNode);
    _NTreeNode* AddNode(_NTreeNode* pParent, const _string& sDisplayText);
 
 

    bool RemoveNode(const _NTreeNode* pRemove);


    _string BuildInFile(const _string& sFullPathName);


  
    _NTreeNode* Find(const _DList<_NTreeNode*>& tnList, const __int64& iKeyValue)const;
    _NTreeNode* Find(const _DList<_NTreeNode*>& tnList, const _string& sKeyValue)const;

    _NTreeNode* Find(const _NTreeNode* tnFindStart, const __int64& iKeyValue)const;
    _NTreeNode* Find(const _NTreeNode* tnFindStart, const _string& sKeyValue)const;

    void SaveSiblingAndChild(_NTreeNode* pNode, _KeyBinaryFile& kbf);
     
    inline _NTreeNode* FindKeyValue(const _string &sKeyValue) { return Find(_Root, sKeyValue.ToInt64()); }


    /// <summary>
    /// 以 char 表示的二进制数据
    /// </summary>
    /// <returns></returns>
    _StrA GetFirstNodeDataA()const;

    /// <summary>
    /// 以 wchar 表示的二进制数据
    /// </summary>
    /// <returns></returns>
    _StrW GetFirstNodeDataW()const;

    /// <summary>
    /// 以 char 表示的二进制数据
    /// </summary>
    /// <returns></returns>
    void SetFirstNodeData(const _StrA&sData);
 
    void Display()const;
    void Display(const _NTreeNode* pNode,const int nLevel = 1)const;

#if _CLR_
     

    void BuildInTreeView(TreeView^ tv, TreeNode^ tnParent, const _NTreeNode* pNode, int nImageIndex);
    void BuildInTreeView(TreeView^ tv,const int iImageIndex = -1);

    _StrW GetTreeNodeDataW(TreeNode^ tn);
    _StrA GetTreeNodeDataA(TreeNode^ tn);

    void Save(TreeView^ tv, const _string& sFullPathName, bool bReWrite = false);

    inline void Save(TreeView^ tv) { Save(tv, _FullPathName, true); }
 

    void AfterLabelEdit_Event(Object^ sender, NodeLabelEditEventArgs^ e);

 
    void UpdateTreeViewNode(TreeView^ tv, TreeNode^ tnModify, String^ sDispalyText = _t(""));

    void TreeViewSelectedNodeDelete(TreeView^ tv);
 
    void TreeViewSelectedNodeAddNewNode(TreeView^ tv, String^ sDisplayText = _t("新节点"));
     
    void ChangeSelectedNodeData(TreeView^ tv, String^ sData);
 

 
    void AfterLabelEdit_Event(TreeView^ tv, Object^ sender, NodeLabelEditEventArgs^ e);

    void TreeViewNodeAttributeChange(TreeNode^ tnNode);

    void ItemDrag_Event(TreeView^ tv, Object^ sender, ItemDragEventArgs^ e);

    void DragDrop_Event(TreeView^ tv, Object^ sender, DragEventArgs^ e);
 
    void DragEnter_Event(TreeView^tv, Object^ sender, DragEventArgs^ e);

    _NTreeNode* GetinitTreeViewTreeNode(TreeView^tv, String^ sText);
 
    TreeNode^ TreeViewAddRootNode(TreeView^ tv, String^ sText);
  
    String^ TreeViewSelectNodeMoveUp(TreeView^ tv);

 
    String^ TreeViewSelectNodeMoveDown(TreeView^ tv);
 
 
#endif
 
};
 

 
/// <summary>
/// 数据树
/// </summary>
class _TreeViewData : public _Object
{

};


_LF_END_

 





#endif // !_LF_LTREE_H_

Tree.cpp

#include "_Tree.h"
#include "global_c_all.h"

_LF_BEGIN_


const _string _NTreeNode::SplitString = _t("||||");

 

void _NTreeNode::InitData(const _string& sDispalyText)
{

#ifdef _NTREENODE_DEBUG_
    //_cout << _t("void _NTreeNode::InitData(const _string& sDispalyText)\n");
#endif

    KeyValue = _DataTime::GetTimeStamp(); //键值,在所有节点中都是唯一的

    //Data  //所带的二进制数据

    DataType = _DataType::dtWChar; // 所带的二进制数据类型

    DispalyText = _t("新节点");//在树型控件中显示的文本

    DisplayForeColor = _Color::Black; //在树型控件中显示文本的字体颜色

    DisplayBackColor = _Color::White; //在树型控件中显示显示文本的背景颜色

    DispalyFont = _Font();  //在树型控件中显示显示的字体

    FirstChildKeyValue = -1;  //第一个子结点键值

    FirstChild = null;  //第一个子结点

    NextSiblingKeyValue = -1;  //下一个兄弟结点键值

    NextSibling = null;      //下一个兄弟结点
}

_NTreeNode::_NTreeNode()
{
    InitData();

}

_NTreeNode::_NTreeNode(const _string sDisplayText)
{
    InitData();
    DispalyText = sDisplayText;
}


_NTreeNode::_NTreeNode(const _NTreeNode& Node)
{  
    KeyValue = Node.KeyValue; //键值,在所有节点中都是唯一的

    Data = Node.Data; //所带的二进制数据

    DataType = Node.DataType;// 所带的二进制数据类型

    DispalyText = Node.DispalyText;//在树型控件中显示的文本

    DisplayForeColor = Node.DisplayForeColor;//在树型控件中显示文本的字体颜色

    DisplayBackColor = Node.DisplayBackColor;//在树型控件中显示显示文本的背景颜色

    DispalyFont = Node.DispalyFont;//在树型控件中显示显示的字体

    FirstChildKeyValue = Node.FirstChildKeyValue;//第一个子结点键值

    FirstChild = Node.FirstChild;//第一个子结点

    NextSiblingKeyValue = Node.NextSiblingKeyValue;//下一个兄弟结点键值

    NextSibling = Node.NextSibling;//下一个兄弟结点
}

_string _NTreeNode::GetPackageDataAdd(const bool& IsOldVersion) const
{
    if (IsOldVersion)  //旧版本在磁盘中保存 7 + 1(Data) 个字段
    {
#if _CLR_
        //Data |||| KeyValue |||| FirstChildKeyValue |||| NextSiblingKeyValue ||||  DispalyText |||| DisplayForeColor |||| DisplayBackColor |||| DispalyFont + ||||  Length 

        // Length  = |||| KeyValue |||| FirstChildKeyValue |||| NextSiblingKeyValue ||||  DispalyText |||| DisplayForeColor |||| DisplayBackColor |||| DispalyFont + ||||



        if (KeyValue == -1 || DispalyText.Length == 0 || DispalyText == _t("") )
            throw gcnew Exception(L"KeyValue == -1 || DispalyText == null ||  DispalyText == "" || DispalyFont == null");

        _string sAdd(_t(""), 1000);

        sAdd.Add(SplitString);
        sAdd.Add(KeyValue.ToString());
        sAdd.Add(SplitString);
        sAdd.Add(FirstChildKeyValue.ToString());
        sAdd.Add(SplitString);
        sAdd.Add(NextSiblingKeyValue.ToString());
        sAdd.Add(SplitString);
        sAdd.Add(DispalyText);
        sAdd.Add(SplitString);


        System::Drawing::ColorConverter^ cc = gcnew System::Drawing::ColorConverter();
        String^ tmp = cc->ConvertToString((Color)DisplayForeColor);
        sAdd.Add(tmp);
        sAdd.Add(SplitString);


        tmp = cc->ConvertToString((Color)DisplayBackColor);
        sAdd.Add(tmp);
        sAdd.Add(SplitString);


        System::Drawing::FontConverter^ fc = gcnew System::Drawing::FontConverter();
        tmp = fc->ConvertToString(DispalyFont);
        sAdd.Add(tmp);
        sAdd.Add(SplitString);



        sAdd.Add(sAdd.Length.ToString());

        return sAdd;        
#else
        d.PrintError(_t("_string _NTreeNode::GetPackageDataAdd(const bool& IsOldVersion) const: 代码未完成!"));
#endif
    }
    else //新版本在磁盘中保存 8 + 1(Data) 个字段 , 个了一个 DataType
    {
        /*
        //Data |||| KeyValue |||| FirstChildKeyValue |||| NextSiblingKeyValue ||||  DispalyText |||| DisplayForeColor |||| DisplayBackColor |||| DispalyFont + |||| + DataType + |||| + Length 

        // Length  = |||| KeyValue |||| FirstChildKeyValue |||| NextSiblingKeyValue ||||  DispalyText |||| DisplayForeColor |||| DisplayBackColor |||| DispalyFont + |||| DataType + ||||

        if (KeyValue == -1 || DispalyText == null || DispalyText == _t("") )
            throw gcnew Exception(L"KeyValue == -1 || DispalyText == null ||  DispalyText == "" || DispalyFont == null");

        _string sAdd(_t(""), 1000);

        sAdd.Add(SplitString);
        sAdd.Add(KeyValue.ToString());
        sAdd.Add(SplitString);
        sAdd.Add(FirstChildKeyValue.ToString());
        sAdd.Add(SplitString);
        sAdd.Add(NextSiblingKeyValue.ToString());
        sAdd.Add(SplitString);
        sAdd.Add(DispalyText);
        sAdd.Add(SplitString);


        System::Drawing::ColorConverter^ cc = gcnew System::Drawing::ColorConverter();
        String^ tmp = cc->ConvertToString((Color)DisplayForeColor);
        sAdd.Add(tmp);
        sAdd.Add(SplitString);


        tmp = cc->ConvertToString((Color)DisplayBackColor);
        sAdd.Add(tmp);
        sAdd.Add(SplitString);


        System::Drawing::FontConverter^ fc = gcnew System::Drawing::FontConverter();
        tmp = fc->ConvertToString(DispalyFont);
        sAdd.Add(tmp);
        sAdd.Add(SplitString);
         

        tmp = ((int)DataType).ToString();
        sAdd.Add(tmp);
        sAdd.Add(SplitString);


        sAdd.Add(sAdd.Length.ToString());

        return sAdd;

        */

        d.PrintError(_t("_string _NTreeNode::GetPackageDataAdd(const bool& IsOldVersion) const: 代码未完成!"));
    }


    return _t("");

}



/// <summary>
/// 把其他八种数据打包进 Data 数据中
/// </summary>
/// <param name="IsOldVersion"></param>
/// 创建时间:????-??-?? 最后一次修改时间:2023-01-04
_ByteArray& _NTreeNode::PackageData(_ByteArray &baResult, const bool& IsOldVersion)
{
    baResult.ClearMemory();

    if (IsOldVersion)
    {
        baResult.Add(Data);

        _string s = GetPackageDataAdd(IsOldVersion);
         
        baResult.Add((_byte*)s.Data, s.Length * sizeof(_char));
    }
    else
    {

        //打包九个字段


        _ByteArray  baTemp;

        //Data.Length +  Data 
        //KeyValue 
        //FirstChildKeyValue 
        //NextSiblingKeyValue  
        //DispalyText  
        //DisplayForeColor  
        //DisplayBackColor 
        //DispalyFont 
        //DataType  

        //------------------------------------------Data
        baResult.SetBuffer(Data.Length + 200);
 

        baResult.AddInt(Data.Length);
        baResult.Add(Data.Data, Data.Length);

        //---------------------------------------KeyValue
        baResult.AddInt64(KeyValue);

        //---------------------------------------FirstChildKeyValue
        baResult.AddInt64(FirstChildKeyValue);

        //---------------------------------------NextSiblingKeyValue
        baResult.AddInt64(NextSiblingKeyValue);

        //---------------------------------------DispalyText
        baResult.AddInt(DispalyText.DataMemoryLength);
        baResult.Add((_byte*)DispalyText.Data,DispalyText.DataMemoryLength);

        //---------------------------------------DisplayForeColor
        baResult.AddInt(DisplayForeColor.PackageMemory(baTemp).Length);
        baResult.Add(baTemp.Data, baTemp.Length);

        //---------------------------------------DisplayBackColor
        baResult.AddInt(DisplayBackColor.PackageMemory(baTemp).Length);
        baResult.Add(baTemp.Data, baTemp.Length);
       
        //---------------------------------------DispalyFont
        baResult.AddInt(DispalyFont.PackageMemory(baTemp).Length);
        baResult.Add(baTemp.Data, baTemp.Length);

        //---------------------------------------DataType
        baResult.AddInt((int)DataType);        
         
    }

    return baResult;
}



/// <summary>
/// 分拆打包后的数据
/// </summary>
/// <param name="IsOldVersion"></param>
/// 创建时间:????-??-?? 最后一次修改时间:2023-01-04
void _NTreeNode::SplitData(const bool& IsOldVersion)
{ 
    if (IsOldVersion)//旧版本在磁盘中保存 7 + 1(Data) 个字段
    {
#if _CLR_
        //Data |||| KeyValue |||| FirstChildKeyValue |||| NextSiblingKeyValue ||||  DispalyText |||| DisplayForeColor |||| DisplayBackColor |||| DispalyFont + ||||  Length 

        // Length  = |||| KeyValue |||| FirstChildKeyValue |||| NextSiblingKeyValue ||||  DispalyText |||| DisplayForeColor |||| DisplayBackColor |||| DispalyFont + ||||

        _string NewData = _t("");

        //_string tmp(_t(""), Data.Length);
        //tmp.Add((_char*)Data.Data, Data.Length / sizeof(_char));

        _string tmp;
        tmp.TrusteeshipMem(Data.Data, Data.MemoryLength);
        Data.GiveUpMem();
         


        int nLengthStart = tmp.LastIndexOf(SplitString);

        if (nLengthStart == -1)
            throw gcnew Exception("nLengthStart = -1");


        _string sLength = tmp.SubStr(nLengthStart + SplitString.Length, tmp.Length - nLengthStart - SplitString.Length);

        
        if (!sLength.IsArabicDigitString())
            throw gcnew Exception("!sLength->isNumberString()");


        int nAttribute = System::Convert::ToInt32(sLength);


        NewData = tmp.SubStr(0, tmp.Length - nAttribute - sLength.Length);


        _string sAttribute = tmp.SubStr(NewData.Length + SplitString.Length, nAttribute - SplitString.Length - SplitString.Length);

        _StringList ls(sAttribute, SplitString, false);


        if (ls.Count != 7)
            throw gcnew Exception( _t("sAttribute = ") + sAttribute + "分隔sAttribute错误, ls->Count != 7");


        KeyValue = System::Convert::ToInt64(ls[0]);

        FirstChildKeyValue = System::Convert::ToInt64(ls[1]);

        NextSiblingKeyValue = System::Convert::ToInt64(ls[2]);

        DispalyText = ls[3];

        System::Drawing::ColorConverter^ cc = gcnew System::Drawing::ColorConverter();
        DisplayForeColor = (System::Drawing::Color)cc->ConvertFromString(ls[4]);
        DisplayBackColor = (System::Drawing::Color)cc->ConvertFromString(ls[5]);


        System::Drawing::FontConverter^ fc = gcnew System::Drawing::FontConverter();
        DispalyFont = (System::Drawing::Font^)fc->ConvertFromString(ls[6]);
         
        
        Data.TrusteeshipMem(NewData);
#else
        d.ThrowException(_t("void _NTreeNode::SplitData(const bool& IsOldVersion): 代码未完成!"));
#endif
    }
    else
    {
        /*
        //打包九个字段


        _ByteArray  baNew, baTemp;

        //Data.Length +  Data 
        //KeyValue 
        //FirstChildKeyValue 
        //NextSiblingKeyValue  
        //DispalyText  
        //DisplayForeColor  
        //DisplayBackColor 
        //DispalyFont 
        //DataType  

        //------------------------------------------Data
        baNew.SetBuffer(Data.Length + 200);
 

        baNew.AddInt(Data.Length);
        baNew.Add(Data.Data, Data.Length);       

        //---------------------------------------KeyValue
        baNew.AddInt64(KeyValue);

        //---------------------------------------FirstChildKeyValue
        baNew.AddInt64(FirstChildKeyValue);

        //---------------------------------------NextSiblingKeyValue
        baNew.AddInt64(NextSiblingKeyValue);

        //---------------------------------------DispalyText
        baNew.AddInt(DispalyText.GetDataMemoryLength);
        baNew.Add((_byte*)DispalyText.Data,DispalyText.GetDataMemoryLength);

        //---------------------------------------DisplayForeColor
        baNew.AddInt(DisplayForeColor.PackageMemory(baTemp).Length);
        baNew.Add(baTemp.Data, baTemp.Length);

        //---------------------------------------DisplayBackColor
        baNew.AddInt(DisplayBackColor.PackageMemory(baTemp).Length);
        baNew.Add(baTemp.Data, baTemp.Length);
       
        //---------------------------------------DispalyFont
        baNew.AddInt(DispalyFont.PackageMemory(baTemp).Length);
        baNew.Add(baTemp.Data, baTemp.Length);

        //---------------------------------------DataType
        baNew.AddInt(DataType);
         
        Data.TrusteeshipMem(baNew); //释放本身内存,托管其它对象
        */

        //拆分九个字段


        _ByteArray  baAll;
        baAll.TrusteeshipMem(Data);

        _byte* p = baAll.Data;


        //-----------------------------Data
        int n = *(int*)p;
        p += sizeof(int);

        Data.ClearMemory();
        Data.Add(p, n);

        p += n;

        //-----------------------------KeyValue
        KeyValue = *(__int64*)p;
        p += sizeof(__int64);

        //-----------------------------FirstChildKeyValue
        FirstChildKeyValue = *(__int64*)p;
        p += sizeof(__int64);

        //-----------------------------NextSiblingKeyValue
        NextSiblingKeyValue = *(__int64*)p;
        p += sizeof(__int64);

        //-----------------------------DispalyText
        n = *(int*)p;
        p += sizeof(int);
        DispalyText.Clear();
        DispalyText.Add((_char*)p, n / sizeof(_char));
        p += n;

        //-----------------------------DisplayForeColor
        n = *(int*)p;
        p += sizeof(int);
        DisplayForeColor.SplitFromMemory(p);

        p += n;

        //-----------------------------DisplayBackColor
        n = *(int*)p;
        p += sizeof(int);
        DisplayBackColor.SplitFromMemory(p);

        p += n;


        //-----------------------------DispalyFont
        n = *(int*)p;
        p += sizeof(int);
        DispalyFont.SplitFromMemory(p);

        p += n;


        //-----------------------------DataType
        DataType = (_DataType) (*(int*)p);

    }
}


bool _NTreeNode::IsMyChild(const _NTreeNode* pChild)
{
    if (pChild == null) return false;

    _NTreeNode* pTemp = FirstChild;

    while (pTemp != null)
    {
        if (pTemp == pChild)
            return true;

        pTemp = pTemp->NextSibling;
    }

    return false;
}

bool _NTreeNode::IsMyParent(const _NTreeNode* pParent)
{
    if (pParent == null) return false;

    const _NTreeNode* pTemp = pParent->FirstChild;

    while (pTemp != null)
    {
        if (pTemp == this)
            return true;

        pTemp = pTemp->NextSibling;
    }

    return false;
}
 




//------------------------------------------------------------------------------------_NTree 定义

const _string _NTree::ConstName = _t("TreeView");






/// <summary>
/// 判断pFind是否pFindStart或者pFindStart下面任何一个节点的第一个子节点,如果不是返回NULL,否则返回它的父节点。
/// </summary>
/// <param name="pFindStart">查找开始位置</param>
/// <param name="pFind">所查找的节点</param>
/// <returns>找到则返回父节点,否则返回NULL</returns>
_NTreeNode* _NTree::FindIsFirstChild(const _NTreeNode* pFindStart, const _NTreeNode* pFind)
{
    if (pFindStart == pFind || pFindStart == null) return null;

    _NTreeNode* pNode = (_NTreeNode*)pFindStart;

    while (pNode != null)
    {
        if (pNode->FirstChild == pFind)
            return pNode;
        else
        {
            _NTreeNode* pTemp = FindIsFirstChild(pNode->FirstChild, pFind);
            if (pTemp != null)
                return pTemp;
        }
        pNode = pNode->NextSibling;
    }
    return null;
}


/// <summary>
/// 遍历所有节点,查找它的子结点,如果子结点包含 pChild,则返回此结点
/// </summary>
/// <param name="pStart">开始位置</param>
/// <param name="pChild">子结点</param>
/// <returns></returns>
/// 创建时间:2022-07-18 最后一次修改时间:2023-01-02
_NTreeNode* _NTree::FindPrent(const _NTreeNode* pStart, const _NTreeNode* pChild)
{
    if (pStart == null || pChild == null || pStart == pChild ) return null;

    _NTreeNode* pTemp = (_NTreeNode*)pStart;

    while (pTemp != null)
    { 
        if (pTemp->IsMyChild(pChild))
            return pTemp;

        _NTreeNode* pResult = FindPrent(pTemp->FirstChild, pChild);

        if (pResult != null)
        {

            return pResult;
        }

        pTemp = pTemp->NextSibling;
    }


    return null;
}


/// <summary>
/// 从tnStart处遍历二叉树,查找 pNode的上一个兄弟节点
/// </summary>
/// <param name="pStart">查找开始处</param>
/// <param name="pNode">查找的节点</param>
/// <returns>找到则返回上一个兄弟节点,否则返回NULL</returns>
/// 创建时间:????-??-?? 最后一次修改时间:2022-07-18
_NTreeNode* _NTree::FindPrevSibling(const _NTreeNode* pStart, const _NTreeNode* pNode)
{
    if (pStart == pNode || pStart == null)
        return null;

    _NTreeNode* tn = (_NTreeNode * )pStart;

    while (tn != null)
    {
        if (tn->NextSibling == pNode)
            return tn;
        else
        {
            if (tn->FirstChild != null)
            {
                _NTreeNode* tmp = FindPrevSibling(tn->FirstChild, pNode);

                if (tmp != null)
                    return tmp;
            }
        }

        tn = tn->NextSibling;
    }

    return null;
}


/// <summary>
/// 获取pNode最后一个兄弟节点
/// </summary>
/// <param name="pFirstSibling"></param>
/// <returns></returns>
_NTreeNode* _NTree::GetLastSibling(const _NTreeNode* pNode)
{
    if (pNode == null) return null;

    _NTreeNode* pTemp = pNode->NextSibling;

    if (pTemp == null)
    {
        return (_NTreeNode*)pNode;
    }
    else
    { 
        while (true)
        {
            if (pTemp->NextSibling == null)
            {
                return pTemp;
            }
            else
            {
                pTemp = pTemp->NextSibling;
            }
        }
    }
}


/// <summary>
/// 删除从树型目录独立出来的孤链,返回删除的个数
/// </summary>
/// <param name="pDelete"></param>
/// <returns></returns>
/// 创建时间:2023-01-05 最后一次修改时间:2023-01-08
int _NTree::_DeleteSolitaryNode(const _NTreeNode* pDelete)
{
    _DList< _NTreeNode*> dl;
    _GetNodeChildrenAll(pDelete, dl);
     
    auto p = dl.First();

    while (p != null)
    {

#ifdef  _NTREE_DEBUG_
        d.PrintError( _t("int _NTree::_DeleteSolitaryNode(const _NTreeNode* pDelete):") + p->Data->DispalyText);
#endif
        _Memory::Delete<_NTreeNode>(p->Data,1);

        p = p->Next;
    }

    _Count = _Count - dl.Count;

    return dl.Count;
}



/// <summary>
/// 删除结点
/// </summary>
/// <param name="pRemove"></param>
/// <returns></returns>
/// 创建时间:2023-01-05 最后一次修改时间:2023-01-08
bool _NTree::RemoveNode(const _NTreeNode* pRemove)
{
    if (pRemove == null) return false;

    if (_Root == pRemove) //删除根节点
    {
        ClearMemory();
        return true;
    }
     
    _NTreeNode* pParent = FindPrent(_Root, pRemove);

    if (pParent == null) //没有父结点,又不是根结点
    {
        d.ThrowException(_t("bool _NTree::RemoveNode(const _NTreeNode * pRemove) : N叉树构建错误!"));
    }
    else  //在这里删除 pRemove
    { 
        _NTreeNode*  pPrev = this->FindPrevSibling(_Root, pRemove);  //上一个亲兄弟节点
        _NTreeNode* pNext = pRemove->NextSibling;   //下一个兄弟结点
        if (pPrev != null) //有上一个兄弟结点
        {
            if (pNext != null) //有上一个兄弟结点,也有下一个兄弟节点
            {
                pPrev->NextSibling = pNext;
                pPrev->NextSiblingKeyValue = pNext->KeyValue;
                _DeleteSolitaryNode(pRemove);
            }
            else //有上一个兄弟结点,没有下一下亲兄弟节眯
            {
                pPrev->NextSibling = null;
                pPrev->NextSiblingKeyValue = -1;
                _DeleteSolitaryNode(pRemove);
            }
        }
        else  //没有上一个兄弟结点,那么它是它父结点的第一个子结点
        {
            if (pNext != null)  
            {
                pParent->FirstChild = pNext;
                pParent->FirstChildKeyValue = pNext->KeyValue;
                _DeleteSolitaryNode(pRemove);
            }
            else //没有兄弟结点,是单独的一个子结点
            {
                pParent->FirstChild = null;
                pParent->FirstChildKeyValue = - 1;

                _DeleteSolitaryNode(pRemove);
            }
        }

        return true;
    }
}



/// <summary>
/// 从文件中建立树,返回上次TreeNode最后一次所选节点Name       
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
/// 创建时间:????-??-?? 最后一次修改时间:2023-01-05
_string _NTree::BuildInFile(const _string& sFullPathName)
{
    ClearMemory();  //清除数据     

    _FullPathName = sFullPathName;

    _KeyBinaryFile kbf(sFullPathName);

    kbf.Open();
     

    //CSharp_slist ls = kbf->getIncludeKeyList(tvName + CSharp_TreeViewTreeNode^->m_Split);
    //这里有一个 bug ,旧的 TreeView 建立的,在新的TreeView显示不了,因为这跟名子相关,TreeView控件名子变了,为了不改动大量的代码
    //每次文件保存时,写入TreeView控件的名子 
    //String tvName = kbf->getString("Last_TreeView_Name", "");

    /*
    String tvName = kbf->getString("Last_TreeView_Name", "");

    if (tvName == "") //旧的文件是显示不了的,但是用新版本程序保存一下时,就可以显示出来了。
    {
        tvName = m_TreeView->Name;
        lg->ShowError("无法读取最后写入文件时TreeView控件的名子,将启用新的默认TreeView控件名称。", "BuildInFile");
    }
    */

    _StringList ls = kbf.GetIncludeKeyList(_NTree::ConstName + _NTreeNode::SplitString);


    //d.PrintError(ls.ToString());
     

    //以前版本的 constName 都是 TreeView 控件的名子,一旦控件名子改了,就建立不了数据了。
    //-------------------------------------------------------------------------------------版本兼容
    _string  oldConstName = _t("");
    if (ls.Count == 0)
    {
        ls = kbf.GetIncludeKeyList(_NTreeNode::SplitString);

        if (ls.Count > 0)
        {
            oldConstName = _StringList(ls[0], _NTreeNode::SplitString, false)[0];
        } 
    }
    else
    {
        oldConstName = ConstName;
    }


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



    if (ls.Count == 0) return _t("-1");



    _DList<_NTreeNode*> tnList;

    for (int i = 0; i < ls.Count; ++i)
    {

        _KeyData* kd = kbf.GetData(ls[i]);
        _Count = 0;
        if (kd != null)
        {
            _NTreeNode* tnNew = _Memory::New< _NTreeNode>(1);
            ++_Count; //计数器,计算分配的内存个数。

            tnNew -> Data = kd->Data;
            tnNew->SplitData(kbf.IsOldVersion());
            tnList.Add(tnNew);
        }        
    }


    //建立关系
    _DListNode<_NTreeNode*>* dn = tnList.First();

    while (dn != null)
    {
        _NTreeNode* tvtn = dn->Data;
        _NTreeNode* tn = null;

        if (tvtn->FirstChildKeyValue != -1)
        {
            tn = Find(tnList, tvtn->FirstChildKeyValue);
            if (tn == null)
            {
                _string sError = _t("_string _NTree::BuildInFile(const _string& sFullPathName):无法找到FirstChild!");
                d.ThrowException(sError);
            }
            else
                tvtn->FirstChild = tn;
        }

        if (tvtn->NextSiblingKeyValue != -1)
        {
            tn = Find(tnList, tvtn->NextSiblingKeyValue);
            if (tn == null)
            {
                _string sError = _t("_string _NTree::BuildInFile(const _string& sFullPathName):无法找到NextSibling!");
                d.ThrowException(sError);
            }      
            else
                tvtn->NextSibling = tn;
        }

        dn = dn->Next;
    }

   

    //--------------------------------------建立树,设置根节点

    //建立First节点
    _string sFirstKeyValue = kbf.GetString(oldConstName + _t("_First"), _t(""));
    _string sSelectName = kbf.GetString(oldConstName + _t("_Select"), _t(""));

    kbf.ClearData();
     

    int n = ls.IndexOf(oldConstName + _NTreeNode::SplitString + sFirstKeyValue);

    //d.PrintError(oldConstName + _NTreeNode::SplitString + sFirstKeyValue);
     
    if (n != -1)
    {
        _Root = tnList[n]; //建立根节点

    }
    else
    {
        _string sError = _t("_string _NTree::BuildInFile(const _string& sFullPathName):不能建立First节点!");
        d.ThrowException(sError);
         
    }     

     
    return sSelectName;  
      
}




/// <summary>
/// 清除内存
/// </summary>
void _NTree::ClearMemory() 
{ 
    _DList<_NTreeNode*>  dlAll;
     
    _GetNodeChildrenAll(_Root, dlAll);

    _DListNode<_NTreeNode*> *pNode = dlAll.First();

    while (pNode != null)
    {
        _Memory::Delete< _NTreeNode>(pNode->Data, 1);

        pNode = pNode->Next;
    }
    _Root = null;
    _Count = 0;
}

/// <summary>
///  遍历整个树,查找指针值相等 或者 KeyVlue 相等的节点,如果不是返回 1 或 0,说明建立的树是错误树。
/// </summary>
/// <param name="pFindStart"></param>
/// <param name="pChild"></param>
/// <param name="dResult"></param>
/// </summary>    /// 创建时间:2023-01-02 最后一次修改时间:2023-01-02
void _NTree::_FindNode(const  _NTreeNode* pFindStart, const _NTreeNode* pNode, _DList<const _NTreeNode*>& dResult)
{ 
    if (pNode == null || pFindStart == null) return;
     

    if (pFindStart == pNode || pFindStart->KeyValue == pNode->KeyValue)
    {
        dResult.Add(pFindStart);     
    }

    _NTreeNode* pTemp = (_NTreeNode*)pFindStart->FirstChild;

    while (pTemp != null)
    {
        _FindNode(pTemp, pNode, dResult);

        pTemp = pTemp->NextSibling;
    }
}


_DList<_NTreeNode*> _NTree::GetNodeAll() const
{
    _DList<_NTreeNode*> dlResult;

    _GetNodeChildrenAll(_Root, dlResult);

    return dlResult;
  
}


/// <summary>
/// 获取 pParent结点下的所有子结点,包括 pParent
/// </summary>
/// <param name="pStart"></param>
/// <param name="dResult"></param>
/// 创建时间:2023-01-02 最后一次修改时间:2023-01-05
void _NTree::_GetNodeChildrenAll(const _NTreeNode* pParent, _DList<_NTreeNode*>& dResult)const
{
    if (pParent == null) return;
       
 
    dResult.Add((_NTreeNode * )pParent);

    _NTreeNode* pTemp = (_NTreeNode*)pParent->FirstChild;


    while (pTemp != null)
    {
        _GetNodeChildrenAll(pTemp,dResult);
          
        pTemp = pTemp->NextSibling;
    }
}


/// <summary>
/// 查找一个节点,如果KeyValue的值相等,也视为找到,找不到返回空链表值.
/// </summary>
/// <param name="pChild"></param>
/// <returns></returns>
/// 创建时间:2023-01-02 最后一次修改时间:2023-01-02
_DList<const _NTreeNode*> _NTree::FindNode(const _NTreeNode* pNode)
{
    _DList<const _NTreeNode*> dResult;

    _FindNode(_Root, pNode, dResult);
     
    return dResult;
}



/// <summary>
/// 添加一个节点,如果父节点pParent为null,则默认添加到根节点中,
/// 如果没有根节点,则添加的节点就是根节点,返回新添加的节点的指针。
/// 这里不检查 pParent 是否树中的一个结点
/// </summary>
/// <param name="pParent"></param>
/// <param name="pChild"></param>
/// <returns></returns>
/// 创建时间:2023-01-02 最后一次修改时间:2023-01-09
_NTreeNode* _NTree::AddNode(_NTreeNode* pParent, const _NTreeNode* pNode)
{
    if (_Root == null)
    {
        if (pParent != null) return null;

        _Root = _Memory::New< _NTreeNode>(1);

        *_Root = *pNode;
        _Root->FirstChild = null;
        _Root->NextSibling = null;
        _Count = 1;

        return _Root;
    }

     
    if (pParent == null && pNode == null) return null;

    if (pNode->FirstChild != null || pNode->NextSibling != null)
    {
        _string Error = _t("_NTreeNode* _NTree::AddChild(const _NTreeNode* pParent, const _NTreeNode* pChild): 只能添加一个孤立的节点!");
        d.PrintError(Error);
        throw Error;
    }


    _NTreeNode* pNew = _Memory::New< _NTreeNode>(1);

    *pNew = *pNode;
 

    
    //获取最后一个兄弟节点
    _NTreeNode* pLast = GetLastSibling(pParent->FirstChild);

    if (pLast == null)
    {
        pParent->FirstChild = pNew;
        pParent->FirstChildKeyValue = pNew->KeyValue;
    }
    else
    {
        pLast->NextSibling = pNew;
        pLast->NextSiblingKeyValue = pNew->KeyValue;
    }


    ++_Count;

    return pNew;
}

/// <summary>
/// 添加一个节点,如果父节点pParent为null,则默认添加到根节点中,
/// 如果没有根节点,则添加的节点就是根节点,返回新添加的节点的指
/// 针。这里不检查 pParent 是否树中的一个结点
/// </summary>
/// <param name="tnList"></param>
/// <param name="iFirstChildKeyValue"></param>
/// <returns></returns>
/// 创建时间:2023-01-17 最后一次修改时间:2023-01-17
_NTreeNode* _NTree::AddNode(_NTreeNode* pParent, const _string& sDisplayText)
{

    _NTreeNode* pNode  = _Memory::New<_NTreeNode>(1);

    pNode->DispalyText = sDisplayText;


    if (pParent == null)
    {
        if (_Root == null) {
            _Root = pNode;
        }
        else
        {
            _NTreeNode* pLast = GetLastSibling(_Root->FirstChild);

            if (pLast == null)
            {
                _Root->FirstChild = pNode;
                _Root->FirstChildKeyValue = pNode->FirstChildKeyValue;
            }
            else
            {
                pLast->NextSibling = pNode;
                pLast->NextSiblingKeyValue = pNode->KeyValue;
            }
        }
    }
    else
    {
        _NTreeNode* pLast = GetLastSibling(pParent->FirstChild);

        if (pLast == null)
        {
            pParent->FirstChild = pNode;
            pParent->FirstChildKeyValue = pNode->FirstChildKeyValue;
        }
        else
        {
            pLast->NextSibling = pNode;
            pLast->NextSiblingKeyValue = pNode->KeyValue;
        }
    }


    ++_Count;

    return pNode;
}


/// <summary>
/// 在LDlist列表中查找键值为 iKeyValue 的结点
/// </summary>
/// <param name="tnList"></param>
/// <param name="iFirstChildKeyValue"></param>
/// <returns></returns>
/// 创建时间:????-??-?? 最后一次修改时间:2022-07-18
_NTreeNode* _NTree::Find(const _DList<_NTreeNode*>& tnList, const __int64& iKeyValue)const
{
    _DListNode<_NTreeNode*>* tn = tnList.First();

    while (tn != null)
    {
        if (tn->Data->KeyValue == iKeyValue)
            return tn->Data;
        tn = tn->Next;
    }
    return null;
}

 
_NTreeNode* _NTree::Find(const _DList<_NTreeNode*>& tnList, const _string& sKeyValue)const
{
    return Find(tnList, sKeyValue.ToInt64());
}

/// <summary>
/// 在结点 tnFindStart 中的子结点中查找节点键值为 iKeyValue 的结点,包括结点 tnFindStart
/// </summary>
/// <param name="tnFindStart">开始查找的结点</param>
/// <param name="iKeyValue">键值</param>
/// <returns>返回第一次出现的结点</returns>
/// <exception cref="Exception"></exception>
/// 创建时间:????-??-?? 最后一次修改时间:2022-07-18
_NTreeNode* _NTree::Find(const _NTreeNode* tnFindStart, const __int64 &iKeyValue)const
{

    if (tnFindStart == null || iKeyValue == -1)
        d.ThrowException(_t("_NTreeNode* _NTree::Find(const _NTreeNode* tnFindStart, const Int64 &iKeyValue): tnFindStart == null ||  iKeyValue == -1"));

    if (_Root == null)      return null;

    _NTreeNode* tnTmp = (_NTreeNode * )tnFindStart;

    while (tnTmp != null)
    {
        if (tnTmp->KeyValue == iKeyValue)  //查找节点本身
        {
            return tnTmp;
        }
        else
        {
            //查找节点的子节点
            if (tnTmp->FirstChild != null)
            {
                _NTreeNode* tnFind = Find((_NTreeNode*)tnTmp->FirstChild, iKeyValue);
                if (tnFind != null)
                {
                    return tnFind;
                }
            }
        }

        //如果都还没找到,继续查找兄弟节点
        tnTmp = (_NTreeNode*)tnTmp->NextSibling;
    }

    return null;
}



/// <summary>
/// 在结点 tnFindStart 中的子结点中查找节点键值为 iKeyValue 的结点,包括结点 tnFindStart
/// </summary>
/// <param name="tnFindStart">开始查找的结点</param>
/// <param name="sKeyValue"></param>
/// <returns>返回第一次出现的结点</returns>
/// 创建时间:????-??-?? 最后一次修改时间:2022-07-18
_NTreeNode* _NTree::Find(const _NTreeNode* tnFindStart, const _string& sKeyValue)const
{
    if (!sKeyValue.IsArabicDigitString())
    {
        _string sError = _t("_NTreeNode* _NTree::Find(const _NTreeNode* tnFindStart, const _string& sKeyValue) 错误: sKeyValue=“") + sKeyValue + _t("” 不是数字!");  
        d.ThrowException(sError);
    }

    return Find(tnFindStart, sKeyValue.ToInt64());     
}



/// <summary>
/// 把本节点、兄弟节点、子节点数据写入磁盘.
/// 除非构建的链表,或者节点数据有问题,否则此函数是正确的。
/// </summary>
/// <param name="tvtnNode"></param>
/// <param name="kbf"></param>
/// 创建时间: ????-??-??      最后一次修改时间:2022-10-27 
void _NTree::SaveSiblingAndChild(_NTreeNode* pNode, _KeyBinaryFile& kbf)
{ 
    if (pNode == null) return;

    _NTreeNode* pTemp = pNode;
    _ByteArray ba;

    while (pTemp != null)
    {
        _string sKeyString(_t(""), 100);
        
        
        sKeyString.Add(ConstName);
        sKeyString.Add(_NTreeNode::SplitString);
        sKeyString.Add(std::to_wstring(pTemp->KeyValue).c_str());
     

        kbf.AddByteArray(sKeyString, pTemp->PackageData(ba,false));

        //log::d(L"sKeyString = "+ sKeyString->ToString(), L"CSharp_TreeDataView::SaveSiblingAndChild");

        //log::d(L"tvtn->KeyValue.ToString() = " + tvtn->KeyValue.ToString(), L"CSharp_TreeDataView::SaveSiblingAndChild");

        //log::d(L"tvtn->DispalyText.ToString() = " + tvtn->DispalyText->ToString(), L"CSharp_TreeDataView::SaveSiblingAndChild");

        //log::d(tvtn->PackageData(), L"SaveSiblingAndChild");


        SaveSiblingAndChild(pTemp->FirstChild, kbf);

        pTemp = pTemp->NextSibling;
    }
}


/// <summary>
/// 返回根节点的数据
/// </summary>
/// <returns></returns>
_StrA _NTree::GetFirstNodeDataA() const
{
    if (_Root != null)
        return (char*)_Root->Data.Data;
    else
        return "";
}

_StrW _NTree::GetFirstNodeDataW() const
{
    if (_Root != null)
        return (wchar_t*)_Root->Data.Data;
    else
        return _t("");
}

void _NTree::SetFirstNodeData(const _StrA& sData)
{
    if (_Root != null)
    {
        _Root->Data.ClearData();
        _Root->Data.AddStringA(sData); 
    }
    else
    {
        d.ShowError(_t("没有根节点!"), _t("void _NTree::SetFirstNodeData(const _string& sData)"));
    } 
}

void _NTree::Display() const
{
    Display(_Root);
}


/// <summary>
/// 
/// </summary>
/// <param name="pNode"></param>
/// <param name="nLevel"></param>
/// 创建时间:2023-01-17 最后一次修改时间:2023-01-17
void _NTree::Display(const _NTreeNode* pNode, const int nLevel) const
{
    
    _string sRoot;

    for (int i = 1; i < nLevel; ++i)
    {
        sRoot.Add('\t');
    }

    if (pNode != null)
    {
        _cout << sRoot << pNode->DispalyText << _t("\n");
        
    }
    else
    {
        return;
    }

    _NTreeNode* pChild = pNode->FirstChild;

    while (pChild != null)
    {
        Display(pChild, nLevel + 1);

        pChild = pChild->NextSibling;
    }
}

 
#if _CLR_

void _NTree::Save(TreeView^ tv,const _string& sFullPathName, bool bReWrite)
{

    if (sFullPathName.CSharp_Trim().Length == 0)
    {
        d.ShowError(sFullPathName + _t("\n文件名不能为空!"), _t("void _NTree::Save(const _string & sFullPathName, TreeView ^ tv, bool bReWrite)"));
    }

    if (sFullPathName.FileExists())
    {
        if (!bReWrite)
        {
            d.ShowError(sFullPathName + _t("\n文件已存在!"), _t("void _NTree::Save(const _string & sFullPathName, TreeView ^ tv, bool bReWrite)"));
            return;
        }
    }

    _KeyBinaryFile  kbf(sFullPathName);

    if (_Root != null)
    {

        kbf.AddString(ConstName + _t("_First"), _Root->KeyValue.ToString());


        if (tv != null)
        {
            if (tv->SelectedNode != null)
                kbf.AddString(ConstName + _t("_Select"), tv->SelectedNode->Name);
            else

                kbf.AddString(ConstName + _t("_Select"), _t("-1"));
        }

        SaveSiblingAndChild(_Root, kbf);

        kbf.SaveAnother(sFullPathName);
         
    }
    else  //空文件
    {
        kbf.SaveAnother(sFullPathName);
    }
}


void _NTree::BuildInTreeView(TreeView^ tv, TreeNode^ tnParent, const _NTreeNode* pNode, int nImageIndex)
{
    //if (! CheckTreeViewTreeNode(tvtnNode, L"CSharp_Tree::BuildTreeView")) return;

    _NTreeNode* pn = (_NTreeNode *) pNode;

    while (pn != null)
    {
        TreeNode^ tn = gcnew TreeNode(pn->DispalyText);
        tn->Name = pn->KeyValue.ToString();
        tn->ForeColor = pn->DisplayForeColor; //tv->ForeColor;  
        //tn->BackColor =   pn->DisplayBackColor; //tv->ForeColor; 
         
        tn->NodeFont =  pn->DispalyFont; //tv->Font;  

        //d.PrintError(_geti((int)pn->DispalyFont.Size),"void _NTree::BuildInTreeView(");

        tn->ImageIndex = nImageIndex;
        tn->SelectedImageIndex = nImageIndex;
        tn->StateImageIndex = nImageIndex;

        if (tnParent == null)
            tv->Nodes->Add(tn);
        else
            tnParent->Nodes->Add(tn);

        BuildInTreeView(tv,tn, pn->FirstChild, nImageIndex);

        pn = pn->NextSibling;
    }
}



/// <summary>
/// 把树显示在控件 TreeView 上
/// </summary>
/// <param name="tv"></param>
void _NTree::BuildInTreeView(TreeView^ tv,const int iImageIndex)
{
    if (tv == null) return;

    tv->Nodes->Clear();

    BuildInTreeView(tv, null, _Root, iImageIndex);

    tv->ExpandAll();
}


_StrW _NTree::GetTreeNodeDataW(TreeNode^ tn)
{
    _NTreeNode* tvtn = Find(_Root, tn->Name);

    if (tvtn == null)
        throw gcnew Exception("tvtn == null");

    return (wchar_t*)tvtn->Data.Data;
}

_StrA _NTree::GetTreeNodeDataA(TreeNode^ tn)
{
    _NTreeNode* tvtn = Find(_Root, tn->Name);

    if (tvtn == null)
        throw gcnew Exception("tvtn == null");

    return (char*)tvtn->Data.Data;
}


void _NTree::AfterLabelEdit_Event(Object^ sender, NodeLabelEditEventArgs^ e)
{
    TreeView^ tv = (TreeView^)sender;

    if (e->Label != null && e->Label->Trim() != "")
    {
        UpdateTreeViewNode(tv,e->Node, e->Label);
        IsModify = true;
    }
    else
    {
        e->CancelEdit = true;
    }
}

/// <summary>
/// TreeView的节点属性改变,同时更新CSharp_Tree^的节点。
/// </summary>
/// <param name="tnModify">发生改变的节点</param>
/// <param name="sDispalyText">所显示的文本</param>
/// <exception cref="Exception"></exception>
/// 创建时间: 2022-03-05      最后一次修改时间:2022-03-05
void _NTree::UpdateTreeViewNode(TreeView^ tv, TreeNode^ tnModify, String^ sDispalyText)
{
    _NTreeNode* tnFind = Find(_Root, tnModify->Name);

    if (tnFind == null)
        throw gcnew Exception("tnFind = null");

    if (sDispalyText != _t(""))
        tnFind->DispalyText = sDispalyText;
    else
        tnFind->DispalyText = tnModify->Text;

    if (tnModify->NodeFont == null)  //如果没有设置时,新建的节点是NULL,自动跟TreeView的Font^相同
    {
        tnFind->DispalyFont = tv->Font;
    }
    else
    {
        tnFind->DispalyFont = tnModify->NodeFont;
    }


    tnFind->DisplayBackColor = tnModify->BackColor;
    tnFind->DisplayForeColor = tnModify->ForeColor;

}

void _NTree::TreeViewSelectedNodeDelete(TreeView^ tv)
{
    TreeNode^ tn = tv->SelectedNode;
    if (tn != null)
    {
        if (MessageBox::Show(_t("真的要删除“") + tn->Text + _t("”吗?"), _t("删除提示"), MessageBoxButtons::YesNo, MessageBoxIcon::Question) == DialogResult::Yes)
        {

            tv->Nodes->Remove(tn);

            if (_Root == null)
                throw gcnew Exception("First==null");

            _NTreeNode* tnRemove = Find(_Root, tn->Name);

            if (tnRemove == null)
                throw gcnew Exception("tnRemove == null");


            if (!RemoveNode(tnRemove))
            {
                throw gcnew Exception(" RemoveNode(tnRemove) == False");
            }

            IsModify = true;
        }
    }
}

void _NTree::TreeViewSelectedNodeAddNewNode(TreeView^ tv, String^ sDisplayText)
{

    _NTreeNode  ntn;
     
    ntn.DispalyFont = tv->Font;
    ntn.DispalyText = sDisplayText;
    ntn.DisplayBackColor = tv->BackColor;
    ntn.DisplayForeColor = tv->ForeColor;
    ntn.NextSibling = null;

    TreeNode^ tn = gcnew TreeNode(sDisplayText);
    tn->Name = ntn.KeyValue.ToString();


    if (tv->SelectedNode == null) //如查没有选中根节点,则在根节点中加入子节点
    {
        if (tv->Nodes->Count == 0)
        {
            tv->Nodes->Add(tn);
        }
        else
        {
            tv->Nodes[0]->Nodes->Add(tn);
        }
       
        
        AddNode(null, &ntn);
    }
    else
    {

        tv->SelectedNode->Nodes->Add(tn);

        _NTreeNode *pParent = Find(_Root, tv->SelectedNode->Name);

        if (pParent == null)
        {
            _string sErrorInfo = _t("NTree中无法找到 m_TreeView->SelectedNode->Name= “") + _string(tv->SelectedNode->Name) + _t("” 的节点");
            d.ShowError(sErrorInfo, _t("CSharp_TreeDataView->TreeViewSelectedNodeAddNewNode"));
            //log::d(sErrorInfo, L"CSharp_TreeDataView->TreeViewSelectedNodeAddNewNode");
            return;
        }

        AddNode(pParent, &ntn);

    }

    tv->SelectedNode = tn;
    IsModify = true;

}
/// <summary>
/// 改变节点数据
/// </summary>
/// <param name="sData"></param>
void _NTree::ChangeSelectedNodeData(TreeView^ tv, String^ sData)
{
    TreeNode^ tn = tv->SelectedNode;

    if (tn == null)
        throw gcnew Exception("tn == null");

    _NTreeNode* pntn = Find(_Root, tv->SelectedNode->Name);

    if (pntn == null)
        throw gcnew Exception("tvtn == null");

    pntn->Data.ClearData();
    
    //TreeView 都用 char
    pntn->Data.AddStringA(sData);   //pntn->Data.AddString(sData);

    if (tn->NodeFont != null)
    {
        pntn->DispalyFont = tn->NodeFont;
    }

    pntn->DispalyText = tn->Text;
    pntn->DisplayBackColor = tn->BackColor;
    pntn->DisplayForeColor = tn->ForeColor;

    IsModify = true;

}




/// <summary>
/// TreeView控件的修改节点事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="Exception"></exception>
/// 创建时间: ????-??-??      最后一次修改时间:2022-03-05
void _NTree::AfterLabelEdit_Event(TreeView^ tv, Object^ sender, NodeLabelEditEventArgs^ e)
{
    if (e->Label != null && e->Label->Trim() != "")
    {
        UpdateTreeViewNode(tv,e->Node, e->Label);
        IsModify = true;
    }
    else
    {
        e->CancelEdit = true;
    }
}


/// <summary>
/// 改变字体或者前景色
/// </summary>
/// <param name="tnNode"></param>
void _NTree::TreeViewNodeAttributeChange(TreeNode^ tnNode)
{
    _NTreeNode* tn = Find(_Root, tnNode->Name);

    if (tn != null)
    {
        tn->DispalyFont = tnNode->NodeFont;
        tn->DispalyText = tnNode->Text;
        tn->DisplayForeColor = tnNode->ForeColor;
        tn->DisplayBackColor = tnNode->BackColor;

        IsModify = true;
    }
}

void _NTree::ItemDrag_Event(TreeView^ tv, Object^ sender, ItemDragEventArgs^ e)
{

    if (e->Button == MouseButtons::Left)
    {
 
        tv->DoDragDrop(e->Item, DragDropEffects::Move);
        
    }
}



/// <summary> 
/// 记住格式是: GetData("System.Windows.Forms.TreeNode") 不是: GetData("System.Windows::Forms::TreeNode");
/// </summary>
/// <param name="tv"></param>
/// <param name="sender"></param>
/// <param name="e"></param>
/// 创建时间:????-??-?? 最后一次修改时间:2023-01-11
void _NTree::DragDrop_Event(TreeView^ tv, Object^ sender, DragEventArgs^ e)
{ 

    //获得拖放中的节点
    TreeNode^ tnMove = (TreeNode^)e->Data->GetData("System.Windows.Forms.TreeNode");

    if (tnMove == nullptr)
    {
        d.ShowError(_t("错误:tnMove == nullptr"), _t("void _NTree::DragDrop_Event(TreeView^ tv, Object^ sender, DragEventArgs^ e)"));
    }

    //根据鼠标坐标确定要移动到的目标节点
    Point p = Point(e->X, e->Y);
    Point pt = ((TreeView^)sender)->PointToClient(p);


    TreeNode^ tnTarget = tv->GetNodeAt(pt);



    if (tnTarget == null) { return; }



    if (tnMove->Nodes->Find(tnTarget->Name, true)->Length != 0)
    {
        ga.p(L"无法移动父节点到到它子节点中去!", L" void DragDrop_Event");
        return;
    }



    //不需要变动,因为把tnMove放在tnTarget下为子节点,而tnMove本身就是tnTarget的最后一个子节点。
    if (tnTarget->Nodes->Count > 0 && tnTarget->Nodes[tnTarget->Nodes->Count - 1] == tnMove)
        return;


    //----------------------------------------------------------------在CSharp_Tree^上操作
    _NTreeNode* ltnMove = Find(_Root, tnMove->Name);

    if (ltnMove == null)
    {
        throw gcnew Exception(L"无法找到节点:" + tnMove->Text);
    }


    //除去ltnMove

    _NTreeNode* ltnPrevSibling = FindPrevSibling(_Root, ltnMove);

    if (ltnPrevSibling != null)
    {
        ltnPrevSibling->NextSibling = ltnMove->NextSibling;
        ltnPrevSibling->NextSiblingKeyValue = ltnMove->NextSiblingKeyValue;

        //一定要设置ltnMove为孤链
        ltnMove->NextSibling = null;
        ltnMove->NextSiblingKeyValue = -1;
    }
    else
    {
        _NTreeNode* ltnParent = FindIsFirstChild(_Root, ltnMove);

        if (ltnParent != null)
        {
            if (ltnMove->NextSibling != null)
            {

                ltnParent->FirstChild = ltnMove->NextSibling;
                ltnParent->FirstChildKeyValue = ltnMove->NextSibling->KeyValue;

                //一定要设置ltnMove为孤链
                ltnMove->NextSibling = null;
                ltnMove->NextSiblingKeyValue = -1;
            }
            else
            {
                ltnParent->FirstChild = null;
                ltnParent->FirstChildKeyValue = -1;
            }
        }
        else
        {
            throw gcnew Exception(L"链接错误!");
        }
    }

    //查找目标节点
    _NTreeNode* ltnTarget = Find(_Root, tnTarget->Name);

    if (ltnTarget == null)
    {
        throw gcnew Exception(L"无法找到节点:" + tnTarget->Text);
    }


    //在目标节点未加上子节点ltnMove
    AddNode(ltnTarget,ltnMove);
     

    //-------------------------------------------------------------在控件上操作

    //如果目标节点为分组则添加到下级节点的未端,如果目标节点为素材文件则添加为同级节点
    TreeNode^ NewMoveNode = (TreeNode^)tnMove->Clone();


    tnTarget->Nodes->Insert(tnTarget->Nodes->Count, NewMoveNode);

    //更新当前拖动的节点选择
    tv->SelectedNode = NewMoveNode;
    //展开目标节点,便于显示拖放效果
    tnTarget->Expand();

    //移除拖放的节点
    tnMove->Remove();

    IsModify = true;

}



/// <summary>
/// 记住格式是: "System.Windows.Forms.TreeNode"  不是:"System.Windows.Forms.TreeNode", 跟C#一样
/// </summary>
/// </summary>
/// <param name="tv"></param>
/// <param name="sender"></param>
/// <param name="e"></param>
/// 创建时间:????-??-?? 最后一次修改时间:2023-01-11
void _NTree::DragEnter_Event(TreeView^ tv, Object^ sender, DragEventArgs^ e)
{

    /*
    auto a = e->Data->GetFormats();

    for each (String^ s in a)
    {
        d.PrintError(s);
    }


    if (e->Data->GetDataPresent("System.Windows.Forms.TreeNode"))
    {
        
    }
    */

    if (e->Data->GetDataPresent(_t("System.Windows.Forms.TreeNode")))
        e->Effect = DragDropEffects::Move;
    else
       e->Effect = DragDropEffects::None;
 
}

_NTreeNode* _NTree::GetinitTreeViewTreeNode(TreeView^ tv,String^ sText)
{
    _NTreeNode* tvtnNew;

    if (sText != "")
        tvtnNew->DispalyText = sText;
    else
        tvtnNew->DispalyText = _t("新节点");

    if (tv->Font == null)
        throw gcnew Exception("m_TreeView->Font== null");
    tvtnNew->DispalyFont = tv->Font;
    tvtnNew->DisplayBackColor = tv->BackColor;
    tvtnNew->DisplayForeColor = tv->ForeColor;

    return tvtnNew;
}


TreeNode^ _NTree::TreeViewAddRootNode(TreeView^ tv, String^ sText)
{
    _NTreeNode* tvtnNew = GetinitTreeViewTreeNode(tv,sText);

    AddNode(null, tvtnNew);

    TreeNode^ tnNew;

    if (sText != "")
        tnNew = tv->Nodes->Add(sText);
    else
        tnNew = tv->Nodes->Add("新节点");

    tnNew->Name = tvtnNew->KeyValue.ToString();

    IsModify = true;

    return tnNew;
}


/// <summary>
/// 把选中的节点上移一位
/// </summary>
/// <returns></returns>
/// 创建时间:2022-07-17 最后一次修改时间:2022-07-19
String^ _NTree::TreeViewSelectNodeMoveUp(TreeView^ tv)
{


    TreeNode^ tnSelect = tv->SelectedNode;

    if (tnSelect == null)
    {
        return _t("未先定节点");
    }

    _NTreeNode* tvtnSelect = Find(_Root, tnSelect->Name);

    _NTreeNode* tvtnSelectParent = FindPrent(_Root, tvtnSelect);

    if (tvtnSelectParent == null) return L"未找到父结点!";


    if (tvtnSelect == null) return L"未找到值为:+ " + tnSelect->Name + L" 的节点!";

    _NTreeNode* prevOne = FindPrevSibling(_Root, tvtnSelect);

    if (prevOne == null)  return L"上一个兄弟结点不存在,无法上移!";



    _NTreeNode* prevTwo = FindPrevSibling(_Root, prevOne);

    if (prevTwo == null)
    {
        //-----------------------------在TreeView中
        TreeNode^ tnParent = tnSelect->Parent;
        int nInsertIndex = tnSelect->Index - 1;

        if (tnParent != null)
        {
            TreeNode^ newNode = (TreeNode^)tnSelect->Clone();    //克隆选中的节点
            tnParent->Nodes->Insert(nInsertIndex, newNode);
            tnSelect->Remove();



            //------------------------------------------在 Tree中
            //交换的是第一个结点,要找出它的父结点

            Int64 iTempKey = tvtnSelect->NextSiblingKeyValue;
            tvtnSelectParent->FirstChildKeyValue = tvtnSelect->KeyValue;
            tvtnSelect->NextSiblingKeyValue = prevOne->KeyValue;
            prevOne->NextSiblingKeyValue = iTempKey;

            _NTreeNode* tnTemp = tvtnSelect->NextSibling;
            tvtnSelectParent->FirstChild = tvtnSelect;
            tvtnSelect->NextSibling = prevOne;
            prevOne->NextSibling = tnTemp;

            tv->SelectedNode = newNode;
        }

    }
    else
    {
        //-----------------------------在TreeView中
        TreeNode^ tnParent = tnSelect->Parent;
        int nInsertIndex = tnSelect->Index - 1;

        if (tnParent != null)
        {
            TreeNode^ newNode = (TreeNode^)tnSelect->Clone();    //克隆选中的节点
            tnParent->Nodes->Insert(nInsertIndex, newNode);
            tnSelect->Remove();

            //------------------------------------------在 Tree中
            //交换中间结点,要找出它的父结点

            Int64 iTempKey = tvtnSelect->NextSiblingKeyValue;
            prevTwo->NextSiblingKeyValue = tvtnSelect->KeyValue;
            tvtnSelect->NextSiblingKeyValue = prevOne->KeyValue;
            prevOne->NextSiblingKeyValue = iTempKey;

            _NTreeNode* tnTemp = tvtnSelect->NextSibling;
            prevTwo->NextSibling = tvtnSelect;
            tvtnSelect->NextSibling = prevOne;
            prevOne->NextSibling = tnTemp;

            tv->SelectedNode = newNode;
        }
    }

    return "";
}

/// <summary>
/// 把选中的节点下移一位
/// </summary>
/// <returns></returns>
/// 创建时间:2022-07-17 最后一次修改时间:2022-07-19
String^ _NTree::TreeViewSelectNodeMoveDown(TreeView^ tv)
{

    TreeNode^ tnSelect = tv->SelectedNode;

    if (tnSelect == null)
    {
        return "未先定节点";
    }

    _NTreeNode* tvtnSelect = Find(_Root, tnSelect->Name);

    _NTreeNode* tvtnSelectParent = FindPrent(_Root, tvtnSelect);

    if (tvtnSelectParent == null) return "未找到父结点!";


    if (tvtnSelect == null) return "未找到值为:+ " + tnSelect->Name + " 的节点!";

    _NTreeNode* nextOne = tvtnSelect->NextSibling;


    if (nextOne == null) return "下一个兄弟结点不存在,无法下移!";


    _NTreeNode* prevOne = FindPrevSibling(_Root, tvtnSelect);



    if (prevOne == null)  //第一节点移到下面
    {
        //-----------------------------在TreeView中
        TreeNode^ tnParent = tnSelect->Parent;
        int nInsertIndex = tnSelect->Index + 2;

        if (tnParent != null)
        {
            TreeNode^ newNode = (TreeNode^)tnSelect->Clone();    //克隆选中的节点
            tnParent->Nodes->Insert(nInsertIndex, newNode);
            tnSelect->Remove();



            //------------------------------------------在 Tree中
            //交换的是第一个结点,要找出它的父结点

            Int64 iTempKey = nextOne->NextSiblingKeyValue;
            tvtnSelectParent->FirstChildKeyValue = nextOne->KeyValue;
            nextOne->NextSiblingKeyValue = tvtnSelect->KeyValue;
            tvtnSelect->NextSiblingKeyValue = iTempKey;

            _NTreeNode* tnTemp = nextOne->NextSibling;
            tvtnSelectParent->FirstChild = nextOne;
            nextOne->NextSibling = tvtnSelect;
            tvtnSelect->NextSibling = tnTemp;

            tv->SelectedNode = newNode;
        }

    }
    else
    {
        //-----------------------------在TreeView中
        TreeNode^ tnParent = tnSelect->Parent;
        int nInsertIndex = tnSelect->Index + 2;

        if (tnParent != null)
        {
            TreeNode^ newNode = (TreeNode^)tnSelect->Clone();    //克隆选中的节点
            tnParent->Nodes->Insert(nInsertIndex, newNode);
            tnSelect->Remove();

            //------------------------------------------在 Tree中
            //交换中间结点 

            Int64 iTempKey = nextOne->NextSiblingKeyValue;
            prevOne->NextSiblingKeyValue = nextOne->KeyValue;
            nextOne->NextSiblingKeyValue = tvtnSelect->KeyValue;
            tvtnSelect->NextSiblingKeyValue = iTempKey;

            _NTreeNode* tnTemp = nextOne->NextSibling;
            prevOne->NextSibling = nextOne;
            nextOne->NextSibling = tvtnSelect;
            tvtnSelect->NextSibling = tnTemp;

            tv->SelectedNode = newNode;
        }
    }

    return _t("");
}


#endif



_LF_END_

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值