应用:
_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_