下面是代码只能调用递归调用一次。然后就出错。TReeview中只能生成一层。
unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, ADODB, ComCtrls;type
TNodeData = record
  Index : integer;    //treeview编号
  Caption : string;   //Treeview内容
end;
  PNodeData = ^TNodeData;
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    ADOQuery1: TADOQuery;
    //Ptr: PNodeData;
    ADOConnection1: TADOConnection;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure AddTree(Node: TTreeNode; PN: PNodeData);
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementation{$R *.dfm}{ TForm1 }procedure TForm1.AddTree(Node: TTreeNode; PN: PNodeData);
var
  nNode :TTreeNode;
  PNode :PNodeData;
begin
try
//ADOQUERY1.Create(NIL);
  ADOQuery1.SQL.Text := 'Select * from tb1 Where PID = ' + inttostr(PN^.Index);
  if ADOQuery1.Active then
    Adoquery1.Close;
  ADOQuery1.Open;
  while  ADOQuery1.Eof = FALSE do
  begin
    New(PNode);
    PNode^.Caption := ADOQuery1.FieldByName('Caption').AsString;
    PNode^.Index := ADOQuery1.FieldByName('ID').AsInteger;
    nNode :=TreeView1.Items.AddChildObjectFirst(Node , PNode^.Caption , PNode);
    nNode.SelectedIndex := 2;
    AddTree(nNode , PNode);一调用就出错。
    ADOQuery1.Next;
  end;
finally
   ADOQuery1.Free;
end;end;procedure TForm1.FormCreate(Sender: TObject);
var
  Prt :PNodeData;
  Node : TTreeNode;
begin
New(Prt);
Prt^.Index := 0;
Prt^.Caption := '我的目录';
Node := TreeView1.Items.AddChildObject(nil , '我的目录' , prt) ;
AddTree(Node , Prt);
end;end.

解决方案 »

  1.   

    你递归到里层时,ADOQuery1就保留不了外层的数据了,因为是同一个数据集,这是其中一个明显的错误。然后你还要FREE掉这个ADOQUERY,那返回外层的时候自然就地址错了。
      

  2.   

    procedure TForm1.AddTree(Node: TTreeNode; PN: PNodeData); 
    var 
      nNode :TTreeNode; 
      PNode :PNodeData;             tmpadoquery:tadoquery;   
    begin 
    try 
    //ADOQUERY1.Create(NIL);          //使用递归,一定要动态创建adoquery
                                       tmpadoquery:=tadoquery.create(self);

      tmpadoquery.SQL.Text := 'Select * from tb1 Where PID = ' + inttostr(PN^.Index); 
      if tmpadoquery.Active then 
        tmpadoquery.Close; 
      tmpadoquery.Open; 
      while  tmpadoquery.Eof = FALSE do 
      begin 
        New(PNode); 
        PNode^.Caption := tmpadoquery.FieldByName('Caption').AsString; 
        PNode^.Index := tmpadoquery.FieldByName('ID').AsInteger; 
        nNode :=TreeView1.Items.AddChildObjectFirst(Node , PNode^.Caption , PNode); 
        nNode.SelectedIndex := 2; 
      AddTree(nNode , PNode); 
        tmpadoquery.Next; 
      end; 
    finally 
      tmpadoquery.Free; 
    end; end; 
      

  3.   

    3楼那样就没错了 
    ADOQuery 得动态创建才行
      

  4.   

     使用递归为什么一定要动态创建adoquery
      

  5.   

    楼上分析的很精辟,adoquery就是要动态创建,不过你可能事先将 tb1 表中的记录读入一个集合里.这样就不用反复读数据库了
      

  6.   

    遞歸太慢了,這樣快一些,類似於WINDOWS資源管理器procedure TRES_BOM_VIEW_F.cx_TVExpanding(Sender: TObject; Node: TTreeNode;
      var AllowExpansion: Boolean);
    function IsNum(str:string):Boolean;
    var
      iLoop:Integer;
    begin
      Result:=True;
      for iLoop:=1 to Length(str) do
        if not (str[iLoop] in ['0'..'9']) then
        begin
          Result:=False;
          Break;
        end;
    end;  
    begin
      inherited;
      if (Node.Level>0)and(IsNum(Node.Text)) then
      begin
        try
          RES_LOADING_F:=TRES_LOADING_F.Create(Self);
          RES_LOADING_F.Label1.Caption:='正在查找數據......';
          RES_LOADING_F.Show;
          RES_LOADING_F.Update;
          Application.ProcessMessages;
          Node.DeleteChildren;
          qry_op.Close;
          qry_op.SQL.Text:='select distinct chld_litm from RES_BOM_LH where parn_litm='''+ Node.Text+'''';
          qry_op.Open;
          qry_op.First;
          while not qry_op.Eof do
          begin
            cx_TV.Items.AddChildFirst(Node,qry_op.Fieldbyname('chld_litm').AsString);
            qry_op.Next;
          end;
        finally
          RES_LOADING_F.Close;
        end;
      end;
    end;procedure TRES_BOM_VIEW_F.cx_TVExpanded(Sender: TObject; Node: TTreeNode);
    var
      iLoop:Integer;
    begin
      inherited;
      if Node.Level>0 then
      begin
        for iLoop:=0 to Node.Count-1 do
        begin
          adoq_op.Close;
          //select CHLD_LITM,(case when CHLD_LITM in (select distinct PARN_LITM from RES_BOM_LH) then '1' else '0' end)as [Status] from RES_BOM_LH a where PARN_LITM='31030509101' and PARN_TYP='NetScroll 600'
          adoq_op.SQL.Text:='select top 1 chld_litm from RES_BOM_LH where parn_litm='''+Node.Item[iLoop].Text+'''';
          adoq_op.Open;
          if (adoq_op.RecordCount>0) then
            Node.Item[iLoop].HasChildren:=True;
          Application.ProcessMessages;
        end;
      end;  
    end;
      

  7.   


    因为按你这个代码的算法原理, 要求每次调用AddTree时, 在AddTree内使用局部于本次调用的一个私有的Query, 而不能和其他调用共用一个Query。
    所以,得把Query申明为AddTree的一个局部变量。
      

  8.   

    procedure TForm1.AddTree(Node: TTreeNode; PN: PNodeData);
    var
      nNode :TTreeNode;
      PNode :PNodeData;
    begin
    try
    //ADOQUERY1.Create(NIL);
      ADOQuery1.SQL.Text := 'Select * from tb1 Where PID = ' + inttostr(PN^.Index);
      if ADOQuery1.Active then 
        Adoquery1.Close;
      ADOQuery1.Open;
      while  ADOQuery1.Eof = FALSE do
      begin
        New(PNode);
        PNode^.Caption := ADOQuery1.FieldByName('Caption').AsString;
        PNode^.Index := ADOQuery1.FieldByName('ID').AsInteger;
        nNode :=TreeView1.Items.AddChildObjectFirst(Node , PNode^.Caption , PNode);
        nNode.SelectedIndex := 2;
      AddTree(nNode , PNode);一调用就出错。
        ADOQuery1.Next;
      end;
    finally
      ADOQuery1.Free;//这句去掉,否则第二次调用的时候就不存在了,所以报错
    end;end; 
      

  9.   

    只用一个ADOQuery的例子:procedure TForm1.AddTree(Node: TTreeNode; PN: PNodeData);
    var
      nNode: TTreeNode;
      PNode: PNodeData;
    begin
      ADOQuery1.Filter := 'PID = ' + IntToStr(PN^.Index);
      ADOQuery1.Filtered := True;
      ADOQuery1.First;
      while not ADOQuery1.EOF do
      begin
        New(PNode);
        PNode^.Caption := ADOQuery1.FieldByName('Caption').AsString;
        PNode^.Index := ADOQuery1.FieldByName('ID').AsInteger;
        nNode := TreeView1.Items.AddChildObjectFirst(Node, PNode^.Caption, PNode);
        nNode.SelectedIndex := 2;
        ADOQuery1.Next;
      end;
      nNode := Node.GetFirstChild;
      while nNode <> nil do
      begin
        PNode := PNodeData(nNode.Data);
        AddTree(nNode, PNode);
        nNode := Node.GetNextChild(nNode);
      end;
    end;procedure TForm1.FormCreate(Sender: TObject);
    var
      Prt :PNodeData;
      Node : TTreeNode;
    begin
      ADOQuery1.SQL.Text := 'Select * from tb1';
      if ADOQuery1.Active then Adoquery1.Close;
      ADOQuery1.Open;  New(Prt);
      Prt^.Index := 0;
      Prt^.Caption := '我的目录';
      Node := TreeView1.Items.AddChildObject(nil, '我的目录', prt) ;
      AddTree(Node, Prt);
    end;