至少你应该在表中有个字段表示开始结点啊?
var Node,ChildNode: TTreeNode;   with TreeView do
   begin
     Items.Clear;
     Query1.Close;
     Query1.Sql.Text := 'SELECT * FROM tbTree WHERE .....'; //取第一层
     Query1.Open;
     while not Query1.Eof do
     begin
       Node := Items.AddChild(nil,Query1.FieldByName('TreeName').AsString);
       Query2.Close;
       Query2.Sql.Text := 'SELECT * FROM tbTree WHERE UpperTreeID='''+Query1.FieldByName('TreeID')+'''';
       Query2.Open;
       while not Query2.Eof do
       begin
         DepNode := Items.AddChild(UnitNode,Query2.FieldByName('TreeName').AsString);
         Query2.Next;   
       end;
       Query1.Next;  
     end;
   end;

解决方案 »

  1.   

    代码会比较麻烦,哪怕是仅仅显示数据库用dbTreeview吧
      

  2.   

    至少你应该在表中有个字段表示开始结点啊?
    var Node,ChildNode: TTreeNode;   with TreeView do
       begin
         Items.Clear;
         Query1.Close;
         Query1.Sql.Text := 'SELECT * FROM tbTree WHERE .....'; //取第一层
         Query1.Open;
         while not Query1.Eof do
         begin
           Node := Items.AddChild(nil,Query1.FieldByName('TreeName').AsString);
           Query2.Close;
           Query2.Sql.Text := 'SELECT * FROM tbTree WHERE UpperTreeID='''+Query1.FieldByName('TreeID')+'''';
           Query2.Open;
           while not Query2.Eof do
           begin
             ChildNode := Items.AddChild(Node,Query2.FieldByName('TreeName').AsString);
             Query2.Next;   
           end;
           Query1.Next;  
         end;
       end;
      

  3.   

    DBTree 控件你可以看看带Source
      

  4.   

    说明: 根节点 UpperTreeId=NULLgenphone_ru(票票):
      你这样好像不可以,只能搜索出第二层来,第三层以后就搜索不出了。
     
    laoZheng(阿明):
      我现在只是想知道treeview是怎么和数据库联系起来的。
      

  5.   

    DBTree的源代码:unit dbTree;{ TDBTreeView component: Data-Aware TTreeView component.
      Version 0.82  Aug-10-1997  (C) 1997 Christoph R. Kirchner
      !! This component is currently UNDER CONSTRUCTION !!
    }
    { Users of this unit must accept this disclaimer of warranty:
        "This unit is supplied as is. The author disclaims all warranties,
        expressed or implied, including, without limitation, the warranties
        of merchantability and of fitness for any purpose.
        The author assumes no liability for damages, direct or
        consequential, which may result from the use of this unit."  This Unit is donated to the public as public domain.  This Unit can be freely used and distributed in commercial and
      private environments provided this notice is not modified in any way.  If you do find this Unit handy and you feel guilty for using such a
      great product without paying someone - sorry :-)  Please forward any comments or suggestions to Christoph Kirchner at:
      [email protected]  Maybe you can find an update of this component at my
      "Delphi Component Building Site":
      http://www.geocities.com/SiliconValley/Heights/7874/delphi.htm  Thanks to Maxim Monin for his TDBOutline-component I could start with.
    }
    interfaceuses
      SysUtils, Windows, Messages, Classes, Graphics, Controls,
      CommCtrl, Dialogs, BDE, Dbconsts, DB, DBTables, StdCtrls, ComCtrls,
      TreeVwEx, ECDataLink, dbTvRecordList;type  TCustomDBTreeView = class;  TDBTreeOption = (
        dtAllowDelete, dtAllowInsert, dtAutoDragMove, dtAutoExpand,
        dtAutoShowRoot, dtCancelOnExit, dtConfirmDelete, dtFocusOnEdit,
        dtInsertAsChild, dtMouseMoveSelect, dtRebuildFocusedOnly,
        dtRootItemReadOnly, dtSynchronizeDataSet);
      TDBTreeOptions = set of TDBTreeOption;{ Options:  dtAutoDragMove:
        The user can move items by dragging them in the DBTreeView.
        The parent-field of the record of the moved item will be set to the
        ID of the new parent automatically.  dtAutoExpand:
        The tree will get expanded completely after building.  dtAutoShowRoot:
        The ShowRoot property specifies whether lines connecting root (top-
        level) items are displayed. If dtAutoShowRoot is in Options, the
        DBTreeView will set the ShowRoot property itself, depending on the
        numbers of root-items: If are more then one of them, the DBTreeView
        will set the ShowRoot property to True, otherwise it will set the
        ShowRoot property to False.
        ShowRoot = True will show lines connecting the root items if the
        ShowLines property is True, and If ShowButtons is set to True, a
        button will appear to the left of each root item.  dtCancelOnExit:
        An insertion-operation get canceled if the user leaves the DbTreeView
        without changing the inserted record. This avoids empty records in the
        table. DtCancelOnExit is similar to dgCancelOnExit of TDBGrid.  dtConfirmDelete:
        The user gets asked if he really want to delete the current record
        after he pressed the Del-key. If the current record has children, the
        user gets asked if he want to delete them first.  dtFocusOnEdit:
        If the dataset changes to edit- or insert-mode, the DbTreeView will
        get the focus. This allows to user to edit the tree-node directly
        after pressing edit or insert on a navigation-button. Also, if the
        dateaset is in edit- or insert-mode and the DbTreeView receives the
        focus, the selected node goes into the edit-mode. Please do not set
        dtFocusOnEdit if there is TDBEdit, TDBMemo or TDBGrid on the form
        connected to the same dataset - the user could get confused too much.
        Also, please set dtSynchronizeDataSet too if you use dtFocusOnEdit.
        Setting dtFocusOnEdit is recommended if there is - more or less -
        only a DbTreeView and a DBNavigator on the form.  dtInsertAsChild:
        The new item that is created by pressing the insert key gets
        inserted after the selected node if tveInsertAsChild is false or
        it gets inserted as a child of the selected node if tveInsertAsChild
        is true.  dtMouseMoveSelect:
        If the user moves the mouse, the nearest node gets selected.
        If the user moves the mouse to the upper or lower border of the
        DbTreeView while left button pressed, the DbTreeView will scroll.
        This scrolling happens anyway if the user drags a node.
        The option dtMouseMoveSelect makes sense if the DbTreeView is shown
        in a dropdown-panel.  dtRebuildFocusedOnly:
        If dtRebuildFocusedOnly is in Options, the DbTreeView will not
        rebuild the tree after the dataset changed unless the DbTreeView gets
        the focus. This is not set by default. The TDbTreeLookupComboBox uses
        this option to avoid needless rebuilds of the DbTreeView in the drop-
        down-panel until it gets visible.  dtRootItemReadOnly:
        If there is a record in the dataset with the ID of RootID, then you
        can set it to read-only by setting RootItemReadOnly to true.  dtSynchronizeDataSet:
        The current selected treenode will always represent the current record
        of the DataSet. If not dtSynchronizeDataSet in Options, selecting
        treenodes gets faster.
      }  TDBTVGetNextIDEvent =
        function (Sender: TObject; DataSet: TDataSet): string of object;  TTVFindTextOption = (tvftCaseInsensitive, tvftPartial);
      TTVFindTextOptions = set of TTVFindTextOption;  TDBTreeViewState = (
        dtvsBuilding, dtvsDatasetInEditMode, dtvsEditAfterReBuild,
        dtvsDatasetInInsertMode, dtvsLostFocusWhileDatasetInEditModes,
        dtvsChangingDataset, dtvsNeedReBuildAfterPost, dtvsNeedReBuild,
        dtvsDataSetNeedsRefresh);
      TDBTreeViewStates = set of TDBTreeViewState;
      

  6.   

    TTreeViewLink = class(TECDataLink)
      private
        FTreeView: TCustomDBTreeView;
      protected
        procedure DatasetRefreshed; override;
        procedure ActiveChanged; override;
        procedure DataSetChanged; override;
        procedure DataSetScrolled(Distance: Integer); override;
        procedure RecordChanged(Field: TField); override;
        procedure EditingChanged; override;
      { procedure UpdateData; override; }
        procedure DoBeforePost(DataSet: TDataSet); override;
        procedure DoAfterPost(DataSet: TDataSet); override;
        procedure DoAfterCancel(DataSet: TDataSet); override;
        procedure DoBeforeDelete(DataSet: TDataSet); override;
        procedure DoAfterDelete(DataSet: TDataSet); override;
        procedure DoBeforeEdit(DataSet: TDataSet); override;
        procedure DoBeforeInsert(DataSet: TDataSet); override;
      public
        constructor Create(ATreeView: TCustomDBTreeView);
      end;  TTreeIDNode = class(TTreeNode)
      private
        FID: string;
      public
        constructor Create(AOwner: TTreeNodes);
        procedure Assign(Source: TPersistent); override;
        property ID: string read FID write FID;
      end;  TCustomDBTreeView = class(TCustomTreeViewEx)
      private
        FOptions: TDBTreeOptions;
        FUserOnEdited: TTVEditedEvent;
        FTreeViewLink: TTreeViewLink;
        FTableIDField: string;
        FTableParentField: string;
        FTableTextField: string;
        FRootID: string;
        FOnClosedLoop: TNotifyEvent;
        FOnRootNotFound: TNotifyEvent;
        FPrevState: TDataSetState;
        FDelRootID: string;
        FIDOfDeleted: string;
        FState: TDBTreeViewStates;
        FTVRecordList: TTVRecordList;
        FReBuildTimer: Longint;
        FOnGetNextID: TDBTVGetNextIDEvent;
        function  GetDataSource: TDataSource;
        procedure SetDataSource(ADataSource: TDataSource);
        procedure SetTableIDField(const Value: string);
        procedure SetTableParentField(const Value: string);
        procedure SetTableTextField(const Value: string);
        function  GetDataSet: TDataSet;
        procedure SetRootID(ID: string);
        procedure SetOptions(Value: TDBTreeOptions);
        function CreateTVRecordList: TTVRecordList;
        function  NeedRebuild: Boolean;
        procedure CreateTree(ParentNode: TTreeNode;
          const AParent: string; TempRecordList: TTVRecordList);
        function  AddNewNodeFromDataset(
          Node: TTreeNode; AsChild: Boolean): TTreeNode;
        function  GetDataSetIDNode: TTreeNode;
        function  GetID(AIndex: Integer): string;
        function  GetSelectedID: string;
        procedure SelectID(const Value: string);
        procedure IndexChanged;
        procedure AfterEdit(Sender: TObject; Node: TTreeNode; var S: string);
        procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
        procedure WMSetFocus(var Message: TMessage); message WM_SETFOCUS;
        procedure WMTimer(var Msg: TWMTimer); message WM_TIMER;
      protected
        function CreateNode: TTreeNode; override;
        function CanEdit(Node: TTreeNode): Boolean; override;
        procedure Edit(const Item: TTVItem); override;
        procedure Change(Node: TTreeNode); override;
        procedure Expand(Node: TTreeNode); override;
        procedure KeyDown(var Key: Word; Shift: TShiftState); override;
        procedure Notification(AComponent: TComponent;
                               Operation: TOperation); override;
      

  7.   

    procedure KillAllTimer; override;
        function DragAllowed(Node: TTreeNode): Boolean; override;
        procedure ActiveChanged(Value: Boolean);
        procedure DataChanged;
        procedure RecordNumberChanged;
        procedure RecordChanged(Field: TField);
        procedure EditingChanged;
        procedure DataSetBeforePost;
        procedure DataSetAfterPost;
        procedure DataSetAfterCancel;
        procedure DataSetBeforeDelete;
        procedure DataSetAfterDelete;
        procedure DatasetRefreshed;
        procedure ClosedLoop;
        procedure RootNotFound;
        function DataSetLocate(const ID: string): Boolean;
        function GetDeleteQuestion(Node: TTreeNode): string; override;
        function DoDelete(Node: TTreeNode): Boolean; override;
      { Called by procedure Insert, GetNewID has to calculate the ID of a
        new record. It calls OnGetNextID: }
        function GetNewID: string; virtual;
        procedure BuildTree; virtual;
        property  TreeViewLink: TTreeViewLink read FTreeViewLink;
      public
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
        procedure RebuildTree;
        procedure BuildTreeIfNeeded;
        procedure Insert(AsChild: Boolean); override;
        procedure Delete; override;
        function MoveNode(Source, Destination: TTreeNode;
                          Mode: TNodeAttachMode): Boolean; override;
        function FindTextID(const S: string; var ID: string;
          TVFindTextOptions: TTVFindTextOptions): Boolean;
        function TextIDList(const S: string;
          TVFindTextOptions: TTVFindTextOptions): TStringList;
      { With GetExpanded you can save all Items[].Expanded in a string
        (e.g. to save this in an INI-file)
        to restore all Items[].Expanded with SetExpanded: }
        function GetExpanded(Separator: Char): string;
        procedure SetExpanded(const List: string; Separator: Char);
      { If not dtSynchronizeDataSet in Options, use this procedure to show
        the current record of the dataset in the tree: }
        procedure SynchronizeSelectedNodeToCurrentRecord;
      { If not dtSynchronizeDataSet in Options, use this procedure to move
        the dataset to the selected node of the tree: }
        procedure SynchronizeCurrentRecordToSelectedNode;
      { IsRootNode is true if the node has no parent: }
        function IsRootNode(Node: TTreeNode): Boolean;
      { IsSingleRootNode is true if the node is the only one without parent: }
        function IsSingleRootNode(Node: TTreeNode): Boolean;
      { To get the ID of a Node: }
        function IDOfNode(Node: TTreeNode): string;
      { To get the Node that has the ID: }
        function GetIDNode(const aID: string): TTreeNode;
      { DataSource.DataSet: }
        property DataSet: TDataSet read GetDataSet;
      { The ID of the current selected node,
        or set Selected with SelectedID := ID: }
        property SelectedID: string read GetSelectedID write SelectID;
      { ID of Items[Index]. Index is 0 to Items.Count -1: }
        property IDs[Index: Integer]: string read GetID;
      { possible published: }
        property DataSource: TDataSource read GetDataSource write SetDataSource;
        property TableIDField: string read FTableIDField write SetTableIDField;
        property TableParentField: string
          read FTableParentField write SetTableParentField;
        property TableTextField: string
          read FTableTextField write SetTableTextField;
        property RootID: string read FRootID write SetRootID;
        property OnClosedLoop: TNotifyEvent read FOnClosedLoop write FOnClosedLoop;
      { Called by the procedure Insert, OnGetNextID has to calculate the ID of
        a new record. This is not needed if the type of the ID-field is ftAutoInc.
        You have to override GetNewID if you hide the record with the highest
        ID and the type of the ID-field is not ftAutoInc:
        - DataSet is TQuery and TQuery.SQL uses 'WHERE ...'
        - DataSet.MasterSource is set.
        If you use a TQuery as Dataset, it is recommended to calculate the
        new ID yourself.
        If you set the new ID on Dataset.OnNewRecord, please use OnGetNextID
        or your own GetNewID bacause the ID is needed before the Dataset gets
        into insert-mode.}
        property OnGetNextID: TDBTVGetNextIDEvent
          read FOnGetNextID write FOnGetNextID;
        property OnRootNotFound: TNotifyEvent
          read FOnRootNotFound write FOnRootNotFound;
        property Options: TDBTreeOptions read FOptions write SetOptions;
      

  8.   

    数据库结构示例
      创建一个数据库,为简化程序,我只创建两个数据库字段,定义如下:
    字段名 类型 长度 
    text c 10 
    longid c 6  
      LongID字段实际上由两段组成,每一段3位,LongID只能表示1000条记录。将LongID定义为索引字段,存为c:\testtree\tree.dbf。编辑该DBF文件,新建一条记录,Text字段设为TOP,LongID字段设为“000”(3个“0”前为三个空格)。  创建演示程序
      在Form1上放置TreeView1、Table1、PopupMenu1、Edit1、Edit2。TreeView1的PopupMenu属性设为PopupMenu1;Table1的DataBaseName属性设为c:\testtree,TableName属性设为tree.dbf,IndexFieldNames属性设为LongID;为PopupMenu1加选单项Add1和Del1,Caption分别为Add和Del;Edit1用来输入新节点的Text属性值,Edit2用来输入新节点的3位ID号。存为c:\testtree\treeunit.pas和c:\testtree\testtree.dpr。
      在treeunit.pas的Type关键字后加入一行:Pstr:^string;{Pstr为字符串指针}  为Form1的OnCreate事件添加代码:  procedure TForm1.FormCreate(Sender: TObject);  var p:Pstr;Node:TTreeNode;  begin   with Table1,Treeview1 do   begin   open;   first;   new(p);{为指针p分配内存}   p^:=FieldByName(′LongID′).AsString;   Node:=Items.AddChildObject(nil,FieldByName(′Text′).AsString,p);   if HasSubInDbf(Node) then Items.AddChildObject(Node,′ ′,nil);{有子节点则加一个空子节点}   end;  end;  HasSubInDbf为自定义函数,自变量为Node,检查节点Node有无子节点,有则返回True,反之返回False,并在TForm1的类定义里加入原型声明(其它自定义函数的原型也在TForm1的类定义里声明,不另作解释),函数代码如下:  function TForm1.HasSubInDbf(Node:TTreeNode):Boolean;  begin   with Table1 do   begin   Table1.FindNearest([copy(Pstr(Node.Data)^,4,3)+′000′]);   result:=copy(FieldByName(′LongID′).AsString,1,3)=copy(Pstr(Node.Data)^,4,3);{如数据库里当前记录的LongID字段内容的前3位和节点Node的Data的后3位相同,则Node应该有子节点}   end;  end;  为TreeView1控件的OnDeletion事件添加代码,需要指出的是,不仅调用Delete方法可以触发OnDeletion事件,而且当树控件本身被释放前,也触发OnDeletion事件,所以,在此处加入dispose(node.data)会很“安全”:  procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode);  begin   Dispose(Node.Data);{释放节点数据内存}  end;  为Add1选单项的OnClick事件添加代码如下:  procedure TForm1.Add1Click(Sender: TObject);  var p:pstr;Tmpstr:string;i:integer;  begin   try   StrToInt(Edit2.Text);  Tmpstr:=Edit2.Text;{注:在实用中,必须用更好的方法来产生ID}   except;  ShowMessage(′重新输入Edit2的内容′);  abort;   end;   with TreeView1 do   begin   new(p);   p^:=copy(Pstr(Selected.Data)^,4,3)+TmpStr;   Items.AddChildObject(Selected,Edit1.Text,p);   end;   with Table1 do{ 在数据库里添加记录 }   begin   Append;   FieldByName(′Text′).AsString:=Edit1.text;   FieldByName(′LongID′).AsString:=p^;   Post;   end;   TmpStr:=inttostr(strtoint(TmpStr)+1);   for i:=length(TmpStr) to 2 do TmpStr:=′0′+TmpStr;   Edit2.Text:=TmpStr;  end;  为Del1菜单项的OnClick事件添加代码如下:  procedure TForm1.Del1Click(Sender: TObject);  var DelList:TStringList;LongID,NSubLongID:string;  begin   DelList:=TStringList.create;   DelList.Sorted:=True;   DelList.Add(Pstr(TreeView1.Selected.Data)^);   while DelList.Count>0 do   begin   LongID:=DelList.Strings[0];   DelList.Delete(0);   Table1.SetKey;   Table1.FieldByName(′LongID′).AsString:=LongID;   if Table1.GotoKey then Table1.Delete;   if HasSubInDbf(TreeView1.Selected) then   begin   NSubLongID:=Table1.FieldByName(′LongID′).AsString;   while (copy(NSubLongID,1,3)=copy(LongID,4,3))and(not Table1.Eof) do   begin   dellist.Add(NSubLongId);   Table1.Next;   NSubLongId:=Table1.FieldByName(′LongID′).AsString;   end;  end;   end;   DelList.Free;   TreeView1.Items.Delete(TreeView1.Selected);  end;   为TreeView1的OnExpanding事件添加代码:  procedure TForm1.TreeView1Expanding(Sender: TObject; Node: TTreeNode;   var AllowExpansion: Boolean);  var TmpNode:TTreeNode;NSubLongID:String;p:Pstr;bm:TBookMark;  begin   with Table1,TreeView1 do   begin  Items.BeginUpdate;  SetKey;  FieldByName(′LongID′).AsString:=Pstr(Node.Data)^;  if not GotoKey then Items.Delete(Node)  else  begin   TmpNode:=Node.GetFirstChild;   if (TmpNode.Text=′ ′)and(TmpNode.Data=nil) then   begin   TmpNode.Delete;   if HasSubInDbf(Node) then   begin   NSubLongID:=FieldByName(′LongID′).AsString;   while (copy(NSubLongID,1,3)=copy(Pstr(Node.Data)^,4,3))and(not Eof) do   begin   new(p);   p^:=FieldByName(′LongID′).AsString;   bm:=GetBookMark;   TmpNode:=Items.AddChildObject(Node,FieldByName(′Text′).AsString,p);   if HasSubInDbf(TmpNode) then Items.AddChildObject(TmpNode,′ ′,nil);   GotoBookMark(bm);   FreeBookMark(bm);   Next;   NSubLongId:=FieldByName(′LongID′).AsString;   end; end; end;   end;  Items.EndUpdate;   end;  end;  以上简要谈了谈数据库的树状显示的基本方法,另外,编辑树上节点的Text属性的同时对数据库进行修改、同一数据库在多用户同时操作时数据库以及树的一致性、树上节点的拷贝与复制等就不再赘述,读者可自行完善。本文程序在Dlphi4.0、Windows 98下调试通过
      

  9.   

    这样的问题我已经给别人解决过很多次可我自己用的方法不是记录每一个接点其实TreeView的数据是一个文本,如:
    ////////////////////////////////Begin 树文本
    食品
    主食品
    大米
    小麦
    玉米
    副食品
    酱油
    食盐
    日用品
    牙刷
    洗衣粉
    ////////////////////////////////End 树文本用一个文本字段,一条记录来处理,方便、快速,为什么不!
      

  10.   

    我的意思是如何将数据库中的数据显示到treeview1中的Treeview1.items.item[1]节点下面;表tbTree结构:
    tbTree
    ( TreeId,     (节点编号)
      TreeName,   (节点名称)
      UpperTreeId (上级节点编号)
    )
    UpperTreeId=NULL 表示根节点
      

  11.   

    参考
    TTreeView.SaveToFile()
    TTreeView.LoadFromFile()
    TTreeView.SaveToStream()
    TTreeView.LoadFromStream()
      

  12.   

    function DataSetToTreeNode(mDataSet: TDataSet;
      mTreeView: TTreeView; mTreeNode: TTreeNode;
      mParentText: string): Boolean;
    const
      cFieldNameParent = 'UpperTreeId';
      cFieldNameTreeName = 'TreeName';
      cFieldNameTreeId = 'TreeId';
      cFieldNames = cFieldNameParent + ';' + cFieldNameTreeName + ';' + cFieldNameTreeId;
    var
      vTreeNode: TTreeNode;
      vFieldValues: Variant;
    begin
      Result := False;
      if not Assigned(mDataSet) then Exit;
      if not Assigned(mTreeView) then Exit;
      if not mDataSet.Active then Exit;
      mDataSet.Filtered := False;
      mDataSet.Filter := Format('%s=%s', [cFieldNameParent, QuotedStr(mParentText)]);
      mDataSet.Filtered := True;
      if mDataSet.RecordCount = 0 then Exit;
      mDataSet.First;
      while not mDataSet.Eof do begin
        vTreeNode := mTreeView.Items.AddChild(mTreeNode,
          mDataSet.FieldByName(cFieldNameTreeName).AsString);
        vFieldValues := mDataSet[cFieldNames];
        DataSetToTreeNode(mDataSet, mTreeView, vTreeNode,
          mDataSet.FieldByName(cFieldNameTreeID).AsString);
        ///////Begin 恢复位置
        mDataSet.Filtered := False;
        mDataSet.Filter := Format('%s=%s', [cFieldNameParent, QuotedStr(mParentText)]);
        mDataSet.Filtered := True;
        mDataSet.Locate(cFieldNames, vFieldValues, []);
        ///////End 恢复位置
        mDataSet.Next;
      end;
      Result := True;
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      TreeView1.Items.Clear;
      DataSetToTreeNode(Table1, TreeView1, nil, 'NULL');
    end;
      

  13.   

    zswang(伴水)(* pascal→c *): 好像不可以哦,只能搜索出第一层节点。我的表结构:
      table1 (NodeId,NodeName,UpperNodeId)
    ( UpperNodeId=0 为根接点 )测试代码:
      treeview1.Items.Clear;
      DataSetToTreeNode(ClientDataSet1, treeview1, nil, '0');(注:我用 TClientDataSet 连数据库)我只改你的函数的前面部分):
      cFieldNameParent = 'UperGroupId';
      cFieldNameTreeName = 'GroupName';
      cFieldNameTreeId = 'GroupId'
      

  14.   

    zswang(伴水)(* pascal→c *): 
       请您看看我写的代码,我怎么觉得好像没错,可是偏偏就是错了,不能把节点全部搜索出来,第一层能正确地全部搜索出来,可是第二层只能搜索出第一个节点。第二层以后就更别说了。//表结构: 
    table1 
    ( NodeId,      --节点编号
      NodeName,    --节点名称
      UpperNodeId  --上级节点编号
    )
    // 寻找第一层 
    // TQuery 的创建省略
    procedure ListAllNode(TreeView:TTreeview);
    var 
      qry : TQuery;
      Temp : TTreeNode;    
    begin
      qry.SQL.Add('select NodeId,NodeName from table1 where UpperNodeId=0');
      qry.ExecSQL;
      while not qry.Eof do
      begin
        Temp := TreeView.Items.Add(nil,qry.FieldAsString('NodeId')); // 增加根节点
        GetNext(Temp,qry.FieldAsString('NodeId'));
        qry.Next;
      end;
    end;//递归寻找下一个节点
    procedure GetNext(Node : TTreeNode;Parent : string);
    var 
      qry : TQuery;
      Temp : TTreeNode;    
    begin
      qry.SQL.Text := 'select nodeid,f1 from table1 where ParentNodeId='+parent;
      qry.open;
      while not qry.Eof do
      begin
        Temp := TreeView.Items.AddChild(Node,qry.FieldAsString('NodeName'));       
        GetNext(Temp,qry.FieldAsString('NodeId'));
        qry.Next;
      end;
    end;//测试
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      TreeView1.Items.Clear;
      ListAllNode(treeview1);
    end;
      

  15.   

    你可以在节点的Data属性中存储对象的,你可以先构造一个新的对象完全映射你的数据库字段,这样你就可以是实现索引了排序了
      

  16.   

    TmyRecord=class(Tobject)
        ID:Integer;
        pID:integer;
        Name:String;
        Parent:TmyRecord;
      end;
    TMyList=class(TList)
        function Find(ID:integer):TmyRecord;
        function FindParent(pID:integer):TmyRecord;
        function Add(Obj:TmyRecord):integer;overload;
        procedure Delete(index:integer);
      end;  
    实现函数

    procedure TUnitForm.CreateTree(Tree:TTreeView;Data:TMyList);
     {创建一个结点的子树}
     procedure CreateSubTree(Node:TTreeNode;Data:TmyList);
       var
         subNode:TTreeNode;
        // subNodeN:TTreeNode;
        i:integer;
      begin
       if Data.Count >0 then
            begin
                 i:=0;
               while i<= Data.Count -1 do
                begin
                if TmyRecord(Data.Items[i]).pid=TmyRecord(Node.Data).ID then
                 begin             SubNode:=Tree.Items.AddChildObject(Node,TmyRecord(Data.Items[i]).Name,Data.Items[i]);
                 SubNode.Data:=Data.Items[i];
                 Data.Delete(i);
                 CreateSubTree(SubNode,Data);
                 continue;
                 end;
                 inc(i);
               end;
            end;  end;
     var
      Node:TTreeNode;
      //DataSet:TClientDataSet;
    //  i:integer;
    //  flag:boolean;
      obj:TMyrecord;
    begin
     // DataSet:=nil;
      //Node:=nil;
    //  flag:=false;
    {  DataSet:=TClientDataSet.Create(nil);
      DataSet.Data:=Data;
      while Not DataSet.Eof do
        begin
         if DataSet.FieldByName('UpTreeID').AsInteger=0 then
           begin
            flag:=true;
            break;
           end;
        end;  if flag  then
        begin
       //  Node:=TMyNode.Create( Tree.Items.AddFirst(nil,DataSet.FieldByName('Name').AsString))  ;
        // Node.ID:=DataSet.FieldByName('ID').AsInteger;
         DataSet.First;
         CreateSubTree(Node,nil);    end;
    DataSet.Free;   }
    obj:=Data.Find(1);
    Tree.Items.Clear;
    if Obj<>nil then
        begin
         Node:=Tree.Items.AddObjectFirst(nil,Obj.Name,Obj);
         CreateSubTree(Node,Data);
        end; 
    end;
    我过去写的一段
    Node的Data中存储TMyrecord对象
      

  17.   

    比如
    节点名称 节点编号 上次节点号
     aaa       1        -1 
     bbb       2        1 
     ccc       3        3只有-1埮在节点编号中出现,那么把aaa读出,然后类似展开
      

  18.   

    // 寻找第一层 
    // TQuery 的创建省略
    procedure ListAllNode(TreeView:TTreeview);
    var 
      qry : TQuery;
      Temp : TTreeNode;    
    begin
    //#你的qry还没有分配资源qry := TQuery.Create; qry.DatabaseName := '???';  qry.SQL.Add('select NodeId,NodeName from table1 where UpperNodeId=0');
      qry.ExecSQL; //#qry.Open;
      while not qry.Eof do
      begin
        Temp := TreeView.Items.Add(nil,qry.FieldAsString('NodeId')); // 增加根节点
        GetNext(Temp,qry.FieldAsString('NodeId'));
        qry.Next;
      end;
    end;
      

  19.   

    //#你的qry还没有分配资源qry := TQuery.Create; 
    //#qry.Open;
    这两点我改了,可是还是不行,我发现问题好象在:
      GetNext(Temp,qry.FieldAsString('NodeId'));
      qry.Next;比如对A进行递归查找时,
        A
         ┝x
         ┝y
        B
    当查找x的子节点为空后,按理应该返回到y,可是却返回到了B这里了,真是奇怪,您说应该如何修改呢?
      

  20.   

    tbTree
    ( TreeId,     (节点编号)
      TreeName,   (节点名称)
      UpperTreeId (上级节点编号)
    )分别是什么类型?我提供的函数自己已经调试通过
    你把完整代码我看
      

  21.   

    你所写代码的思路也是正确的
    自己多多调试调试
    一定是什么细节没有考虑
    一步步的来
    首先确定自己通过的模拟数据是否正确
    其次确定思路是否正确
    之后确定每一步是否正确如果你不能解决,请发一个可以调试的例子发给我看看
    [email protected]
    明天就放假了,最好今天中午之前
      

  22.   

    with rationdatamodule.gcquery do
       begin
          close;
          sql.Clear;
          sql.Add('select * from t_gcsm order by gcbh');
          prepared;
          open;
          first;
          if recordcount<>0 then
          begin
             for i:=1 to recordcount do
             begin
                gcm:=trim(fieldbyname('gcm').asstring);
                treeNodeparent:=TreeView1.Items.Add(nil,gcm);
                with rationdatamodule.demladoquery1 do
                begin
                   close;
                   sql.clear;
                   sql.Add('select * from t_deml where gcm=:gcm');
                   parameters.ParamByName('gcm').value:=gcm;
                   prepared;
                   open;
                   first;
                   if recordcount<>0 then
                   begin
                      for j:=1 to recordcount do
                      begin
                         xjmc:=trim(fieldbyname('xjmc').asstring);
                         treeNodechild:=TreeView1.Items.Addchild(treeNodeparent,xjmc);
                         next;
                      end;
                   end;
                end;
                next;
             end;
       end;
    end;
    改一下字段,如果不行的话,你打我,呵呵
      

  23.   

    问题已经解决。
    非常感谢大家的帮助,谢谢大家.
    特别谢谢zswang(伴水)(* pascal→c *),我一定谨遵您的教诲。