• 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.

  • 相关阅读:
    IIS配置和发布网站
    单点登录的理论原理(一)
    Tomcat乱码或异常
    浅谈Tomcat 、Apache、 Nginx的区别及优缺点
    KETTLE数据互交
    Centos7防火墙配置
    【linux】查看某个进程PID对应的文件句柄数量,查看某个进程当前使用的文件句柄数量
    this license XXXXXX has been cancelled
    Ubuntu16.04安装Redis
    redis的 rdb 和 aof 持久化的区别
  • 原文地址:https://www.cnblogs.com/jijm123/p/12874129.html
Copyright © 2020-2023  润新知