给你点资料
一.表结构 
---- 首先建立如下结构的数据表code.db,并输入一些测试数据: 
字段名    类型    长度    说明
acode    字符型    20    科目代码
aname    字符型    30    科目代码名称
......    ......    ......    ......
表(一)  ---- 其中,科目代码acode的数据类型一定要字符型(一定),长度按具体要求而定,假如要支持六级编码,且代码结构是"3-2-2-2-2-2",则该字段的长度不小于18,而其他字段则不作要求 。另外,要为字段acode建一索引(切记),因为要用它来排序。 
二.编写程序 
---- 1.新建一project:codetree.drp,主窗体命名为frmmain,单元存为main.pas。在frmmain上添加一ttreeview控件,命名为tvecode,一个timagelist,命名为imgicon,并装入三个icon和bmp,最后添加一ttable控件,命名tblcode。 
frmmain和各控件的属性按表(二)设置:
组件          属性           设置
frmmain        caption          '科目代码'
        font        宋体 9号
        borderstyle    bsdialog
tvwcode        images          imgicon
        readonly    true
imgicon        imagelist    装入三个图标
btnclose    caption        关闭(c)
表(二)---- 2. 单元main.pas的完整源代码如下: 
unit main;interfaceuses
  windows, messages, sysutils, classes, graphics, 
controls, forms, dialogs,
  db, dbtables, comctrls, imglist, stdctrls;type
  tform1 = class(tform)
tvwcode: ttreeview;
tblcode: ttable;
imagelist1: timagelist;
btnclose: tbutton;
procedure formcreate(sender: tobject);
procedure btncloseclick(sender: tobject);
  private
{ private declarations }
function loadcode(crtbl:tdbdataset):integer;
function getlevel(sformat,scode:string):integer;
  public
{ public declarations }
  end;var
  form1: tform1;const
scodeformat = '322222';  //科目代码结构
sfirstnodetxt  = '科目代码';  //首节点显示的文字implementation{$r *.dfm}
//以下函数是本文的重点部分,
其主要功能是用一循环将code.db表中的
//科目代码和科目代码名称显示出来
function tform1.loadcode(crtbl:tdbdataset):integer;
var nowid,sname,showtxt:string;
i,level:integer;
mynode:array[0..6]of ttreenode;
//保存各级节点,最长支持6级(重点)
begin
screen.cursor:=crhourglass;
level:=0;
with crtbl do
begin
try
if not active then open;
first;
tvwcode.items.clear;
//以下是增加第一项
mynode[level]:=tvwcode.items.add
(tvwcode.topitem,sfirstnodetxt);
mynode[level].imageindex:=0;
mynode[level].selectedindex:=0;
//以上是增加第一项
while not eof do
begin
nowid:=trim(fieldbyname('acode').asstring);
showtxt:=nowid+' '+fieldbyname('aname').asstring;
level:=getlevel(scodeformat,nowid); 
//返回代码的级数
//以下是增加子项
//以下用上一级节点为父节点添加子节点
if level> 0 then//确保代码符合标准
begin
  mynode[level]:=tvwcode.items.addchild
(mynode[level-1],showtxt);
  mynode[level].imageindex:=1;
  mynode[level].selectedindex:=2;
end;  
//以上是增加子项
next;
end;
finally
close;
end;
end;
mynode[0].expand(false);//将首节点展开
screen.cursor:=crdefault;
end;
//以上函数将code.db表中的科目代码和科目代码名称显示出来//下面函数的功能是返回一代码的级数,
参数sformat传递科目代码结构;
//参数scode传递某一科目代码
function tform1.getlevel
(sformat,scode:string):integer;
var i,level,ilen:integer;
begin
level:=-1;//如果代码不符合标准,则返回-1
ilen:=0;
if (sformat<  > '')and(scode<  > '')then
for i:=1 to length(sformat) do
begin
ilen:=ilen+strtoint(sformat[i]);
if length(scode)=ilen then
begin
  level:=i;
  break;
end;
end;
result:=level;
end;
//上面函数的功能是返回一代码的级数procedure tform1.formcreate(sender: tobject);
begin
with tblcode do
begin
databasename:=paramstr(1); 
//使tblcode的databasename指向应用程序所在的路径
tablename:='code.db';  //指向数据表code.db
open;
indexfieldnames:='acode'; 
//按字段acode排序(不要漏掉)
end;
loadcode(tblcode);
end;procedure tform1.btncloseclick(sender: tobject);
begin
close;
end;end.---- 其中,常量scodeformat是科目代码的代码结构,其定义的规则一定要和数据表code..db中的字段acode的值相符。所以在实际应用中,让用户新增科目代码时,必须严格检查其规范性,只有完全符合事先定义的代码结构,才能添加入库。 
---- 函数getlevel是求某一科目代码的级数,例如,有一科目代码"10102",在代码结构是"322222"的情况下,调用函数getlevel('322222','10102')将返回整数2 。 ---- 当然,本文的核心是loadcode函数,该函数用了一个循环来遍历数据表code.db的所有记录,将字段acode和aname的内容按层次显示出来。而在该函数中定义的二维数组mynode[0..6],则显得优为重要,在这里,它作用类似于递归中的栈。因为在ttreeview添加子节点的方法addchild(node: ttreenode; const s: string)中,要为其指定一父节点作为参数,而父节点的代码级数一定是要添加节点的代码级数减1,所以只要用一数组来动态保存和指定父节点就成功了。 三.运行结果 
---- 好了,现在把code.db复制到和可执行文件相同的目录下,按下f9键编译运行,本人运行的效果如图(一)。只要在以上的基础上加以完善,如增加维护功能,就可搬到实际应用中了。当然,本算法不单能用在科目代码上,其他类似的树型结构都能奏效。本人就已将此算法应用于[科目代码]、[物料清单(bom)]、[库房管理]和[物料主文件]等多个模块中,取得令人满意的效果。 
---- 以上程序在中文windows 9x、delphi 4 c/s环境下编译通过。 

解决方案 »

  1.   

    谢谢,不过我的表中的节点使用一个iflag来标记其是主节点还是子节点,并有一个主节点编号标记其是哪一个主节点下的子节点,用一个while循环无法显示所有节点,
      

  2.   

    我程序里的一段,递归建军树,可以有无限层次,parent表示当前结点的父节点,id表示当前结点,也可以说是它是你程序中的iflag,因为它的所有子结点都指向它,源程序如下:
    procedure TForm8.LoadTreeView;
    var
      strsql,tid:string;
    begin
      try    DataModule3.ADOTable3.open;
        DataModule3.ADOTable3.Locate('DTname',RzComboBox1.Text,[lopartialkey]);
        tid:=inttostr(DataModule3.ADOTable3.FieldByName('id').value);
        strsql:='select * from T where TypeID='+tid;
        DQ.Active :=false;
        DQ.SQL.Clear ;
        DQ.SQL.Add(strsql);
        DQ.Active :=true;
        DQ.Filtered :=true;
        DQ.Filter := 'Parent=0';
        U_DiGui(0,seltv.TopItem );//从当前0层开始递归建树
      except
        showmessage('字典里没有数据!');
      end;
    end;
    procedure TForm8.U_DiGui(parentID:Cardinal;ParentNode:TTreeNode);
    var
      tmpTBData:array of TableData;
      i,j:integer;
      tmpNode:TTreeNode;begin
      j:=DQ.RecordCount;
      setlength(tmpTBData,j);//保存递规上一层结点值
      for i:=0 to j-1 do begin
        tmpTBData[i].ID := Cardinal(DQ.fieldbyname('ID').value);
        tmpTBData[i].Name  := DQ.fieldbyname('Name').value;
        tmpTBData[i].ParentID  := Cardinal(DQ.fieldbyname('Parent').value);
        DQ.Next;
      end;
      for i:=0 to j-1 do begin //递规调用建立所有结点
        tmpNode:=seltv.Items.AddChild(ParentNode,tmpTBData[i].Name);
     //   tmpNode.ImageIndex:=2;
        new(pData);
        pData^.ID:=tmpTBData[i].ID;
        tmpNode.Data:=pData;
        DQ.Filter := 'Parent=' + IntToStr(Integer(tmpTBData[i].ID));
        if DQ.RecordCount >0 then begin
          U_DiGui(tmpTBData[i].ID,tmpNode );
        end;
      end;
    end;
      

  3.   

    你用的什么数据库,ORACLE中的START WITH ..CONNECT BY ..PRIOR 方法可以选出按层次关系排序的顺序,在这个结果集上用一个循环就可以把树建好,速度比递归的办法快好几倍。
    我觉得建树之前先在记录的排列顺序上下点功夫,让它按层次排序还是很值得的!