用树型结构表示科目代码的一种高效算法

原创 2000年08月26日 09:49:00
用树型结构表示科目代码的一种高效算法
松本电工实业有限公司电脑部
舒嵩嵩
---- 在很多常见的财务软件中,科目代码一般都用树型结构来显示。要实现这一点,通常的做法是用多个(嵌套)循环,甚至递归等算法,将科目表中的代码"织"成树,但这样不但算法复杂,而且执行效率低。本人在实际的开发应用中,摸索出一种简单高效的算法,在此和盆托出,只在抛砖引玉,找出最佳解决方案。下面介绍在Delphi中的实现方法。

一.表结构
---- 首先建立如下结构的数据表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;

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,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环境下编译通过。


 

对科目***货币 ***未定义汇率差额科目

解决: 维护 OBA1 -> KDF
  • zhongguomao
  • zhongguomao
  • 2015年06月19日 14:20
  • 1108

科目余额表代码

科目余额表代码/**公司名称代码开始**/Select t.* Into #AcctBal2569457n From (    Select 0 FBalanceTotal,a.FAccountID,...
  • sumeing
  • sumeing
  • 2010年10月25日 15:56
  • 1041

SAP FICO—总账科目

一、总账科目的概述 总账科目,它起到统驭整个财务的作用。不同的会计科目在总账主数据中创建会应用到不同的“字段”(field),通过这些不同“字段”的组合,就会形成系统能够识别并能够为我们现行会计...
  • xx4565715
  • xx4565715
  • 2015年01月15日 10:26
  • 648

SAP笔记-SD 销售订单 收入 和 成本 对应科目的逻辑

销售订单 收入 和 成本 对应科目的逻辑 (2009-02-19)一.收入:1.       销售订单类型 - > 单据定价过程    2.       单据定价过程->定价过程sorg :销售组织 ...
  • fangkailove
  • fangkailove
  • 2009年02月19日 15:05
  • 7693

C primer plus第10章(指针)习题

//下面每种情况中*ptr和*(ptr+2)的值分别是什么 int *ptr; int torf[2][2] = {12,14,16}; ptr = torf[0]; ...
  • dizzthxl
  • dizzthxl
  • 2013年03月04日 15:26
  • 1527

[基础题] 5.(*)按如下要求编写Java应用程序:(1)编写一个用于表示战斗能力的接口Fightable,

/*5.(*)按如下要求编写Java应用程序: (1)编写一个用于表示战斗能力的接口Fightable, 该接口包含:整型常量MAX; 方法void win(),用于描述战斗者获胜后的行为; 方法in...
  • hacker754
  • hacker754
  • 2017年11月23日 16:28
  • 127

总帐科目的批量传输与复制

一.说明 总帐科目(G/L Account)作为FI模块重要的主数据,维护工作量巨大,对于不同系统、不同公司之间的科目数据克隆,除使用常规批处理工具LSMW、SHDB等外,还可使用OBY9、FS15...
  • zhongguomao
  • zhongguomao
  • 2017年05月31日 15:46
  • 482

“库存商品”和“原材料”科目的使用区别?

如果是购买的成品或者商品,那么用“库存商品”科目 如果购买的是企业在生产中需要用到的原材料、燃料等,用“原材料”科目 参考一下准则中有关原材料和库存商品科目核算的内容: 1403 原...
  • zhongguomao
  • zhongguomao
  • 2016年05月05日 08:34
  • 1735

统驭科目的集成修改

SAP中的统驭科目指应收应付和资产相关科目一般设置成统驭科目(有分类账的总帐科目)。在创建GL主数据的时候指定;当你在创建客户或供应商主数据的时候,都会提示输入特别总帐标准,就会用到统驭科目,与会计科...
  • u010518863
  • u010518863
  • 2013年05月12日 22:31
  • 1132

蓝桥杯基础练习--十进制转十六进制

问题描述   十六进制数是在程序设计时经常要使用到的一种整数的表示方式。它有0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F共16个符号,分别表示十进制数的0至15。十六进制的计数方法...
  • er3456qi
  • er3456qi
  • 2014年02月21日 12:40
  • 1299
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用树型结构表示科目代码的一种高效算法
举报原因:
原因补充:

(最多只允许输入30个字)