Delphi下Treeview控件基于节点编号的访问 - 癫狂编程

Delphi下Treeview控件基于节点编号的访问

有时我们需要保存和重建treeview控件,本文提供一种方法,通过以树结构节点的编号访问树结构,该控件主要提供的方法如下:

function GetGlobeNumCode(inNode:TTreeNode):String;

功能:返回当前节点的编号,编号规则见源码内说明。

function LocatOrGenerateNode(inNumCode:String):TTreeNode;

功能:以编号返回节点,假如节点的父节点和它的前继兄弟节点不存在,该方法会创建它们,名称为\'Temp\',当然假如已经存在,就不执行创建工作。

通过以上两个函数,这样我们就可以不加限制的创建和访问节点。该控件在我以前开发的,现在提供给大家做一个参考,希望能对你有帮助。

源码:

// ***********************************************

//

// 用于实现对TreeView控件的树结构的保存和重建

// 编写该控件主要用于实现对行政文件等具有树的层次结构的对象

// 实现保存和显示

// 节点编号规则:

// + ***** ->1

// + ***** ->1.1

// + ***** ->1.1.1

// + ***** ->1.2

// 作者:Jack

// 最后修改日期:2002-12-24

//

// **********************************************

unit CtrlTree;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

ComCtrls;

type

TCtrlTree = class(TTreeView)

private

{ Private declarations }

function GetPosAtBound(inString:String;inStart:Integer):Integer;

function GetTheLastPointPos(inString:String):Integer;

protected

{ Protected declarations }

public

{ Public declarations }

function GetNumInSameLevel(inNode:TTreeNode):Integer;

function GetGlobeNumCode(inNode:TTreeNode):String;

function GetParent(inNumCode:String):TTreeNode;

function LocateNodeInLevel(parNode:TTReeNode;LevelCode:integer):TTReeNode;

published

{ Published declarations }

function LocatOrGenerateNode(inNumCode:String):TTreeNode;

function InsertAsFinalChild(inString:String;inNode:TTreeNode):TTReeNode;

function InsertAsPreviousSibling(inString:String;inNode:TTreeNode):TTReeNode;

end;

procedure Register;

implementation

procedure Register;

begin

RegisterComponents(\'Standard\', [TCtrlTree]);

end;

{ TCtrTree }

function TCtrlTree.GetNumInSameLevel(inNode: TTreeNode): integer;

{功能:产生已存在节点在兄弟节点层中对应的编号,从1起编

入口参数:inCode:TTreeNode节点

返回:同层编号

}

var

i:integer;

tmp:TTreeNode;

begin

i:=0;

tmp:=inNode;

while tmp<>nil do

begin

tmp:=tmp.getPrevSibling;

i:=i+1;

end;

Result:=i;

end;

function TCtrlTree.GetGlobeNumCode(inNode: TTreeNode): string;

{功能:产生已存在节点对应的全局编号

入口参数:inCode:TTreeNode节点

返回:全局编号

}

var

nocode:string;

tmp:TTreeNode;

begin

tmp:=inNode;

nocode:=IntToStr(GetNumInSameLevel(tmp));

while tmp.Level<>0 do

begin

tmp:=tmp.Parent;

nocode:=inttostr(GetNumInSameLevel(tmp))+\'.\'+nocode;

end;

Result:=nocode;

end;

function TCtrlTree.LocatOrGenerateNode(inNumCode: String): TTreeNode;

{功能:根据提供的全局编号进行定位,如路径不全,则创建路径

在定位过程产生的节点的Text为Temp

最终返回对应于全局编号的子节点

入口参数:inNumCode:String为全局编号

返回:全局编号对应的字节点

}

var

i,j:Cardinal;

NumInLevel:integer;

tmp:TTreeNode;

par:TTreeNode;

begin

tmp:=nil;

i:=1;

while i<=StrLen(PChar(inNumCode)) do

begin

//得到下一个点号的开始位

j:=GetPosAtBound(inNumCode,i);

//得到在兄弟节点中的排行数

NumInLevel:=StrToInt(Copy(inNumCode,i,j-i+1));

//定位父节点

par:=GetParent(Copy(inNumCode,1,j));

//得到对应的节点

tmp:=LocateNodeInLevel(par,numInLevel);

i:=j+2;

end;

Result:=tmp;

end;

function TCtrlTree.GetParent(inNumCode: String): TTreeNode;

{功能:根据提供的全局编号找到对应的父节点

如果是第一层的节点,则父节点为nil

入口参数:inNumCode:String为全局编号

返回:全局编号对应的父节点

}

var

GoStep:integer;

i:integer;

j:integer;

k:integer;

SearChInNode:TTReeNode;

ReturnNode:TTReeNode;

begin

//是第一层节点,返回nil;

k:=GetTheLastPointPos(inNumCode);

if k=0 then

begin

Result:=nil;

Exit;

end;

//是第二层或第二层以上节点

i:=1;

SearchInNode:=Items.GetFirstNode;

while i < GetTheLastPointPos(inNumCode) do

begin

j:=GetPosAtBound(inNumCode,i);

GoStep:=StrToInt(Copy(inNumCode,i,j-i+1));

if i=1 then //在第一层节点中搜索

begin

ReturnNode:=SearchInNode;

for k:=1 to GoStep-1 do

ReturnNode:=ReturnNode.getNextSibling;

end

else //在第二层或第二层以上节点中搜索

begin

GoStep:=StrToInt(Copy(inNumCode,i,j-i+1));

ReturnNode:=SearchInNode.Item[GoStep-1];

end;

SearchInNode:=ReturnNode;

i:=j+2

end;

Result:=SearchInNode;

end;

function TCtrlTree.LocateNodeInLevel(parNode: TTReeNode;LevelCode: integer): TTReeNode;

{功能:根据父节点以及在兄弟节点中的编号找到对应的节点

如果要创建兄弟及自己,则新创建的节点的Text为Temp

入口参数:parNode: TTReeNode为父节点

LevelCode: integer为编号

返回:在parNode中编号为LevelCode的孩子节点

}

var

i:integer;

j:integer;

tmp:TTreeNode;

tmps:TTreeNode;

begin

//父节点为空,是第一层节点

tmp:=nil;

if parNode=nil then

begin

i:=1;

tmps:=Items.GetFirstNode;

while (tmps<>nil) and (i<=LevelCode) do

begin

tmp:=tmps;

tmps:=tmps.getNextSibling;

i:=i+1;

end;

i:=i-1;

for j:=1 to LevelCode-i do

tmp:=Items.AddChild(nil,\'Temp\');

Result:=tmp;

end

else //父节点不为空,正常处理

begin

if parNode.Count<LevelCode then

for i:= 1 to LevelCode-parNode.Count do

Items.AddChild(parNode,\'Temp\');

Result:=parNode.Item[LevelCode-1];

end;

end;

function TCtrlTree.GetPosAtBound(inString: String;inStart:Integer): Integer;

{功能:根据起始位置找到下一个\'.\'的前一个位置

入口参数:inString: String节点编号

inStart: Integer当前处理层次的起始位置

返回:当前处理层次的结束位置

}

var

tmp:Char;

pos:integer;

begin

pos:=inStart+1;

while pos <= Integer(StrLen(PChar(inString))) do

begin

tmp:=inString[pos];

if tmp=\'.\' then

Break

else

pos:=pos+1;

end;

Result:=pos-1;

end;

function TCtrlTree.GetTheLastPointPos(inString: String): Integer;

{功能:找到编号中最后的\'.\'的位置

入口参数:inString: String为节点编号

返回:节点编号中最后的\'.\'的位置

}

var

tmp:Char;

pos:integer;

begin

pos:=Integer(StrLen(PChar(inString)));

while pos>=1 do

begin

tmp:=inString[pos];

if tmp=\'.\' then

Break

else

pos:=pos-1;

end;

Result:=pos;

end;

function TCtrlTree.InsertAsFinalChild(inString: String; inNode: TTreeNode):TTReeNode;

{功能:为当前节点插入一个孩子节点,位置为最后

入口参数:inString: String为节点编号为待插入节点的字符串

inNode: TTreeNode,当前节点

}

begin

Result:=Items.AddChild(inNode,inString);

end;

function TCtrlTree.InsertAsPreviousSibling(inString: String;

inNode: TTreeNode):TTReeNode;

{功能:为当前节点插入一个前导的兄弟节点

入口参数:inString: String为节点编号为待插入节点的字符串

inNode: TTreeNode,当前节点

}

begin

Result:=Items.AddChildFirst(inNode,inString);

end;

end.