基于数据库(access)层次编码记录对TreeView的操作(实现自动编码,灵活控制编码规则和编码层次)...
{-----------------------------------------------------------------------------
根据有规则的编码层次结构数据构建TreeView
使用时直接引用此单元即可。
最后修改:米铁强
最后完成日期:2009-7-7
-----------------------------------------------------------------------------}
unit U_LevelDBTree;
interface
uses ComCtrls, ADODB, DB, Classes, SysUtils, StrUtils, windows, Controls, forms,
math;
{-----------------------------------------------------------------------------
定义的常量值,通过更改此处的内容,可以灵活的改变树的编码格式及层次。
-----------------------------------------------------------------------------}
const
cTreeCodeFormat = '222'; //编码格式为 XX XX XX
cTreeMaxLevel = 3; //最大编码层次
cTreeRootTxt = '商品类别'; //树根结点名称
{-----------------------------------------------------------------------------
函数名称:LoadTree
功能:根据数据库记录初始化树
参数及说明:tree:目标Treeview,treeDB:数据集,sID:字段名称,sCaption:字段名称。
返回值:无
-----------------------------------------------------------------------------}
procedure LoadTree(tree: Ttreeview; treeDB: TADOTable; sID, sCaption: string);
{-----------------------------------------------------------------------------
函数名称:GetNodeLevel
功能:获取某一节点的层次
参数及说明:sFormat:编码格式, sCode:编码。
返回值:integer
-----------------------------------------------------------------------------}
function GetNodeLevel(sFormat, sCode: string): integer;
{-----------------------------------------------------------------------------
函数名称:MaxCount
功能:得到某一层次的最大允许节点数量
参数及说明:sLevel:层次。
返回值:integer
-----------------------------------------------------------------------------}
function MaxTotal(sLevel: integer): Integer;
{----------------------------------------------------------------------------
函数名称:GetCurrentNodeCode
功能:得到当前节点的编码
参数及说明:curNode:当前节点。
返回值:string
-----------------------------------------------------------------------------}
function GetCurrentNodeCode(curNode: TTreeNode): string;
{-----------------------------------------------------------------------------
函数名称:GetNewCode
功能:得到新建节点的编码
参数及说明:TempDB:临时查询;sID:字段名称;sTable:表名称,curNode:当前节点,
Child:新建节点是否为子节点。
返回值:string
-----------------------------------------------------------------------------}
function GetNewCode(TempDB: TAdoquery; sID, sTable: string; curNode: TTreenode;
Child: boolean): string;
{-----------------------------------------------------------------------------
函数名称:UpdateTreeAndDB
功能:同步更新树结构和数据库内容(包括新增、删除、修改)
参数及说明:tree: 需要操作的树; CurTreeNode: 当前节点; treeDB: 数据表; sid, sCaption:字段名称;
nodeTxt:字段值, state: 操作状态; NewID: 新节点编号,默认为''。
返回值:无
-----------------------------------------------------------------------------}
procedure UpdateTreeAndDB(tree: TTreeView; CurTreeNode: TTreeNode; treeDB:
TADOTable; sid, sCaption, nodeTxt, state: string; NewID: string = '');
{-----------------------------------------------------------------------------
函数名称:UpdateTable
功能:同步数据库内容(包括新增、删除、修改)(内部参数)
参数及说明:treeDB: 关联的数据表; sid, sCaption:字段名称; ClassID, ClassName:
字段值; state: 操作状态。
返回值:无
-----------------------------------------------------------------------------}
procedure UpdateTable(treeDB: TADOTable; sid, sCaption, ClassID, ClassName:
string; state: string);
implementation
procedure LoadTree(tree: Ttreeview; treeDB: TADOTable; sID, sCaption: string);
//初始化树
var
curID, nodeTxt: string;
level: integer;
mynode: array[0..cTreeMaxLevel] of TTreenode;
begin //初始化变量
tree.Items.BeginUpdate;
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
Filtered := False;
if not Active then
open;
first;
while not Eof do
begin
curID := trim(FieldByName(sID).AsString);
nodeTxt := curID + '-' + trim(FieldByName(sCaption).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(true); //这里指明根节点是否展开;
tree.Items.EndUpdate;
mynode[0].Selected := True; //选择根节点
tree.SetFocus;
end;
end;
function 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[i]);
if Length(sCode) = iLen then
begin
level := i;
break;
end;
end
else
if (sFormat <> '') and (sCode = '') then
level := 0;
result := level;
end;
function MaxTotal(sLevel: integer): Integer; //得到某一层次的最大允许节点数量
var
m, i: integer;
tmp: string;
begin
tmp := '';
m := StrToInt(ctreecodeformat[slevel]);
for i := 1 to m do
begin
tmp := tmp + '9';
end;
Result := StrToInt(tmp);
end;
//给新建节点自动编码
function GetNewCode(TempDB: TAdoquery; sID, sTable: string; curNode: TTreenode;
Child: boolean): string;
var
tmpSQL: string;
i, NodeLevel, n: Integer;
NodeCode: string;
preZero, surZero, Prefix, surfix: string; //前缀 ,后缀
min, max: string; //查询区间
cMaxTotal, ChildMaxTotal, icount: Integer;
begin
icount := 0;
NodeCode := getcurrentNodeCode(curNode);
NodeLevel := GetNodeLevel(cTreeCodeFormat, nodecode);
tmpSQL :=
'select %s from %s where (%s > "%s") and (%s <= "%s") and (len(%s) = len("%s"))order by %s';
{ tmpSQL :=
'select %s from %s where (cvar(%s) > %s) and (cvar(%s) <= %s) order by %s';}
preZero := ''; //初始化前缀补零数量
surZero := ''; //初始化后缀补零数量
for i := 1 to StrToInt(cTreeCodeFormat[1]) - 1 do
preZero := preZero + '0'; //前面需补零的数量,这是固定的
if Child then //如果新建节点是子节点
begin
if NodeLevel = ctreemaxlevel then
begin
MessageBox(Application.Handle,
PChar(Format('系统允许的最大嵌套层次为%d层,无法添加子项。',
[ctreemaxlevel])),
'警告', MB_OK + MB_ICONWARNING);
end;
Prefix := NodeCode;
//cMaxTotal := MaxTotal(NodeLevel);
ChildMaxTotal := MaxTotal(Nodelevel + 1);
for i := 1 to StrToInt(cTreeCodeFormat[NodeLevel + 1]) - 1 do
begin
surZero := surZero + '0'
end;
surfix := surZero + '1';
end
else //如果是新增同级节点
begin
if NodeLevel < 1 then //根目录无法增加同级节点
begin
MessageBox(application.Handle, '根目录下只能新增子项目。', '警告', MB_OK +
MB_ICONWARNING);
Result := '';
Exit;
end
else
begin
for i := 1 to NodeLevel - 1 do
icount := icount + StrToInt(MidStr(cTreeCodeFormat, i, 1));
Prefix := LeftStr(nodecode, icount);
//cMaxTotal := MaxTotal(NodeLevel - 1);
ChildMaxTotal := MaxTotal(Nodelevel);
for i := 1 to StrToInt(cTreeCodeFormat[NodeLevel]) - 1 do
begin
surzero := surzero + '0'
end;
surfix := surzero + '1';
end;
end;
min := prefix + surzero + '0';
max := Prefix + IntToStr(Childmaxtotal);
tmpSQL := Format(tmpSQL, [sID, sTable, sID, min, sID, max, sID, max, sID]);
TempDB.Close;
TempDB.SQL.text := tmpsql;
TempDB.Open;
TempDB.last;
if TempDB.RecordCount < 1 then //如果没有节点,则从第1个节点编起。
Result := Prefix + surfix
else
if TempDB.fieldbyname(sID).asstring < max then
begin
if Child then
for i := 1 to NodeLevel + 1 do
n := n + strtoint(midstr(cTreeCodeFormat, NodeLevel - 1, 1))
else
for i := 1 to NodeLevel do
n := n + strtoint(midstr(cTreeCodeFormat, NodeLevel - 1, 1));
if (Length(IntToStr(TempDB.fieldbyname(sID).AsInteger)) < n) and (TempDB.fieldbyname(sID).AsInteger <> 9)then //自动补"0"
result := prezero + IntToStr(TempDB.fieldbyname(sID).asinteger + 1)
else
result := IntToStr(TempDB.fieldbyname(sID).asinteger + 1);
end
else
begin
MessageBox(Application.Handle,
'当前项目已达到允许的最大数量,无法继续添加。',
'警告', MB_OK + MB_ICONWARNING);
Result := '';
end;
end;
function GetCurrentNodeCode(curNode: TTreeNode): string;
//获得当前节点的编码
var
li_pos: integer;
ClassID: string;
begin
li_pos := pos('-', curNode.Text);
ClassID := MidStr(curNode.Text, 1, li_pos - 1);
result := ClassID;
end;
//以下过程在新增、删除、修改记录时,同步更新树形结构和数据库
procedure UpdateTreeAndDB(tree: TTreeView; CurTreeNode: TTreeNode; treeDB:
TADOTable; sid, sCaption, nodeTxt, state: string; NewID: string = '');
var
tmpNode: TTreeNode;
oldid: string;
begin
oldid := GetCurrentNodeCode(CurTreeNode);
if UpperCase(state) = 'ADD' then //添加平级节点
begin
CurTreeNode := tree.items.add(curtreenode, NewID + '-' + nodeTxt);
CurTreeNode.ImageIndex := 2;
end;
if UpperCase(state) = 'ADDCHILD' then //添加子节点
begin
CurTreeNode := tree.items.addchild(curtreenode, NewID + '-' + nodeTxt);
CurTreeNode.ImageIndex := 2;
end;
if UpperCase(state) = 'DEL' then
begin
if CurTreeNode.Level = 0 then
begin
MessageBox(Application.Handle, '根节点无法删除。', '错误', MB_OK +
MB_ICONSTOP);
exit;
end;
try
tmpNode := CurTreeNode.GetPrev;
except
try
tmpNode := CurTreeNode.Getnext;
except
tmpNode := CurTreeNode.Parent;
end;
end;
NewID := GetCurrentNodeCode(CurTreeNode);
CurTreeNode.DeleteChildren;
CurTreeNode.delete;
CurTreeNode := tmpNode;
end;
if UpperCase(state) = 'EDIT' then
begin
CurTreeNode.Text := NewID + '-' + nodeTxt;
end;
CurTreeNode.Selected := true;
treeDB.Active := true;
treeDB.Locate(sid, oldID, []);
UpdateTable(treeDB, sid, sCaption, Newid, nodetxt, state); //更新表
end;
//以下过程在新增、删除、修改记录时,同步更新数据库表
procedure UpdateTable(treeDB: TADOTable; sid, sCaption, ClassID, ClassName:
string; state: string);
begin
if (UpperCase(state) = 'ADD') or (UpperCase(state) = 'ADDCHILD') then
begin
//treeDB.Active := True;
treeDB.Insert;
treeDB.SetFields([ClassID, ClassName]);
treeDB.Post;
end;
if UpperCase(state) = 'DEL' then
begin
//treeDB.Active := True;
treeDB.Filtered := False;
treeDB.Filter := sid + ' like ' + QuotedStr(classid + '%');
treeDB.Filtered := True;
treeDB.First;
while not treeDB.Eof do
begin
treeDB.Delete;
end;
treeDB.Filtered := False;
end;
if UpperCase(state) = 'EDIT' then
begin
//treeDB.Active := True;
treeDB.Edit;
treeDB.FieldByName(sid).AsString := ClassID;
treeDB.FieldByName(scaption).AsString := ClassName;
treeDB.Post;
end;
end;
end.
转载于:https://www.cnblogs.com/piaoliuxia/archive/2008/10/17/1937284.html