建立一棵树的好方法

时间:2022-08-26 21:28:07
我想在一个TreeView控件中显示一棵树,该树如下:
   商品
      |-家电类
             |-电视机类
             |-冰箱类
      |—食品类
             |—奶粉类
             |—水果类
             |—其它类
        。
        。
        。
 每个类的下级分类都有是不确定数,如何设计表及显示出来。



16 个解决方案

#1


表设计如下:
parentid,id
家电类,电视机类
家电类,冰箱类
电视机类,TCL
电视机类,康佳
。。。。。
当然,你可以用代号来代表你的这些名称
其实这就是二维表的BOM结构
。。。。。

然后在展树的时候递归实现,论坛上很多这样的问题,给你一段的代码:
这是一段加载树的代码
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^.mcaption:='';
    p^.tcaption:=s;
    p^.num:=1;
    TNode:=Treeview1.Items.AddChildObject(TNode,p^.tcaption,p);
  end;
  with QR,treeview1 do
  begin
    Items.BeginUpdate;
    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^.mcaption:=s;
      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;
  Items.EndUpdate;
  end;
end;


下面是一段删除选中节点及子节点的代码(同时删除数据库中对应数据):
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;





#2


上面有申明一个记录类型来保存节点信息

#3


DBTreeView组件就简单的了

#4


主从关系,如果要无级的(分层不限制)就要在一个表里实现了

需要可以给你个库看看,记得有一个

#5


type
  FNodeInfo=^TNodeInfo;    //指针类型,存储对应节点信息
    TNodeInfo=Packed Record
       NodeId:String;        //节点
       NodeName:string;      //节点名称
       ParentId:string;      //父节点
    end;


procedure TFa_FDepartment.InitTree(Id: string; ParentNode: TTreeNode ;DTree:TTreeView;adoconn:tadoconnection);
var
    QryTmp:TadoQuery;
    MyNode,pernode:TTreeNode;
    TmpNodeInfo:FNodeInfo;
begin
    QryTmp:=TadoQuery.Create(nil);
    QryTmp.Connection :=adoconn;
    QryTmp.SQL.Add('Select * from HR_ORGANISESTRUCTURE');
    qrytmp.sql.add(' where SuperiorDept='''+Id+''''+' Order by SuperiorDept');
    QryTmp.Open;
    MyNode:=nil;
    while not QryTmp.Eof do
    begin
      New(TmpNodeInfo);
      TmpNodeInfo.Nodeid:=Trim(QryTmp.Fields[1].AsString);
      TmpNodeInfo.Parentid:=Trim(QryTmp.Fields[6].AsString);
      TmpNodeInfo.Nodename:=Trim(QryTmp.Fields[2].AsString);
      MyNode:=DTree.Items.AddChildObject(ParentNode,QryTmp.Fields[2].AsString,TmpNodeInfo);  //把所有节点当作子节点遍历
      mynode.ImageIndex:=0;
      InitTree(QryTmp.Fields[1].AsString ,MyNode,DTree,adoconn); //递归调用
      QryTmp.Next;
    end;
    QryTmp.Free;
end;

#6


递归太笨了,还是用队列来实现吧.选找到根结点进队,每一个出队时把它的下级结点进队,直到队空.

#7



              ↑↑↑ 
             ↑↑我↑↑
            ↑↑↑来↑↑↑
           ↑↑↑↑顶↑↑↑↑
          ↑↑↑↑↑↑↑↑↑↑↑ 

#8


--建立分类号关系表 
If object_id("sortt") is not null 
   drop table sortt 
go
create table sortt 
(
   sortid int primary key,         --分类号 
   motherid int null,              --母类号 
   name varchar(40) not null,      --类别名称 
   c1 varchar(200) null            --备注 
)
go

#9


学习

#10


其实 wdsimon() 说法是对了,只是在实现方法上不需要进行递归
一次仅仅展开一级的信息,需要展开下一级的信息,可以通过展开节点来生成下一层节点的信息

#11


哈哈哈!学习!!!!!!!UP!

#12


up

#13


up

#14


表结构:
iden iID, NodeName, iParentID
1    10000   商品        0
2    11000   家电类      10000
3    11001   电视机类    11000
...............................
等。
type
  PMenuNode=^TMenuNode;
  TMenuNode=record
     NodeID:integer;        
     NodeName:string; 
     ParentID:integer;        
   end;

procedure TForm1.InitTree;
var
  i:integer;
  ParentNode:TTreeNode;
begin
  query.SQL.Text := 'Select iID, NodeName, ParentID yourtable'
  query.Open;
  
  FillTree(nil, 0);
  i:= 0;
  while i < TreeView1.Items.Count do
  begin
    ParentNode := TreeView1.Items[i];
    FillTree(ParentNode, pMenuNode(ParentNode.Data)^.NodeID);
    i := i+1;
  end;
  TreeView.Items.EndUpdate;
  query.close;
  query.Filtered := false;
end

procedure TForm1.FillTree(ParentNode: TTreeNode;
   const ParentID: integer);
var
  pNode: PMenuNode;
  CurNode: TTreeNode;
begin

  query.Filter := 'iParentID=' + IntToStr(ParentID);
  query.Filtered:=true;
  query.First;

  while not query.Eof  do
  begin
    new(pNode);
    pNode^.NodeID := query.FieldByName('iID').AsInteger;
    pNode^.NodeName := trim(Query.FieldByName('NodeName').AsString);
    pNode^.ParentID := query.FieldByName('iParentID').AsInteger;

    if ParentNode=nil   then
    begin
      CurNode := TreeView1.Items.AddObject(nil,
                   pNode^.NodeName, pNode);
      CurNode.ImageIndex := 2;
      CurNode.SelectedIndex := 0;

    end
    else begin
      CurNode := TreeView1.Items.AddChildObject(ParentNode,
                   pNode^.NodeName, pNode);
      CurNode.ImageIndex := 1;
      CurNode.SelectedIndex := 1;
     
      Query.Next;
  end;
end;

基本如上,根据以前项目里的一段代码改的,没有调试,你自己在斟酌一下吧!

#15


在FillTree(nil,0)调用之前加:TreeView1.BeginUpdate

#16


http://expert.csdn.net/Expert/topic/2489/2489919.xml?temp=.5750391

有一例

#1


表设计如下:
parentid,id
家电类,电视机类
家电类,冰箱类
电视机类,TCL
电视机类,康佳
。。。。。
当然,你可以用代号来代表你的这些名称
其实这就是二维表的BOM结构
。。。。。

然后在展树的时候递归实现,论坛上很多这样的问题,给你一段的代码:
这是一段加载树的代码
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^.mcaption:='';
    p^.tcaption:=s;
    p^.num:=1;
    TNode:=Treeview1.Items.AddChildObject(TNode,p^.tcaption,p);
  end;
  with QR,treeview1 do
  begin
    Items.BeginUpdate;
    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^.mcaption:=s;
      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;
  Items.EndUpdate;
  end;
end;


下面是一段删除选中节点及子节点的代码(同时删除数据库中对应数据):
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;





#2


上面有申明一个记录类型来保存节点信息

#3


DBTreeView组件就简单的了

#4


主从关系,如果要无级的(分层不限制)就要在一个表里实现了

需要可以给你个库看看,记得有一个

#5


type
  FNodeInfo=^TNodeInfo;    //指针类型,存储对应节点信息
    TNodeInfo=Packed Record
       NodeId:String;        //节点
       NodeName:string;      //节点名称
       ParentId:string;      //父节点
    end;


procedure TFa_FDepartment.InitTree(Id: string; ParentNode: TTreeNode ;DTree:TTreeView;adoconn:tadoconnection);
var
    QryTmp:TadoQuery;
    MyNode,pernode:TTreeNode;
    TmpNodeInfo:FNodeInfo;
begin
    QryTmp:=TadoQuery.Create(nil);
    QryTmp.Connection :=adoconn;
    QryTmp.SQL.Add('Select * from HR_ORGANISESTRUCTURE');
    qrytmp.sql.add(' where SuperiorDept='''+Id+''''+' Order by SuperiorDept');
    QryTmp.Open;
    MyNode:=nil;
    while not QryTmp.Eof do
    begin
      New(TmpNodeInfo);
      TmpNodeInfo.Nodeid:=Trim(QryTmp.Fields[1].AsString);
      TmpNodeInfo.Parentid:=Trim(QryTmp.Fields[6].AsString);
      TmpNodeInfo.Nodename:=Trim(QryTmp.Fields[2].AsString);
      MyNode:=DTree.Items.AddChildObject(ParentNode,QryTmp.Fields[2].AsString,TmpNodeInfo);  //把所有节点当作子节点遍历
      mynode.ImageIndex:=0;
      InitTree(QryTmp.Fields[1].AsString ,MyNode,DTree,adoconn); //递归调用
      QryTmp.Next;
    end;
    QryTmp.Free;
end;

#6


递归太笨了,还是用队列来实现吧.选找到根结点进队,每一个出队时把它的下级结点进队,直到队空.

#7



              ↑↑↑ 
             ↑↑我↑↑
            ↑↑↑来↑↑↑
           ↑↑↑↑顶↑↑↑↑
          ↑↑↑↑↑↑↑↑↑↑↑ 

#8


--建立分类号关系表 
If object_id("sortt") is not null 
   drop table sortt 
go
create table sortt 
(
   sortid int primary key,         --分类号 
   motherid int null,              --母类号 
   name varchar(40) not null,      --类别名称 
   c1 varchar(200) null            --备注 
)
go

#9


学习

#10


其实 wdsimon() 说法是对了,只是在实现方法上不需要进行递归
一次仅仅展开一级的信息,需要展开下一级的信息,可以通过展开节点来生成下一层节点的信息

#11


哈哈哈!学习!!!!!!!UP!

#12


up

#13


up

#14


表结构:
iden iID, NodeName, iParentID
1    10000   商品        0
2    11000   家电类      10000
3    11001   电视机类    11000
...............................
等。
type
  PMenuNode=^TMenuNode;
  TMenuNode=record
     NodeID:integer;        
     NodeName:string; 
     ParentID:integer;        
   end;

procedure TForm1.InitTree;
var
  i:integer;
  ParentNode:TTreeNode;
begin
  query.SQL.Text := 'Select iID, NodeName, ParentID yourtable'
  query.Open;
  
  FillTree(nil, 0);
  i:= 0;
  while i < TreeView1.Items.Count do
  begin
    ParentNode := TreeView1.Items[i];
    FillTree(ParentNode, pMenuNode(ParentNode.Data)^.NodeID);
    i := i+1;
  end;
  TreeView.Items.EndUpdate;
  query.close;
  query.Filtered := false;
end

procedure TForm1.FillTree(ParentNode: TTreeNode;
   const ParentID: integer);
var
  pNode: PMenuNode;
  CurNode: TTreeNode;
begin

  query.Filter := 'iParentID=' + IntToStr(ParentID);
  query.Filtered:=true;
  query.First;

  while not query.Eof  do
  begin
    new(pNode);
    pNode^.NodeID := query.FieldByName('iID').AsInteger;
    pNode^.NodeName := trim(Query.FieldByName('NodeName').AsString);
    pNode^.ParentID := query.FieldByName('iParentID').AsInteger;

    if ParentNode=nil   then
    begin
      CurNode := TreeView1.Items.AddObject(nil,
                   pNode^.NodeName, pNode);
      CurNode.ImageIndex := 2;
      CurNode.SelectedIndex := 0;

    end
    else begin
      CurNode := TreeView1.Items.AddChildObject(ParentNode,
                   pNode^.NodeName, pNode);
      CurNode.ImageIndex := 1;
      CurNode.SelectedIndex := 1;
     
      Query.Next;
  end;
end;

基本如上,根据以前项目里的一段代码改的,没有调试,你自己在斟酌一下吧!

#15


在FillTree(nil,0)调用之前加:TreeView1.BeginUpdate

#16


http://expert.csdn.net/Expert/topic/2489/2489919.xml?temp=.5750391

有一例