表DeptInfo:
   Code    SubCode   (字段)
    A        C
    A        E
    B        D
    B        F
    C        G
    D        H    其中,Code是SubCode的上级部门。   上述表用TREEVIEW显示如下:
        ___    
    A--|    C--G
    |  |___ E
    |
    B--|--  D-H
       | 
       ---- F      请问用什么算法让数据更快更好的加载到TREEVIEW来呢?
   100分相送,决不食言!!!
   (有代码最好!)

解决方案 »

  1.   

    你可以加一个selfcode保存自已的结点号,最深处的如A,B,自己的结点号为0,加载的时候先选出结点号为0的用TREEVIEW的ADD(NIL,‘A’)的ADD(NIL,‘B’)加上即可,之后选中第一个,tnode:=treeview.items[0].text;然后查找它的SubCode,将其加载为自己的下结点:即tnode.addchild();然后tnode:=tnode.getnext.这样直到你加完最后一个结点
      

  2.   

    谢谢 yhq2002(yhq) 
       可是我发觉陷入一个递归陷阱,光是一级一级找部门级别层次都很累了
    如何解决这个问题呢?
      

  3.   

    怎么会呢。我这么做了,没有错啊,tnode:=tnode.getnext,用一循环做,应该没问题吧
      

  4.   

    用SQL就可以解决这样的问题那还要Delphi干嘛?好老说,你这个数据库的设计也有问题,如果把你的SubCode改为UpCode就要好作多了。当然,象你这样也可以作的,不过要多一个Query
    先用一个RootQry:TADOQuery来取第一级部门SQL象这样
    select * from DepInfo where not code in (select SubCode from DepInfo)
    用一个DetailQry:TADOQuery来Select * from DepInfo然后再用递归生成树---绝对累不死CPU,除非你程序有死循环!也不应该很慢!!大体如下:
    var
      ANode:TTreeNode;
    begin
    RootQry.First;
    while not RootQry.Eof do
    begin
      ANode:=TreeView.Items.Add(nil,RootQry.FieldByName('Code').AsString);
      CreateChild(ANode);  
      RootQry.Next;
    end;
    procedure CreateChild(FNode:TTreeNode);
    var
      BookMark:String;
      ANode:TTreeNode;
    begin
      DetailQry.First;
      While Not DetailQry.Eof do
      begin
        if DetailQry.FieldByName('Code').AsString=FNode.Text then
        begin
          ANode:=TreeView.Items.AddChild(FNode,
                                         DetailQry.FieldByName('SubCode').AsString);
          Book:=DetailQry.Book;
          CreateChild(ANode);//此处递归!!
          DetailQry.Book:=Book;  
        end;
        DetailQry.Next;
      end;
      DetailQry.
    end;
      

  5.   

    在你的表中加两条记录 0 A  0 B
    procedure InitTreeView(TreeNode:TTreeNode;Key:String);
    var
      TN:TTreeNode;
      s_ADOQuery:TADOQuery;
    begin
      s_ADOQuery:=TADOQuery.Create(self);
      s_ADOQuery.Connection:=ADOConnection1;
      s_ADOQuery.Close;
      s_ADOQuery.SQL.Clear;
      s_ADOQuery.SQL.Text:='select code,subcode from deptinfo where code='+Quotedstr(key);
      s_ADOQuery.Open;
      if not s_ADOQuery.IsEmpty then
        begin
          while not s_ADOQuery.Eof do
            begin
              TN:=Treeview1.Items.AddChild(TreeNode,s_ADOQuery.fieldbyname('subcode').AsString);
              InitTreeView(TN,s_ADOQuery.fieldbyname('subcode').AsString);
              s_ADOQuery.Next;
            end;
        end;
    end;procedure TForm1.Button1Click(Sender: TOBject);
    begin
      InitTreeView(nil,'0');
    end;
      

  6.   

    function TForm1.FindNode(TreeView:TTreeView;text:string):TTreeNode;
    var i,j:integer;
    begin
      result:=nil;
      j:=treeview.Items.Count;
      for i:=0 to j-1 do
      begin
        if treeview.Items[i].Text=text then
        begin
          result:=treeview.Items[i];
          exit;
        end;
      end;
    end;procedure TForm1.MoveChildNode(TreeView:TTreeView;DestNode:TTreeNode;SourNode:TTreeNode);
    var tn1,tn2:TTreeNode;
    begin
      tn1:=nil;
      tn2:=nil;
      tn1:=sournode.getFirstChild;
      if tn1<>nil then
      begin
        tn2:=treeview.Items.AddChild(destnode,tn1.Text);
        if tn1.HasChildren then
        begin
          self.MoveChildNode(treeview,tn2,tn1);
        end;
      end;
      tn1:=sournode.GetNextChild(tn1);
      while tn1<>nil do
      begin
        tn2:=treeview.Items.AddChild(destnode,tn1.Text);
        if tn1.HasChildren then
        begin
          self.MoveChildNode(treeview,tn2,tn1);
        end;
        tn1:=sournode.GetNextChild(tn1);
      end;
      tn1:=nil;
      tn2:=nil;
    end;procedure TForm1.Button1Click(Sender: TObject);
    var tn1,tn2,tn3:TTreeNode;i,j:integer;value:string;
    begin
      table1.Open;
      while not table1.Eof do
      begin
        value:=table1.FieldValues['code'];
        tn1:=self.FindNode(self.TreeView1,value);
        if tn1=nil then
        begin
          tn1:=self.TreeView1.Items.Add(nil,value);
        end;
        value:=table1.FieldValues['subcode'];
        tn2:=self.FindNode(self.TreeView1,value);
        if tn2=nil then
        begin
          tn2:=self.TreeView1.Items.AddChild(tn1,value);
        end else
        begin
          tn3:=self.TreeView1.Items.AddChild(tn1,value);
          self.MoveChildNode(self.TreeView1,tn3,tn2);
          tn2.Delete;
        end;
        table1.Next;
      end;
      table1.Close;
    end;
      

  7.   

    如果不在deptinfo中增加记录就用下面的代码,个人觉得加两条记录方便些procedure TForm1.Button1Click(Sender: TOBject);
    var
      m:TTreeNode;
      s_ADOQuery:TADOQuery;
    begin
      s_ADOQuery:=TADOQuery.Create(self);
      s_ADOQuery.Connection:=ADOConnection1;
      s_ADOQuery.Close;
      s_ADOQuery.SQL.Clear;
      s_ADOQuery.SQL.Text:='select distinct(code) from deptinfo where code not in (select distinct(subcode) from deptinfo)';
      s_ADOQuery.Open;
      if not s_ADOQuery.IsEmpty then
        begin
          while not s_ADOQuery.Eof do
            begin
              m:=TreeView1.Items.Add(nil,s_ADOQuery.fieldbyname('code').AsString);
              InitTreeView(m,s_ADOQuery.fieldbyname('code').AsString);
              s_ADOQuery.Next;
            end;
        end;
    end;
      

  8.   

    谢谢blazingfire(烈焰)(正在思考的流浪汉...) 
     不过你的算法出现一个问题,上述数据中,上级代码A出现了两次,B也如此。
     还有C和D也在A和B的同一级。
      

  9.   

    blazingfire(烈焰)(正在思考的流浪汉...) 
    的方法主要在query的指针移动上消耗时间我的方法主要在移动node上消耗时间: bluezwt(蓝色天涯) 
    的方法主要是增加了数据库的连接数量楼主 你都试试看哪个方法快?
      

  10.   

    blazingfire(烈焰)
       你的建议我已经接受了!
      

  11.   

    谢谢bluezwt(蓝色天涯) 
       不过你的方法我好像陷入死循环。
      

  12.   

    谢谢 citytramper(从开始到现在) 
       不过你的方法我也好像陷入死循环。
      

  13.   

    citytramper(从开始到现在):
       blazingfire(烈焰)(正在思考的流浪汉...)的算法快。
    在query的指针移动上消耗时间;肯定要比移动节点上消耗时间少。
       如有不妥请斧正!
      

  14.   

    能不能给我个大一点的数据表让我测试一下
    [email protected]
      

  15.   

    unit DBTrees;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,ComCtrls, DB,StdCtrls;type  TTreeNodeInfo=record
       Id:String;
       ParentId:String;
      end;  TDBTreeView=class(TTreeView)
       private
        fTable:TDataSet;
        fId,fParentId,fName:string;
        function AddItem:TTreeNode;
        function FindItem(Id:string):TTreeNode;
       protected
         procedure Change(Node: TTreeNode); override;
       public
        function GetId:string;
        procedure BuildTree;
        procedure ClearTree;    constructor Create(AOwner:TComponent);override;
        destructor Destroy;override;
       published
        property FieldId:string Read fId Write fId;
        property FieldParentId:string Read fParentId Write fParentId;
        property FieldName:string Read fName Write fName;
        property DataSource:TDataSet Read fTable Write fTable;
        property ActiveId:string Read GetId;
      end;
    procedure Register;implementationfunction TDBTreeView.FindItem(Id:string):TTreeNode;
     var i:integer;
         NodeInfo:^TTreeNodeInfo;
    begin
     Result:=nil;
     For i:=0 to Items.Count-1 do
     begin
      NodeInfo:=Items[i].Data;
      If NodeInfo^.Id=Id then
      begin
       Result:=Items[i];
       Exit;
      end;
     end;
    end;function TDBTreeView.GetId:string;
     var NodeInfo:^TTreeNodeInfo;
    begin
     If Selected=nil then Result:=''
     else
     begin
      NodeInfo:=Selected.Data;
      Result:=NodeInfo^.Id;
     end;
    end;function TDBTreeView.AddItem:TTreeNode;
     var NodeInfo:^TTreeNodeInfo;
         BMark:TBookMark;
         ObjParent:TTreeNode;
         Name,CurId:string;
    begin
     ObjParent:=FindItem(fTable.FieldByName(fId).AsString);
     If ObjParent<>nil then
     begin
      Result:=ObjParent;
      Exit;
     end
     else
     begin
      New(NodeInfo);
      NodeInfo^.Id:=fTable.FieldByName(fId).AsString;
      NodeInfo^.ParentId:=fTable.FieldByName(fParentId).AsString;
      Name:=fTable.FieldByName(fName).AsString;
      If fTable.FieldByName(fParentId).AsString<>'' then
      begin
       ObjParent:=FindItem(Name);
       If ObjParent<>nil then
        Result:=Items.AddChildObject(ObjParent,Name,NodeInfo)
       else
       begin
        CurId:=fTable.FieldByName(fId).AsString;
        If fTable.Locate(fId,fTable.FieldByName(fParentId).AsString,[]) then
        begin
         Result:=Items.AddChildObject(AddItem,Name,NodeInfo);
         fTable.Locate(fId,CurId,[]);
        end
        else
         Result:=Items.AddObject(Selected,Name,NodeInfo);
       end;
      end
      else
      begin
       Result:=Items.AddObject(Selected,Name,NodeInfo);
      end;
     end;
    end;procedure TDBTreeView.BuildTree;
     var ChangeEvent:TTVChangedEvent;
    begin
     If (fTable=nil) or (not fTable.Active) then Exit;
     ChangeEvent:=OnChange;
     OnChange:=nil;
     Items.BeginUpdate;
     ClearTree;
     fTable.First;
     While not fTable.Eof do
     begin
      AddItem;
      fTable.Next;
     end;
     AlphaSort;
     Items.EndUpdate;
     OnChange:=ChangeEvent;
    end;procedure TDBTreeView.ClearTree;
     var NodeInfo:^TTreeNodeInfo;
         i:integer;
    begin
     Items.BeginUpdate;
     for i:=0 to Items.Count-1 do
     begin
      NodeInfo:=items[i].Data;
      Dispose(NodeInfo);
     end;
     While Items.Count>0 do Items.Delete(Items[0]);
     Items.EndUpdate;
    end;procedure Register;
    begin
      RegisterComponents('Data Controls',[TDBTreeView]);
    end;constructor TDBTreeView.Create(AOwner: TComponent);
    begin
      inherited;
    end;destructor TDBTreeView.Destroy;
    begin
      inherited;
    end;
    end.
      

  16.   

    procedure CreateSubTree(FNodeName: string; Node: TTreeNode = nil);
    var  mLocalName: string;
    TreeNode: TTreeNode;
    Ads_Tmp: TADODataSet;
    begin
    ADS_Tmp := TADODataSet.Create(Self);
    ADS_Tmp.Connection := ADOConn;
    with ADS_Tmp do
    begin
       Close;
       CommandText := 'Select * from Type Where ParentID =' + FNodeName;
       Open;
       First;
       while not Eof do
       begin
       mLocalName := FieldbyName('ID').Asstring;
       TreeNode := TreeView.Items.AddChild(Node, FieldByName('Name').AsString);
       CreateSubTree(mLocalName, TreeNode);
       Next;
       end;
      end;
    end;简单的底归!
      

  17.   

    我的代码中的那个ADOQuery必须是动态创建的,不能用固定的
      

  18.   

    我写的ADOQuery不是动态的吗?
    ADS_Tmp := TADODataSet.Create(Self);
    ADS_Tmp.Connection := ADOConn;
      

  19.   

    表DeptInfo:
       Code    parentCode   (字段)
       001     
       002     001
       003     001
       004     002
       005     003
       006     004
    如果用oracle,可以:Select *,level from DeptInfo start with parentCode is null 
    connect by code=parentCode order by code;
                               ^^^^^^^^^^^^^^//可选
    查出:
       Code    parentCode   level
       001                  1
       002     001          2
       004     002          3
       006     004          4
       003     001          2
       005     003          3这就是TreeView中的顺序!遍历一边记录,就可以创建所有节点的。
    (level是虚拟列,自动赋值的,可以不用)