各位前辈:
我想在一个窗体上左边放一个treeview,右边放一个dbgrid.右边进行增加,修改和删除工作,数据库结构是:id,parentid,name
我想问几个思路性的问题:
1,点击左边treeview的节点,右边显出它的兄弟好呢?还是儿子好?
2,右边增加一个记录后,也就是进数据库后,是否需要重新生成左边的树?
3,从数据库中读数据生成一棵树,采用什么方法好呢?
请大家指点。有代码最好不过,谢谢!

解决方案 »

  1.   

    1、儿子好
    2、不重新。而是新建树的item.
    3、递归吧。
      

  2.   

    可以试试第三方控件
    ExpressDBTree
      

  3.   

    3、用递归:
    首先,在单元接口部分声明一记录类型及其指针,用来保存你的树节点需传递的信息。
    type
      pchar=^str;
      str=record
        tcaption:string;
        num:integer;
      end;
    写一生成树的函数,注意递归:
    function TForm1.ShowTree(TNode: TTreeNode; s: string): boolean;
    var
      QR:TADOQuery;
      TmpNode:TTreeNode;
      p:pchar;
    begin
      QR:=TADOQuery.Create(self);
      if TNode=nil then //判断是否顶层接点 ;
      begin
        new(p);
        p^.tcaption:=s;
        p^.num:=1;
        TNode:=Treeview1.Items.AddChildObject(TNode,p^.tcaption,p);
      end;
      with QR,treeview1 do
      begin
        close;
        connection:=ADOCONNECTION1;
        SQL.Clear;
        SQL.Add('select MD003,MD006 from BOMMD where MD001=:NN');
        parameters[0].Value:=s;
        open;
        ACTIVE;
        first;
        while not eof do
        begin
          new(p);
          p^.tcaption:=QR.fieldbyname('MD003').AsString;
          P^.num:=QR.fieldbyname('MD006').AsInteger;
          TmpNode:=Items.AddChildObject(TNode,p^.tcaption,p);
          ShowTree(TmpNode,p.tcaption);//递归
          next;
        end;
      end;
    end;
    然后在需要的时候调用该函数就可以了,例如:
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      ShowTree(nil,'0102-73316000');
    end;
    上述为一展BOM树的实例(BOM结构以关系数据库结构存储)。
    2、不需重新生成树,直接调用
    treeview1.items.addchildobject()即可增加子节点
    1、右边显示儿子好。
      

  4.   

    1\当然是生成儿子好啊
    2\不要了直接用语句加个ITEM就可以了
    3\要程序留个MAIL给
      

  5.   

    复录结构用递归,一般可能还不用,如果是左边树中显示库中的表和一的字段,右边显示左边所选表的记录,那用循环就可以了,最多是多重的。另外试试第3方控件,比如devexpress的那个dbtreelist什么的。
      

  6.   

    不好意思,楼主,我来看得太迟了,因为我的网络有点小问题。我常用的方法是78(编程失败,自己.人生辉煌,别人) 的方法。
    代码可以参照wdsimon(老王)的。建议你自己多写一点处理各种问题类,
    建议你用类来封装,
    尽量少用结构或指向结构的指针,建议底层的数据结构用类来封装,这样可扩展性会更好。
      

  7.   

    1、显示儿子会更好一点;
    2、不需要重新生成树,只需要再增加一个节点就可以了;
    3、给你一个简单的例子看看:
    var
        FirstNode,SecondNode: TTreeNode;
    TreeView1.Items.Clear;
        FirstNode := TreeView1.Items.AddFirst(TreeView1.Items.GetFirstNode, '系统角色');
        AdoRole.Close;
        AdoRole.SQL.Text := 'select * from RoleTable';
        AdoRole.Open;
        if AdoRole.RecordCount > 0 then
        begin
        AdoRole.First;
        while not AdoRole.Eof do
        begin
            SecondNode := TreeView1.Items.AddChild(FirstNode, AdoRole.FieldByName('RoleName').AsString);
            AdoUser.Close;
            AdoUser.SQL.Text := 'select * from UserList where RoleID = '+AdoRole.FieldByName('RoleID').AsString+'';
            AdoUser.Open;
            while not AdoUser.Eof do
            begin
                TreeView1.Items.AddChild(SecondNode, AdoUser.FieldByName('Name').AsString);
                AdoUser.Next;
            end;
            AdoRole.Next;
        end;
        end;
      

  8.   

    老王:你好!
    你的'select MD003,MD006 from BOMMD where MD001=:NN');‘
    md003
    md006
    等是什么东东?我有点看不懂。
      

  9.   

    MD003就是你表里的parentid(父节点),MD006 就是你表里id(当前节点),BOMMD 就是你的表
    需要注意
    1、首先,在单元接口部分声明一记录类型及其指针,用来保存你的树节点需传递的信息。
    type
      pchar=^str;
      str=record
        tcaption:string;
        num:integer;
      end;
    当然你,可以依据你的需要来做(如节点不需保存信息,也可不要指标)。2、写一生成树的函数,注意递归:
    function TForm1.ShowTree(TNode: TTreeNode; s: string): boolean;
    var
      QR:TADOQuery;
      TmpNode:TTreeNode;
      p:pchar;
    begin
      QR:=TADOQuery.Create(self);
      if TNode=nil then //判断是否顶层接点 ;
      begin
        new(p);
        p^.tcaption:=s;
        p^.num:=1;
        TNode:=Treeview1.Items.AddChildObject(TNode,p^.tcaption,p);
      end;
      with QR,treeview1 do
      begin
        close;
        connection:=ADOCONNECTION1;
        SQL.Clear;
        SQL.Add('select parentid,id from 你的表 where condition');
       //注意,condition中你可带参数,也可不带参数
        parameters[0].Value:=s;//那么这句可要也可不要;
        open;
        ACTIVE;
        first;
        while not eof do
        begin
          new(p);
          p^.tcaption:=QR.fieldbyname('parentid').AsString;
          P^.num:=QR.fieldbyname('id').AsInteger;
          TmpNode:=Items.AddChildObject(TNode,p^.tcaption,p);
          ShowTree(TmpNode,p.tcaption);//递归
          next;
        end;
      end;
    end;
      

  10.   

    老王,我想问下你这种办法,在C++builder里怎么实现Record类型?
    还有这种记录类型你是怎么读出数据的?
      

  11.   

    1,点击左边treeview的节点,右边显出它的兄弟好呢?还是儿子好?*我觉得应该显示treeview的同级items,就像windows的资源管理起那样不是更好吗?????2,右边增加一个记录后,也就是进数据库后,是否需要重新生成左边的树?
    *因该是不需要的。3,从数据库中读数据生成一棵树,采用什么方法好呢?
    请大家指点。有代码最好不过,谢谢!
    上面wdsimon(老王) 仁兄的方法没试过,不过我觉得代码量太多,还有递归!,下面的代码大家觉得如何??:
    procedure Tcpya_app.FormCreate(Sender: TObject);//窗体初始化时,加载树。
    begin
      datamodule2.tree.close; //tree:是数据模块中的adoquery 
      datamodule2.tree.sql.clear;
      datamodule2.tree.sql.add('select name from plat order by name');//按照name排序。
      datamodule2.tree.Active:=true;
      datamodule2.tree.Open;
      while not datamodule2.tree.Eof do//填充树
        begin
         with tv.Items do//增加节点
      begin
         MyTreeNode1 := Add(nil,trim(datamodule2.tree.fields[0].asstring));//自动增加父节点
          with datamodule2 do
          begin
           child.close;//child是数据模块中的adoquery
           child.SQL.Clear;
           child.SQL.Add('select comp from dalei where plat='''+Trim(datamodule2.tree.Fields[0].asstring)+''''+' order by comp');
           child.Active:=true;
           child.Open;
           While Not child.Eof do
           begin
                TV.Items.AddChild(mytreenode1,trim(child.Fields[0].AsString));//在父节点下加子节点
                child.Next;
                end; end;
           datamodule2.tree.Next;
       end;
       end;
    end;
    上面的程序中生成父节点的表可以说是主表吧,声称子节点的表是从表,
    其中两个表通过plat字段相关联,
      

  12.   

    IORILI(近视眼@_@) 你的办法里每个节点只能有一个值,比如:我要显示的值是STR,我要写到数据库的是ID,你的这种办法就取不出来ID了,老王写进去的是一个RECORD,所以很关联记录到节点上!所以.............嘿嘿!
      

  13.   

    WuLoveXue(晕死,又这样) :C++builder我不会,delphi也初学。
    treeview的节点有一个data的指针属性,利用他可以把节点存储的信息读出来,
    以下代码是递归删除选定节点下所有节点(包含子节点的节点,同时删除数据库数据):
    注意:pchar在展开树节点时已申明。
    procedure TForm1.detree(node: ttreenode);
    var
      tnode:ttreenode;
      i:integer;
      s1,s2:string;
    begin
      if node.HasChildren then
      begin
        for i:=node.Count-1 downto 0 do
        begin
          if node.Item[i].HasChildren then
          detree(node.Item[i]);
          s1:=pchar(node.Item[i].Data)^.mcaption;
          s2:=pchar(node.Item[i].data)^.tcaption;
          with form1.pub do
          begin
            close;
            sql.Clear;
            sql.Add('delete BOMMD where MD001=:AA and MD003=:BB');
            parameters[0].Value:=s1;
            parameters[1].Value:=s2;
            ExecSQL;
          end;
          node.Item[i].Delete;
        end;
      end;
      node.Delete;
    end;
      

  14.   

    to 老王:你创建了这么多AdoQuery,不用释放吗?
      

  15.   

    老王:你好!
    我的Id,parentId都是字符串,并不是整数。
      

  16.   

    这个树形太难了,我试了老王的不行,别人的也不行,,没有一个成功的
    不知道为什么?
    下面一个也不行:
    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, DB, ADODB, ComCtrls;type
      TForm1 = class(TForm)
        TreeView1: TTreeView;
        ADOConnection1: TADOConnection;
        ADOQuery1: TADOQuery;
        procedure FormCreate(Sender: TObject);
      private
      function FindParent(ID:String):TTreeNode;
      procedure CreateTree;
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;
      stlID:TStringList  ;
    implementation{$R *.dfm}
    function Tform1.FindParent(ID:String):TTreeNode;
    var
     i:Integer;
    begin
      result:=nil;
      for i:=TreeView1.Items.Count-1 downto 0 do
        if stlID.Strings[i]=ID then
        begin
          result:=TreeView1.Items[i];
          break;
        end;
    end;procedure Tform1.CreateTree;
    var
      tmpNode:TTreeNode;
    begin
      adoQuery1.SQL.Text:='select * from material order by ParentID';
      adoQuery1.Open;
      adoQuery1.First;
      while not adoQuery1.Eof do
      begin
        tmpNode:=TreeView1.Items.AddChild(FindParent(adoQuery1.FieldByName('ParentID').AsString),adoQuery1.FieldByName('Name').AsString);
        stlID.Add(adoQuery1.FieldByName('ID').AsString);//记录ID
        adoQuery1.Next;
      end;
    end;procedure TForm1.FormCreate(Sender: TObject);
    begin
    createtree;
    end;end.