程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 用樹型結構表示科目代碼的一種高效算法

用樹型結構表示科目代碼的一種高效算法

編輯:Delphi

用樹型結構表示科目代碼的一種高效算法
松本電工實業有限公司電腦部
舒嵩嵩
---- 在很多常見的財務軟件中,科目代碼一般都用樹型結構來顯示。要實現這一點,通常的做法是用多個(嵌套)循環,甚至遞歸等算法,將科目表中的代碼"織"成樹,但這樣不但算法復雜,而且執行效率低。本人在實際的開發應用中,摸索出一種簡單高效的算法,在此和盆托出,只在拋磚引玉,找出最佳解決方案。下面介紹在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環境下編譯通過。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved