1. 先建立编码表:city_tree(bianma,cityname)。

2. 新建一个项目,按默认保存。

3. 新建一公共单元pubvar,在其中定义以下常量:

Const

cTreeCodeFormat = ‘222’;//编码格式为 XX XX XX

cTreeMaxLevel = 3;//最大编码层次

cTreeRootTxt = ‘城市’;//树根结点名称

这样做为了提高程序的通用性,以后用于其他代码字典的维护时,只需要更改这些特征常量。

4. 程序源代码:

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DB, DBTables, ImgList, ComCtrls , PubVar, Grids, DBGrids, Menus , StrUtils, StdCtrls;


type

TForm1 = class(TForm)

Tree: TTreeView;

ImageList1: TImageList;

Table1: TTable;

DataSource1: TDataSource;

DBGrid1: TDBGrid;

PopupMenu1: TPopupMenu;

AddMenu: TMenuItem;

DeleteMenu: TMenuItem;

RenameMenu: TMenuItem;

Query1: TQuery;

DataSource2: TDataSource;

procedure AddMenuClick(Sender: TObject);//点击增加子项菜单

procedure RenameMenuClick(Sender: TObject);//点击重命名菜单

procedure DeleteMenuClick(Sender: TObject); //点击删除该项菜单

procedure FormCreate(Sender: TObject);

procedure TreeClick(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

procedure LoadTree(treeDB:TDBDataSet);//初始化树

procedure UpdateTree(curNode:TTreenode; nodeTxt:string; state:string);//更新树

function GetNodeLevel(sFormat,sCode:string):integer;//获得节点层数

function GetCurrChildNodeMaxMa(curNode:TTreenode):string;

//获得当前节点子节点的最大编码

function GetCurrentNodeBianma(curNode:TTreenode):string;//获得当前节点的编码

procedure UpdateTable(bianma:string; cityname:string ;state:string); //更新数据库

end;


var

Form1: TForm1;

CurrentTreeNode: TTreeNode;

// AddChildeTreeNode: TTreeNode;

// flag:boolean; //用于标识是否需要在重命名树结点时更新数据


implementation

uses AddChildUnit,RenameItemUnit;

{$R *.dfm}


procedure TForm1.LoadTree(treeDB:TDBDataSet);//初始化树

var

curID,nodeTxt:string;

level:integer;

mynode:array[0..3] of TTreenode;

begin //初始化变量

Screen.Cursor:=crHourGlass;

tree.Enabled:=True;

tree.Items.Clear;

level:=0 ;

//设置根节点

mynode[level]:=tree.items.add(Tree.Topitem,cTreeRootTxt);

mynode[level].ImageIndex:=1;

//遍历数据表,利用编码字段记录排序规律,依次添加树节点

with treeDB do

begin

try

if not Active then open;

first;

while not Eof do

begin

curID:=trim(FieldByName('bianma').AsString);

nodeTxt:=curID+'-'+trim(FieldByName('cityname').AsString);

level:=GetNodeLevel(cTreeCodeFormat,curID);

//这里返回代码的层次数

if level>0 then

begin

//增加下一节点时,用添加子节点的方法可轻松实现节点间的层次关系

//注意:这里的父节点是用当前节点的上一级节点mynode[level-1]

mynode[level]:= tree.items.addchild(mynode[level-1],nodeTxt);

mynode[level].ImageIndex:=2;

end;

next;//下一条记录

end;

finally

close;

End;

mynode[0].expand(False);

Screen.Cursor:=crDefault;

end;

end;


function TForm1.GetNodeLevel(sFormat,sCode:string):integer;//获得节点层数

var i,level,iLen:integer;

begin

level:=-1 ;

iLen:=0;

if (sFormat<>'') and (sCode<>'') then

for i:=1 to Length(sFormat) do //分析编码格式,找出当前代码层次

begin

iLen:=iLen+StrToInt(sFormat);
if Length(sCode)=iLen then
begin level:=i; break; end;
end;
result:=level;
end;

//以下过程在新增、删除、修改记录时,同步更新树形结构
procedure TForm1.UpdateTree(curNode:TTreenode; nodeTxt:string; state:string);
Begin
if UpperCase(state)='ADD' then
begin
curNode:=tree.items.addchild(curNode,nodeTxt);
curNode.ImageIndex:=2;
end;
if UpperCase(state)='DEL' then
begin
curNode.DeleteChildren;
curNode.delete;
end;
if UpperCase(state)='EDI' then curNode.Text:=nodeTxt;
end;

procedure TForm1.AddMenuClick(Sender: TObject);//点击增加子项菜单
var AddChildText, AddTableText,maxbianma : string;
begin
AddChildForm.Label1.Caption:='为&quot;'+CurrentTreeNode.Text+'&quot;增加子项 ';
if AddChildForm.ShowModal=mrOk then
begin
AddChildText:=AddChildForm.Edit1.Text;
maxbianma:=GetCurrChildNodeMaxMa(CurrentTreeNode);
if (CurrentTreeNode.Text='城市') and (maxbianma='1000') then
maxbianma:='11'//如果当前节点为根节点,且只有一个子节点,使增加节点编码为11
else if CurrentTreeNode.Text='城市' then
maxbianma:=IntToStr(StrToInt(LeftStr(maxbianma,2))+1)
else
maxbianma:=IntToStr(StrToInt(maxbianma)+1); //使子项编码自动增1
if maxbianma<>'0' then
begin
//增加树子层
AddTableText:=maxbianma+'-'+AddChildText;
UpdateTree(CurrentTreeNode,AddTableText,'add'); //更新树
UpdateTable(maxbianma,AddChildText,'add'); //更新表
ShowMessage('添加成功!');
end
else ShowMessage('此层为最低子层,不能在该层增加子层');
AddChildForm.Edit1.Text:='';
end;
end;

function TForm1.GetCurrChildNodeMaxMa(curNode:TTreenode):string;
//获得当前节点子节点的最大编码
var
aSQL,maxbianma:string;
li_pos:integer;
begin
li_pos:=pos('-',curNode.Text);
if li_pos=7 then
begin result:='-1'; exit; end;
if (li_pos=0) and (not(curNode.HasChildren)) then // 如果当前节点为根节点并且没有子节点
begin
result:='9'; //使根节点第一个节点编码为10
exit;
end
else begin
aSQL:='select bianma from city_tree where bianma like &quot;' + MidStr(curNode.Text, 1, li_pos-1) + '%&quot;';
Query1.UnPrepare;
Query1.Close;
Query1.SQL.Clear;
Query1.SQL.Text:=aSQL;
Query1.Prepare;
Query1.ExecSQL;
Query1.Active:=true;
Query1.Last;
maxbianma:=Query1.fieldbyname('bianma').AsString;
if Query1.RecordCount=1 then//如果当前项没有子项
maxbianma:=maxbianma+'00';
Query1.Active:=false;
end;
result:=maxbianma;
end;

procedure TForm1.RenameMenuClick(Sender: TObject);//点击重命名菜单
var
bianma:string;
itemtext:string; //用于重命名时保存输入的Edit.text
begin
RenameItemForm.Label1.Caption:='将&quot;'+CurrentTreeNode.Text+'&quot;命名为 ';
if RenameItemForm.ShowModal=mrOk then
begin
itemtext:=RenameItemForm.Edit1.Text;
bianma:=GetCurrentNodeBianma(CurrentTreeNode);
Table1.Locate('bianma',bianma,[]);
UpdateTable('',itemtext,'edi');
itemtext:=bianma+'-'+itemtext;
UpdateTree(CurrentTreeNode,itemtext,'edi');
ShowMessage('重命名成功!');
end;
end;
//以下过程在新增、删除、修改记录时,同步更新数据库表
procedure TForm1.UpdateTable(bianma:string; cityname:string ;state:string); //更新数据库
begin
if state='add' then
begin
Table1.Active:=True;
Table1.Insert;
Table1.SetFields([bianma,cityname]);
Table1.Post;
end;
if state='del' then
begin
Table1.Active:=True;
Table1.Locate('bianma',bianma,[]);
Table1.Delete;
end;
if state='edi' then
begin
Table1.Edit;
Table1.FieldByName('cityname').AsString:=cityname;
Table1.Post;
end;
end;

procedure TForm1.DeleteMenuClick(Sender: TObject); //点击删除该项菜单
var
bianma:string;
begin
CurrentTreeNode.expand(False);
if CurrentTreeNode.Text='城市' then //如果当前节点为根节点
begin
ShowMessage('不能删除根节点');
exit;//退出该过程
end;
if CurrentTreeNode.HasChildren then //如果当前节点具有子项
begin
ShowMessage('请先删除其子项');
exit;//退出该过程
end;
if Application.MessageBox(PChar('真的要删除&quot;'+CurrentTreeNode.Text+'&quot;这项吗?'),'警告',MB_YESNO)=mrYES then
begin
bianma:=GetCurrentNodeBianma(CurrentTreeNode);
UpdateTree(CurrentTreeNode,'','del');
UpdateTable(bianma,'','del');
ShowMessage('删除成功!');
Table1.Refresh;//更新TBGrid控件中的显示
Table1.Active:=true;
CurrentTreeNode:=Form1.tree.selected;
end;
end;

function TForm1.GetCurrentNodeBianma(curNode:TTreeNode):string;//获得当前节点的编码
var
li_pos:integer;
bianma:string;
begin
li_pos:=pos('-',curNode.Text);
bianma:=MidStr(curNode.Text,1,li_pos-1);
result:=bianma;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
LoadTree(Table1);
Table1.Active:=true;
end;

procedure TForm1.TreeClick(Sender: TObject);
begin
CurrentTreeNode:=Form1.tree.selected; //获得当前节点
end;

end.

unit PubVar;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, DbTables, StdCtrls, ExtCtrls, Buttons, Dialogs,Registry,Db, ComCtrls;

const
cTreeCodeFormat='222'; //编码格式:xx xx xx
cTreeMaxLevel=3; //最大编码(树节点)层次
cTreeRootTxt='城市'; //树的根节点名称
implementation
end.