我的表为
  --------------------
  pid  |  id  |  name
   0   |  001 |  原辅料
  001  |  002 |  布料
  001  |  003 |  辅料
  002  |  004 |  纯棉
  002  |  005 |  TC布
  003  |  006 |  扣子
  003  |  007 |  绣线
  --------------------
 
function TF_FenLei.AddChildNode(node: TTreeNode; typecode: string; stype: string): TTreeNode;
var i:integer;
begin
  Result := TreeView1.Items.AddChild(node, stype);  with adoquery1 do begin
    Close;
    SQL.Clear;
    SQL.Text := 'SELECT * FROM B_Lei WHERE pid='+typecode;
    Open;
    while not eof do begin
      TreeView1.Items.AddChild(result,FieldByName('Name').AsString);
      //AddChildNode(Result,FieldByName('id').AsString,FieldByName('Name').AsString);
      next;
    end;
  end;
end;procedure TF_FenLei.FormCreate(Sender: TObject);
begin
  AddChildNode(nil,'001','原辅料');
end;想得到
原辅料
  |--布料
  |    |--纯棉
  |    |--TC布
  |--辅料
       |--扣子
       |--绣线但得到的却是
原辅料
  |--布料
  |    |--纯棉请各位改一下,或给我一个更好的方法生成数据树,谢谢!!!!

解决方案 »

  1.   

    摘录的希望有用
    procedure AddClass(AId: string; FatherNode: TTreeNode; temp_treeview: Ttreeview);
    var
    QryTmp: TADOQuery;
    myNode: TTreeNode;
    myLabel: TLabel;
    begin
    QryTmp := TADOQuery.Create(application);
    qrytmp.connection := form1.ADOConnection1;
    QryTmp.SQL.Add('select * from pro_bom');
    QryTmp.SQL.Add('where cp_peij_no=:AId');
    qrytmp.Parameters.ParamByName('aid').value := aid;
    QryTmp.Open;
    while not QryTmp.Eof do
    begin
    myNode := temp_Treeview.Items.AddChild(FatherNode, QryTmp.fieldbyname('wl_peij_no').AsString);
    //创建标签,caption存放各分支的AutoId表识
    myLabel := TLabel.Create(application);
    myLabel.Visible := false;
    myLabel.Caption := QryTmp.fieldbyname('wl_peij_no').AsString;
    myNode.Data := myLabel;
    AddClass(QryTmp.fieldbyname('wl_peij_no').Asstring, myNode, temp_treeview); //递归用过程
    QryTmp.Next;
    end;
    QryTmp.Free;
    end;
    procedure TForm1.Button2Click(Sender: TObject);
    begin
    AddClass('all',nil,bosstreeview1);
    end;
      

  2.   

    TreeView与数据库数据库应用中常会用到用树形结构显示分类的情况,如有下面的表结构class
    ID(编号)Name(名称) PID(父类编号)
    1 日用品  0
    2 维护品  0
    3 电气产品 1
    4 洗漱用品 1
    5 登高品  2
    6 电气品  2
    7 牙膏  4要生成一个日用品
      电气产品
      洗漱用品
             牙膏
    维护品
      登高品
      电气品这里一般大家会用TreeView,至于TreeView的一般用法,这里就不多说了
    最常见的方法就是递归了,procedure ParaseCls(_TV: TTreeView;NodeID:Integer;ParentNode:TTreeNode);
    var
      LocalQuery:TAdoQuery;
      TN:TTreeNode;
      PNI:PNodeInfo;
    begin
      LocalQuery:=TAdoQuery.Create(nil);
      LocalQuery.Connection:=ADOConnection1;
      LocalQuery.SQL.Add('SELECT * FROM CLASS WHERE PID='+IntToStr(NodeID));
      LocalQuery.Open;
      While Not LocalQuery.Eof do
      begin
        Application.ProcessMessages;
        TN:=_TV.Items.AddChild(ParentNode,LocalQuery.Fields[1].AsString);
        ParaseCls(_TV,LocalQuery.FieldByName('ID').AsInteger,TN);
        LocalQuery.Next;
      end;
      LocalQuery.Free;
    end;
    针对上面的,可以这样调用
      ParaseCls(TreeView1,0,nil);
    简单方便,但是速度比较慢,频繁访问数据库,如果记录数多的话,就是一场噩梦有没有其它方法?有位PlainSong有如下见解“不要用递归,这样会多次访问数据库,加重数据服务器的负担(用存储过程同理)。
    一条SQL把条例要求的数据全读出来,然后:
    “对每一条数据处理,如果ParentID为NULL则加入到树的根结点下并把它的ID和相应的树结点联系在一起放到一个查找表中并从待处理数据中删除。如果ParentID不为空则在查找表中用ParentID查找树结点,如找到则加入为子结点并把自己也加入查找表并从待处理数据中删除。
    “重复以上处理直到待处理数据为空或某次迭代无数据加入查找表(这时有非法数据,把它们抛弃不要)。
    “这样处理不一定比用递归快,但减清了数据服务的负担,当用多个应用服务访问一个数据服务器时会明显提高效率。”
    思路很好,可惜这位老兄只说了这么一段就不见了,他的具体实现未能得知。本来的根据这段话是这样想的
    1、取出数据集
    2、将ID、PID放到一个List之类的东西中,这个List对应于PlainSong说的待处理数据
    3、根据PlainSong 的办法反复遍历这个List,直到List被一条一条删除,或者有一次的遍历没有合适的记录好办法,实现起来不难,速度估计也不错
    有没有再好一点的,以下是我的办法,思路是这样的
    1、取出数据集
    2、将数据集中所有记录均以根节点的方式加到TreeView中去
    3、遍历整个TreeView,将每一个节点移到适当的位置
    针对上面的结构实现方法是这样的type
      PNodeInfo= ^TNodeInfo;
      TNodeInfo = record
        NodeID:Integer;
        PNodeID:Integer;
      end;
    //先定义一个结构,记录每一个节点的信息
    //你可以扩充这个结构,使它更适用//下面是实现的函数
    //其中TVClass是我的TreeView;
    //ADOQuery1的SQL是SELECT * From Class
    procedure ParaCls;
    var
      PNI:PNodeInfo;
      I,J:Integer;
    begin
      LockWindowUpdate(Self.Handle);
      TVClass.Items.BeginUpdate;  for I:=0 to TVClass.Items.Count-1 do
      begin
        if TVClass.Items.Data<>nil then
          Dispose(PNodeInfo(TVClass.Items.Data));
      end;//如果已经有了,就清了它  TVClass.Items.Clear;
      ADOQuery1.Open;
      ADOQuery1.First;
      while not ADOQuery1.Eof do
      begin
        New(PNI);
        PNI.NodeID:=ADOQuery1.FieldByName('CLSID').AsInteger;
        PNI.PNodeID:=ADOQuery1.FieldByName('ParentID').AsInteger;
        TVClass.Items.AddObject(nil,ADOQuery1.FieldByName('Name').AsString,PNI);
        ADOQuery1.Next;
      end;  TVClass.Items.EndUpdate;
      TVClass.Items.BeginUpdate;
       //这里我刷了一更新了一次,因为我发现如果没有上面这两句
      //常会出现TreeView显示不正常,难道是D的BUG,
      //上午同DeathCat说的就是这个问题  I:=0;
      while I<=TVClass.Items.Count-1 do
      begin
        if PNodeInfo(TVClass.Items.Data).PNodeID<>0 then
        //这里父节为0的代表就是要节点
        begin
          for J:=0 to TVClass.Items.Count-1 do
          begin
            if PNodeInfo(TVClass.Items[J].Data).NodeID=PNodeInfo(TVClass.Items.Data).PNodeID then
            begin
              if I<>J then
                TVClass.Items.MoveTo(TVClass.Items[j],naAddChild);
              if I<J then Dec(I);
              //当前节点要是向上移没什么问题,向下移的话就要处理一下了
              break;
            end;
          end;
        end;
        I:=I+1;
      end;
      TVClass.Items.EndUpdate;
      LockWindowUpdate(0);
    end;
    这中间用到了TTreeNode.Data,对每一个结点生成了一个结构指针,所以在退出时要释放了
    用这样的句子
      for I:=0 to TVClass.Items.Count-1 do
      begin
        if TVClass.Items.Data<>nil then
          Dispose(PNodeInfo(TVClass.Items.Data));
      end;
    Data值真要好好利用,试想一个单纯的树形结构有什么用处,包含丰富信息的树(Data)才是有用的树,节点的增加删除修改(要同数据库联动哟)如果充分利用Data则会是很方便的测试了一下,当总记录数在50条以内时,以上方法速度快于递归,但当数据多于100条时,递归方法的速度则远高于上述方法,所以如果记录数不多可行,多了的话还是用递归为好
      

  3.   

    具体请参考:http://www.nxcn.net/bbs/dispbbs.asp?boardID=1&ID=1050&page=5
      

  4.   

    可以使用cxDBTreeList不需要写代码,真接链接就可以显示你的结果
      

  5.   

    TO wywrycxDBTreeList是什么,在哪可找到