需要实现如下效果:
从数据库中提取数据,结构如下
编码         名称
01          a1
0101        a11
010101      a111
010102      a112
0102        a12
010201      a121
02          a2
0201        a21
020101      a211

想实现如下的树
---A
   |---a1
   |    |---a11
   |    |    |--a111
   |    |  ......... 
   |    |---a12 
   |    .........
   |----a2
......................
请问,应该如何解决?
新手,希望得到帮助。

解决方案 »

  1.   

    先在数据库里找出两位的数据,作为TreeView的根结点,然依次以每一个根结点为前缀后面有两位的数据,找到后加到这个根结点的下面作为它的子节点。这样依次做下去就行了。可能需要用到递归算法的。
      

  2.   

    不明白再问我很不错的
    问题
    父     子       值
     A      B        1
     B      C        1
     B      D        2
     D      E        3
    -------------------
             A
             
             B(1)
          C(1)    D(2)
                    E(3) 
    A有 1 个B,B有 2 个D,D有 3 个E 
    我想算出A有几个E,几个D ,几个B解决方法
    --测试--测试数据
    create table 表(父 char(1),子 char(1),值 int)
    insert 表 select 'A','B',1
    union all select 'B','C',1
    union all select 'B','D',2
    union all select 'D','E',3
    go--存储过程
    create proc p_calc
    @id char(1)='A', --要查询的节点
    @num int=1 --数量
    as
    declare @l int 
    set @l=0
    create table #re(id char(1),level int,num int)
    insert #re select @id,@l,@num
    while @@rowcount>0
    begin
    set @l=@l+1
    insert #re select a.子,@l,num=b.num*a.值
    from 表 a join #re b on a.父=b.id
    where b.level=@l-1
    end
    select id,num=sum(num) from #re group by id
    go
    --调用查询
    exec p_calc
    go
    /*--测试结果
    id   num         
    ---- ----------- 
    A    1
    B    1
    C    1
    D    2
    E    6(所影响的行数为 5 行)
    --*/
      

  3.   

    --创建表
    create table t_test(编码 varchar(20),名称 varchar(20))
    --插入数据
    insert into t_test 
    select '01',          'a1'
    union select '0101',        'a11'
    union select '010101',      'a111'
    union select '010102',      'a112'
    union select '0102',        'a12'
    union select '010201',      'a121'
    union select '02',          'a2'
    union select '0201',        'a21'
    union select '020101',      'a211'
    union select '020102',      'a212'
    union select '02010101',      'a2111'
    union select '0201010101',      'a21111'//delphi程序实现
    //窗体上放 button1,adoconnection1, ADOquery1,TreeView1
    //ADOquery1的connection连接  adoconnection1
    //button1的点击事件里写
    procedure TForm1.Button1Click(Sender: TObject);
    function MakeTree:Boolean;
    var
      nodeCur:TTreeNode;
      sPrt,sCld:String;
      iNodeLenth:Longint;
    begin
      nodeCur:=nil;
      with ADOquery1 do
      try
        Close;
        sql.Clear;
        sql.add('select * from t_test order by 编码');
        Open;
        First;
        while not eof do
        begin
          sPrt:=FieldByName('编码').AsString;
          sCld:=FieldByName('名称').AsString;
          if Length(sPrt)=2 then
          begin
            nodeCur:=TreeView1.Items.AddChild(TreeView1.GetNodeAt(0,0),sCld);
            nodeCur.StateIndex:=StrToInt(sPrt);
          end
          else
          begin
            while nodeCur.StateIndex<>strtoint(copy(sPrt,1,length(sPrt)-2)) do
               nodeCur:=nodeCur.Parent;
            nodeCur:=TreeView1.Items.AddChild(nodeCur,sCld);
            nodeCur.StateIndex:=strtoint(sPrt);
          end;
          Next;
        end;
      except
        showmessage('出错!');
        raise;
      end;
      result:= true;
    end;
    begin
      TreeView1.Items.Clear;
      TreeView1.Items.BeginUpdate;
      TreeView1.Items.AddChild(nil,'A');
      MakeTree;
      TreeView1.Items.EndUpdate ;
      TreeView1.FullExpand;
    end;
      

  4.   

    [email protected]
    谢谢大家,解决就给分
      

  5.   

    procedure TForm1.Button1Click(Sender: TObject);
    var node:TTreeNode;
    begin
      node:=nil;
      with ADOQuery1 do
      begin
        Close;
        Sql.Text:='SELECT * FROM t ORDER BY 编码';
        Open;
        TreeView1.Items.BeginUpdate;
        First;
        try
          while not Eof do
          begin
            Node:=TreeView1.Items.AddChildObject(Node,FieldByName('名称').AsString,Pointer(FieldByName('编码').Asstring));
            Next;
            while (node<>nil) and (Length(FieldByName('编码').AsString)<=Length(string(Node.Data))) do
            node:=node.Parent;
          end;
        finally
          TreeView1.Items.EndUpdate;
        end;
        TreeView1.FullExpand;
      end;
    end;
      

  6.   

    一次生成树对于数据量小没有问题,
    但是如果数据量大的话,采用上面的速度将很慢,
    因此建议动态的生成树,在TTreeView的OnExpanded生成子节点,
    在TTreeView的在OnCollapsed
    这样程序性能要提高
      

  7.   

    你用Dev Express(开发快车)的组件:
    有一个TdxDBTreeView,可以直接连到数据库的表,设置几个参数就可以把表中的数据取出生成树了。
      

  8.   

    我也是新手,才遇到过你的问题,不过只有01、0101、0102、……02、0201、0202、……03……等反正只有两层,我是从数据库表中一条一条读出来,可能效率不高,但几百条速度也可以,你可以参考一下。不过这不是好的算法,与编码格式长度有关,可能楼上huamanlouzcj() 的思路更好些。等弄完最近手头的事情再看看更好的算法。这里dm_main是数据模块的name,adst_d是数据模块里一个adodataset的名字,连接数据库里infrm表。
    procedure tfrm1.refreshTree;
    var
      level0,level1,level2:Ttreenode;
      id,name:string;
    begin
       infoTree.Items.Clear;
      dm_main.ADST_D.Close;
      dm_main.ADST_D.CommandText :='select * from infrm';
      dm_main.ADST_D.Open;
       level0:=infoTree.Items.Add(infotree.TopItem,'列表');
       level0.DeleteChildren ;
       try
          dm_main.ADST_d.IndexFieldNames :='ID';//这句很重要,如果你没设主键,
                                              //这里首先按编码排一下序,再一条条读
          dm_main.ADST_d.Open ;
          dm_main.ADST_d.First;
          while not dm_main.ADST_d.Eof do
           begin
              id:=trim(dm_main.ADST_dID.AsString);
              name:=trim(dm_main.ADST_dName.asstring);
              //添加第一级
              if length(trim(id))=2  then            
                   level1:=infotree.Items.AddChild(level0,'('+id+')'+name);                
              //添加第二级
              if length(trim(id))=4 then
                   level2:=infotree.Items.AddChild(level1,'('+id+')'+name);               
              dm_main.ADST_d.next;
           end;
       except
          showmessage('asdasdfsdfsdf');
       end;
       dm_main.ADST_d.close;
       level0.Expand(false);
    end;
      

  9.   

    谢谢大家的合作,希望能够找出最好的算法来解决这个问题,控件嘛,就不用第三方了。
    如果大家感到分数不够,我可以另外开帖补足分数。
    另 huamanlouzcj() ,能否详细说明一下,偶不是很明白。
      

  10.   

    你如果用sql server 的话,用一个adostoredproc与存储过程相连,然后根据字段level进行判断,level就是代表treeview的层次深度!
      另存储过程的最后一句改为以下:
     select id,level,num=sum(num) from #re group by id,level
    这样不就可以了吗?
    以上是一次读取其全部BOM的展开树,
    如果数据量很大,则可以在treeview的oncustomdrawitem事件中写。一次只读一层。
    不用递归算法啊!
      

  11.   

    另你的表的结构能不能改一改,如下,
    分为两张表,其中一张表用来储存基本代码表,另外一张表用来表示其隶属关系。如下 :
     表1                          表2
      编码  名称                子      父  
      01     a1                02      01
      02     a2                03      01
      03     a3                04      01
      04     a4                05      02
      05     a5其树如下:
     --a1
       |--a2
          |--a5
       |--a3
       |--a4
    然后再利用我上面提到的思路!这样可以不受编码长度的限制!