myamanda

博客园 首页 新随笔 联系 订阅 管理

   一、表结构

    首先建立如下结构的数据表Code.DB,并输入一些测试数据

    其中,科目代码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。

    2. 单元main.pas的完整源代码如下:

    unit Main;

    interface

    uses

    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,SFirstN

odeTxt);

    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],Sh

owTxt);

    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键编译运行,运行的效果如图。只要在它的基础上加以完善,如增加维护功能,就可搬到实际应用中了。当然,本算法不单能用在科目代码上,其他类似的树型结构都能奏效。

    以上程序在中文Windows 9x、Delphi 4 C/S环境下编译通过。

posted on 2009-07-21 16:41  myamanda  阅读(227)  评论(0)    收藏  举报