已知数据库表结构如下:
aaa(id int,          //序号
    name varchar 15, //名称
    code varchar 20) //编码数据比如:1  江苏  JS
2  南京  JS01
3  鼓楼  JS0101
4  浙江如何根据上面的数据生成一个目录树,要求南京在江苏下面,鼓楼在南京下面,即如根1代码是JS,它的孩子则为JS01,JS02,JS03...,下一层用JS01001或JS01A等,请教如何构造这样的目录树   

解决方案 »

  1.   

    怎么又是这类问题,问的次数太多了
    liangpei2008、zxf_feng,给弄个通用点的,放上来,以后这类问题就别问了
      

  2.   

    通用的咋也写不出来呀,只能凑和写一个:unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, DB, ADODB, StdCtrls, ComCtrls;type
      TForm1 = class(TForm)
        TreeView1: TTreeView;
        Button1: TButton;
        ADOConnection1: TADOConnection;
        ADOQuery1: TADOQuery;
        ADOQuery2: TADOQuery;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
        function getStr(node: TTreeNode;code: String): String;
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    var
      vnode,vnode1: TTreeNode;
    begin
      with adoquery1 do
      begin
        close;
        sql.text := 'select * from aaa where code is null';
        Open;
        while not eof do
        begin
          vnode := treeview1.Items.Add(nil,fieldbyname('name').AsString);
          with adoquery2 do
          begin
            close;
            sql.text := 'select * from aaa where length(code)=2';
            Open;
            while not eof do
            begin
              vnode1 := treeview1.Items.AddChild(vnode,fieldbyname('name').AsString);
              getStr(vnode1,fieldbyname('code').AsString);
              next;
            end;
          end;
          next;
        end;
      end;
    end;function TForm1.getStr(node: TTreeNode;code: String): String;
    var
      adoquery: TadoQuery;
      vnode: TTreeNode;
    begin
      adoquery := TAdoQuery.create(nil);
      try
        adoquery.Connection := adoConnection1;
        with adoquery do
        begin
          close;
          sql.text := ' select * from aaa '+
                      ' where substr(code,1,'+inttostr(length(code))+')='''+code+''''+
                      ' and length(code)='+inttostr(length(code))+'+2';
          Open;
          while not eof do
          begin
            vnode := treeview1.Items.AddChild(node,fieldbyname('name').AsString);
            getStr(vnode,fieldbyname('code').AsString);
            Next;
          end;
        end;
      finally
        adoquery.Free;
      end;
    end;end.
      

  3.   

    create table aaa(id int,          
        name varchar(15), 
        code varchar(20))
        
    insert into aaa values(1,  '江苏',  'JS'); 
    insert into aaa values(2,  '南京',  'JS01'); 
    insert into aaa values(3,  '鼓楼',  'JS0101');
    insert into aaa values(5,  '鼓楼1',  'JS0102');
    insert into aaa values(4,  '浙江', null);
      

  4.   

    谢谢指点,但此处一级目录长度不一定是2,是任意的,级别也是无限制的,

    1  江苏  JS  (说明:CODE长度是变化的,不固定,)
    2  南京  JS01 
    3  鼓楼  JS0101 
    4  浙江  AAA
    5  宁波  AAAA1
    6  宁波下 AAAA1DDD
    7  山东  S
    8  济南  S123
    9  济南1 S123QQ
    请教该如何实现
      

  5.   

    写了一个基本通用的,完全通用真做不到
    调试数据如下:1,"江苏","001"
    2,"南京","001001"
    3,"鼓楼","001001001"
    4,"湖南","002"
    5,"湖北","003"
    6,"长沙","002001"
    7,"株洲","002002"
    8,"湘潭","002003"
    9,"雨湖区","002003001"
    10,"武汉","003001"
    11,"岳塘区","002003002"
    12,"武昌","003001001"
    13,"汉口","003001002"
    14,"汉阳","003001003"procedure Tform1.createtree(ado1:tadoquery;name,code:string;tree:Ttreeview;code_len:integer;maxlevel:integer);
    ado1:数据集
    name:名称的字段名
    code:代码的字段名
    tree:treeview
    code_len:每一级使用的代码长度,本例子为3
    maxlevel:可能的最大级数procedure Tform1.createtree(ado1:tadoquery;name,code:string;tree:Ttreeview;code_len:integer;maxlevel:integer);
    var
      cur_level,treeindex:integer;
      current_parent_index:array of integer;
    begin
      setlength(current_parent_index,maxlevel);
      treeindex:=0;       //这个是当前treeview的item的AbsoluteIndex
      ado1.First;
      while not ado1.Eof do
      begin
        if length(ado1.FieldByName(code).AsString)=code_len then
        begin
          tree.Items.Add(nil,ado1.fieldbyname(name).AsString);
          current_parent_index[0]:=treeindex;         //
        end
        else
        begin
          cur_level:=length(ado1.FieldByName(code).AsString) div code_len;  //确定是第几级
          tree.Items.AddChild(tree.Items[current_parent_index[cur_level-2]],ado1.fieldbyname(name).AsString);
          current_parent_index[cur_level-1]:=treeindex;
        end;
        treeindex:=treeindex+1;
        ado1.Next;
      end;
    end;
    procedure TForm1.Button1Click(Sender: TObject);
    var
      treeindex:integer;
      current_parent_index:array[1..15] of integer;
    begin
      adoquery1.Active:=false;
      adoquery1.SQL.Clear;
      adoquery1.SQL.Add('select name,code from test order by code');
      adoquery1.Active:=true;
      createtree(adoquery1,'name','code',treeview1,3,10);
    end;
      

  6.   

    昨天好像有个类似的问题
    参考一下,以前整理的
    递归加载树形列表的过程if arrInfo[k].SuperID = AId then
    这一句判断上下级的改一下 
      

  7.   

    好久没来论坛看看。。正好我以前工作时碰到过类似的问题,写个例子吧。~、// 表和数据如下,假设code不会重复,如果重复,建树时会把相同编码建成
    //  node
    //    node
    //  这种形式了create table dirtable{
      name varchar(15),
      code varchar(20) primary key
    );insert into dirtable values('test1', 'A');
    insert into dirtable values('test2', 'AA1');
    insert into dirtable values('test3', 'AA1b');
    insert into dirtable values('test4', 'AA');
    insert into dirtable values('test5', 'AA2');
    insert into dirtable values('test6', 'ss');
    insert into dirtable values('test7', 'ss333');
    insert into dirtable values('test8', 'ss333444');
    insert into dirtable values('test9', 'bb');
    insert into dirtable values('test10', 'c');
    insert into dirtable values('test11', 'bbc');
    insert into dirtable values('test12', 'cbb');
    insert into dirtable values('test13', 'b');代码如下
    unit MainForm;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ComCtrls, DB, ADODB;type
      TDirTreeBuilder = class
      private
        FTreeNodes: TTreeNodes;
        FSortedList: TStringList;    procedure BuildSortedList(ACodeList: TStrings);
        function CompareTextHeader(const AStr, ASubStr: string): Boolean;
        function GetParentNode(AParentList: TStrings; const ACode: string): TTreeNode;
      public
        constructor Create;
        destructor Destroy; override;
        
        procedure BuildTree(ATreeNodes: TTreeNodes; ACodeList: TStrings);
      end;  TForm1 = class(TForm)
        TreeView: TTreeView;
        TreeButton: TButton;
        ADOConnection1: TADOConnection;
        procedure TreeButtonClick(Sender: TObject);
      private
        { Private declarations }
        procedure BuildTree(CodeList, NameList: TStrings);
      public
        { Public declarations }
      end;
      
    var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.TreeButtonClick(Sender: TObject);
    var
      Query: TADOQuery;
      NameList, CodeList: TStringList;
    begin
      Query := TADOQuery.Create(Self);
      NameList := TStringList.Create;
      CodeList := TStringList.Create;
      try
        Query.Connection := ADOConnection1;
        // 一次性把所有记录查询出来
        Query.SQL.Clear;
        Query.SQL.Add('select code, name from dirtable');
        Query.Open;
        try
          Query.First;
          while not Query.Eof do
          begin
            NameList.Insert(CodeList.Add(Query.Fields[0].AsString), Query.Fields[1].AsString);
            Query.Next;
          end;      // 建树
          BuildTree(CodeList, NameList);    finally
          Query.Close;
          Query.SQL.Clear;
        end;
      finally
        Query.Free;
        NameList.Free;
        CodeList.Free;
      end;
    end;procedure TForm1.BuildTree(CodeList, NameList: TStrings);
    var
      Obj: TDirTreeBuilder;
    begin
      TreeView.Items.BeginUpdate;
      Obj := TDirTreeBuilder.Create;
      try
        Obj.BuildTree(TreeView.Items, CodeList);    // 把名称添加到节点名称中
        // ...
      finally
        Obj.Free;
        TreeView.Items.EndUpdate;
      end;
    end;{ TDirTreeBuilder }procedure TDirTreeBuilder.BuildSortedList(ACodeList: TStrings);
    var
      I: Integer;
    begin
      // code列表排序
      FSortedList.Clear;
      for I := 0 to ACodeList.Count - 1 do
      begin
        FSortedList.AddObject(ACodeList[I], TObject(I));
      end;     
    end;procedure TDirTreeBuilder.BuildTree(ATreeNodes: TTreeNodes;
      ACodeList: TStrings);
    var
      ParentCodeList: TStrings;
      I: Integer;
      PNode, Node: TTreeNode;
    begin
      ATreeNodes.BeginUpdate;
      try
        ATreeNodes.Clear;
        FTreeNodes := ATreeNodes;    BuildSortedList(ACodeList);
        ParentCodeList := TStringList.Create;
        try
          ParentCodeList.Clear;
          for I := 0 to FSortedList.Count - 1 do
          begin
            PNode := GetParentNode(ParentCodeList, FSortedList[I]);        Node := FTreeNodes.AddChild(PNode, FSortedList[I]);
            // 原始codelist列表中对应的索引值
            Node.Data := FSortedList.Objects[I];        // 添加到父节点列表
            ParentCodeList.AddObject(FSortedList[I], Node);
          end;
        finally
          ParentCodeList.Free;
          FSortedList.Clear;
        end;
      finally
        ATreeNodes.EndUpdate;
      end;
    end;function TDirTreeBuilder.CompareTextHeader(const AStr, ASubStr: string): Boolean;
    var
      I: Integer;
      S: string;
    begin
      Result := False;
      // 目标串为空时也返回false
      if (Length(AStr) < Length(ASubStr)) or (Length(ASubStr) = 0) then Exit;  // 比较时忽略大小写
      S := Copy(AStr, 1, Length(ASubStr));
      Result := CompareText(S, ASubStr) = 0;    
    end;constructor TDirTreeBuilder.Create;
    begin
      FSortedList := TStringList.Create;
      FSortedList.Sorted := True;
    end;destructor TDirTreeBuilder.Destroy;
    begin
      FSortedList.Free;
      inherited;
    end;function TDirTreeBuilder.GetParentNode(AParentList: TStrings;
      const ACode: string): TTreeNode;
    var
      I: Integer;
    begin
      Result := nil;
      //  查找父节点,在parentlist中倒序查找,
      //  如果acode开是以AParentList[I]开头的话,acode的父节点
      //  就是AParentList[I]
      for I := AParentList.Count - 1 downto 0 do
      begin
        if CompareTextHeader(ACode, AParentList[I]) then
        begin
          Result := TTreeNode(AParentList.Objects[I]);
          Exit;
        end;
        // 如果不是上级节点,则从父节点列表中去掉
        AParentList.Delete(I);
      end;
    end;end.//建出树形如下
    A
      AA 
        AA1
           AA1b
        AA2
    b
     bb
       bbc
    c
     cbb
    ss
      ss333
         ss333444 
      

  8.   

    //建出树形如下 

      AA 
        AA1 
          AA1b 
        AA2 

      bb 这个地方空格忘加了
        bbc 

      cbb  这个地方空格忘加了
    ss 
      ss333 
        ss333444 
      

  9.   

    结贴,这种排序的关键是有顺序的,这种排列查询出以CODE增序排列,按logne的方法才能达到这个效果,如果顺序错乱,就全乱了,至于顺序错乱也能排出,不知是否有方法也能做到。