在数据库内有N条数据(1千<N<10万),小弟必须按关系将他们放进一个TreeView内,数据的格式如下:
-------------------
ID | Title |  Ref |
1     aa       
3     bb     1
4     cc     1,3
7     dd      
8     ee     7 
12    ff     7,8
15    gg     7,8,12
-------------------
说明:ID是唯一的,但却不连续。Ref的值,表示是对应ID的子数据。即如果Ref为空,则是一个最顶层节点,有一个数字就是下一层,有两个数字就是第三层,如此类推。
上述的数据放到TreeView就是如下:
aa
|_bb
  |_cc
dd
|_ee
  |_ff
    |_gg
请问怎样可以做到呢?请各位大哥帮帮忙啦!

解决方案 »

  1.   

    Ref 应该只存父亲,而不是存所有祖先,
    递归取得就可以了,
    参考如下代码
    procedure TClsRightManager.Dataset2TreeView(aDtst: TDataset; aTreeView: TRzCheckTree;
        aImgLst: TImageList; const ImgInx: ArrayBooleanOfInteger;
        const RightableFieldValue: ArrayBooleanOfString;
        const RightableField: string;
        const TextField: string;
        const ParentField: string;
        const IdField: string);    function GetRecordInfo(const Id: string): PArrayString;
        var
            i, IdInx: integer;
            Finded: Boolean;
        begin
            with aDtst do
            begin
                IdInx := FieldDefs.IndexOf(IdField);
                Finded := Fields[IdInx].AsString = Id;            if not Finded then
                begin
                    First;
                    while not Eof do
                    begin
                        Finded := Fields[IdInx].AsString = Id;
                        if Finded then break;
                        Next;
                    end;
                end;
            end;        if Finded then
            begin
                New(Result);
                SetLength(Result^, aDtst.FieldCount);
                for i := 0 to aDtst.FieldCount - 1 do
                    Result^[i] := aDtst.Fields.Fields[i].AsString;
            end;        if not Finded then
                raise Exception.Create('没有找到该id的TTreeNode!!!');
        end;
    {-----------------------------------------------------------------------------
      Procedure: GetRootNode
      Author:    javad
      Date:      02-三月-2004
      Arguments: None
      Result:    TTreeNode
        得到RootNode;有两种情况,
            1.表有外键:存在aParentField和IdField值相同的记录,即外键指向本记录的记录
            2.表没有外键:这种情况将寻找IdField值为空(StringField)或0(IntegerField)的记录作为根节点
            将优先采取第1种方式来进行查找-----------------------------------------------------------------------------}
        function GetRootNode: TTreeNode;
        var
            Finded: Boolean;
        begin
            Result := nil;
            //查找记录        //根据第1种情况
            with aDtst do
            begin
                First;
                while not Eof do
                begin
                    if FieldByName(ParentField).AsString = FieldByName(IdField).AsString then
                    begin
                        Finded := True;
                        break;
                    end;
                    Next;
                end;
            end;        //根据第2种情况
            if not Finded then
            begin
                with aDtst do
                begin
                    First;
                    while not Eof do
                    begin
                        if (FieldByName(IdField).AsString = '') or
                            (FieldByName(IdField).AsString = '0') then
                        begin
                            Finded := True;
                            break;
                        end;
                        Next;
                    end;
                end;
            end;        //创建RootNode
            if Finded then
                Result := aTreeView.Items.AddChildObject(nil,
                    aDtst.FieldByName(TextField).AsString,
                    GetRecordInfo(aDtst.FieldByName(IdField).AsString));        if Result = nil then
                raise Exception.Create('没有找到符合规则的根节点记录!!!');
        end;    function FindNode(const Id: string): TTreeNode;
        var
            i: integer;
            tmp: ArrayString;
        begin
            Result := nil;
            with aTreeView do
                for i := 0 to Items.Count - 1 do
                begin
                    tmp := PArrayString(Items[i].Data)^;
                    if Length(tmp) = 0 then continue;
                    if tmp[aDtst.FieldDefs.IndexOf(IdField)] = Id then
                    begin
                        result := Items[i];
                        break;
                    end;
                end;
        end;    function GetNode(const Id: string; const Text: string): TTreeNode;        function GetFieldValue(const Id: string; const FieldName: string): string;
            var
                IdInx, FieldInx: integer;
            begin
                IdInx := aDtst.FieldDefs.IndexOf(IdField);
                FieldInx := aDtst.FieldDefs.IndexOf(FieldName);
                Result := '';
                with aDtst do
                begin
                    if Fields[IdInx].AsString = Id then
                    begin
                        Result := Fields[FieldInx].AsString;
                        exit;
                    end;
                    First;
                    while not Eof do
                    begin
                        if Fields[IdInx].AsString = Id then
                        begin
                            Result := Fields[FieldInx].AsString;
                            break;
                        end;
                        Next;
                    end;
                end;
            end;
        begin
            Result := FindNode(Id);
            if Result = nil then
                Result := aTreeView.Items.AddChildObject(
                    GetNode(GetFieldValue(Id, ParentField), GetFieldValue(Id, TextField)),
                    Text, GetRecordInfo(Id));
        end;var
        I: integer;
        ModuleList: TStringList;
        tmpNode: TTreeNode;
    begin
        Assert((aDtst <> nil) and
            (aTreeView <> nil) and
            (Trim(TextField) <> '') and
            (Trim(ParentField) <> '') and
            (Trim(IdField) <> ''),
            '传入参数错误!!!');
        //清除原有节点
        aTreeView.Images := aImgLst;
        aTreeView.Items.Clear;    ModuleList := TStringList.Create;
        aDtst.DisableControls;
        try
            with aDtst do
            begin
                First;
                while not Eof do
                begin
                    ModuleList.Add(FindField(IdField).AsString + '=' + FindField(TextField).AsString);
                    Next;
                end;
            end;        GetRootNode.ImageIndex := ImgInx[True];
            with ModuleList do
                for i := 0 to Count - 1 do
                begin
                    tmpNode := GetNode(Names[i], Values[Names[i]]);
                    if PArrayString(tmpNode.Data)^[aDtst.FieldDefs.IndexOf(RightableField)] = RightableFieldValue[True] then
                    begin
                        tmpNode.ImageIndex := ImgInx[True];
                        tmpNode.SelectedIndex := ImgInx[True];
                    end
                    else
                    begin
                        tmpNode.ImageIndex := ImgInx[False];
                        tmpNode.SelectedIndex := ImgInx[False];
                    end;
                end;        aTreeView.Items.GetFirstNode.Expand(False);
        finally
            aDtst.EnableControls;
            ModuleList.Free;
        end;
    end;
      

  2.   

    小弟只是奉命行事,无奈ing~~!
      

  3.   

    unit TreeFillThrd;interfaceuses
      Classes, ComCtrls, ADODB, SysUtils;type
      TNodeData = record
        Index: integer;
        Caption: string;
      end;
      PNodeData = ^TNodeData;
      TTreeFill = class(TThread)
        TV: TTreeView;
        TableName: string;
        FieldIndex: string;
        FieldPID: string;
        FieldCaption: string;
        RootText: string;
        Conn: TADOConnection;
        Ptr: PNodeData;
        constructor Create(ATreeView: TTreeView; AConn: TADOConnection;
          ATable: string; ARootText: string = '我的目录';
          AFieldIndex: string = 'ID'; AFieldPID: string = 'PID';
          AFieldCaption: string = 'Caption');
      private
        procedure AddTree(Node: TTreeNode; PN: PNodeData);
      protected
        procedure Execute; override;
      end;implementation
    //------------------------------------------------------------------------------
    constructor TTreeFill.Create(ATreeView: TTreeView; AConn: TADOConnection;
      ATable: string; ARootText: string = '我的目录';
      AFieldIndex: string = 'ID'; AFieldPID: string = 'PID';
      AFieldCaption: string = 'Caption');
    begin
      FieldIndex := AFieldIndex;
      FieldPID := AFieldPID;
      FieldCaption := AFieldCaption;
      TV := ATreeView;
      TableName := ATable;
      RootText := ARootText;
      Conn := AConn;
      New(Ptr);
      inherited Create(False);
    end;
    //------------------------------------------------------------------------------
    procedure TTreeFill.Execute;
    var
      Node: TTreeNode;
    begin
      FreeOnTerminate := True;
      TV.Items.Clear;
      Ptr^.Index := 0;
      Ptr^.Caption := RootText;
      Node := TV.Items.AddObject(nil, RootText, Ptr);
      Node.ImageIndex := 0;
      Node.SelectedIndex := 0;
      AddTree(Node, Ptr);
      TV.FullExpand;
    end;
    //------------------------------------------------------------------------------
    procedure TTreeFill.AddTree(Node: TTreeNode; PN: PNodeData);
    var Query: TADOQuery;
      nNode: TTreeNode;
      PNode: PNodeData;
    begin
      try
        Query := TADOQuery.Create(nil);
        Query.Connection := Conn;
        Query.SQL.Text := 'Select * from ' + TableName + ' where ' + FieldPID + ' =' + IntToStr(PN^.Index);
        if not Query.Active then
          //Query.Close;
        Query.Active:=true;
        while Query.Eof = False do
        begin
          New(PNode);
          PNode^.Caption := Query.FieldByName(FieldCaption).AsString;
          PNode^.Index := Query.FieldByName(FieldIndex).AsInteger;
          nNode := TV.Items.AddChildObject(Node, PNode^.Caption, PNode);
          nNode.ImageIndex := 1;
          nNode.SelectedIndex := 2;
          AddTree(nNode, PNode);
          Query.Next;
        end;
      finally
        Query.Free;
      end;
    end;
    //------------------------------------------------------------------------------
    end.ID | pid |  Ref |
      

  4.   

    对,ref只能存父,这样更简单,例如4 cc 3,这样做对树的查询有麻烦,如果说是最下层的结点要得到最高层的父结点的ID,就很麻烦,其实建立树还可以采取编码的方式,例如:
    aa 10
    bb 1001 
    cc 100101 
    dd 20 
    ee 2001 
    ff 200101
      

  5.   

    感觉你这样做不是很好,很麻烦
    你可以这样做
    ID | Title |  Ref |
    1    aa       -1
    3    bb       -1
    4    cc       1
    5    dd       3  
    6    ee       5
    8    ff       6
    那这样的的关系在TreeView中就很好表示了,-1是根项,id =(4 and 5)的是第二层,
    id =(6)的是第三层, id =(8)的是第四层,
    这样做才是TreeView的标准方式。
      

  6.   

    像你所做的,跟本就没有意义你应该就一层对应一层的,
    比如说你的第四层,没必要把1,2的ID都放进去,
    只要第三层的ID就行了。