基于数据库(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.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值