生成树型结构有 2 种方法:
1. 动态生成树结点
2. 静态生成树结点
这里暂不讨论动态生成树, 先实现静态生成!
所谓静态生成树结点是指通过遍历数据源的方式一次性把所有树结点全部加载, 说起生成树避免不了谈起数据库结构的设计.
数据库设计的方法有 2 种:
1. 单编号法
单编号法是以每个类为统一编号, 如其有子类, 则顺着该编号向后排. 如水果编号为 001, 则苹果为水果的一类, 则应为 001001 等等, 这种方法易于统计, 但不易于维护! 如: 想要将苹果类变为其它的类, 且苹果类下有 N 层, 那会是一件比较麻烦的事情!
2. 双编号法
双编号也就是我们经常说的用 ID 与 PARENTID 来表示其父子关系, 维护起来比较方便, 但遍历会稍稍复杂一些!
无论哪种方法, 一般情况下都要创建结构体, 并把结构体指针放置到树结点中! 因为 Treeview 的树结点不可能放
置更多的信息, 我们通常要存该结点的名称 (中英文), 结点 ID, 是否为功能结点, 父结点, 图标, 选中结点后的图标, dll 的名称等等等...
以下例子:
- unit Unit1;
- interface
- uses
- Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls, ComCtrls, DB, ADODB;
- type
- PNodeInfoEx = ^TNodeInfoEx;
- TNodeInfoEx = Packed Record
- NodeID : Integer;
- ParentID : Integer;
- NodeType : Integer;
- ChnNodeTitle : String;
- ImageIndex: SmallInt;
- SelectedIndex: SmallInt;
- end;
- TForm1 = class(TForm)
- tv1: TTreeView;
- btn1: TButton;
- qry1: TADOQuery;
- procedure btn1Click(Sender: TObject);
- procedure FormDestroy(Sender: TObject);
- private
- { Private declarations }
- function StaticBuildTree(TreeView:TTreeView ):Boolean;
- function AddTreeItem(TreeView:TTreeView; AddNodeInfo:PNodeInfoEx):TTreeNode;
- function FindTreeItem(TreeView:TTreeView; CurNodeID:integer): TTreeNode;
- public
- { Public declarations }
- end;
- var
- Form1: TForm1;
- implementation
- {$R *.dfm}
- function TForm1.StaticBuildTree(TreeView:TTreeView ):Boolean;
- var
- AddNodeInfo : PNodeInfoEx;
- begin
- Result := False;
- qry1.LoadFromFile('c:/AdminixTree.xml');// 这里以 xml 文件做为数据源
- Treeview.Items.BeginUpdate;// 记住: 在进行批量添加数据时要使用 BeginUpdate, 来暂时关闭由于添加数据而触发的某些事件 (如 OnChange 事件等)
- Treeview.Items.Clear;// 清空 Treeview
- try
- try
- if qry1.RecordCount>0 then
- begin
- qry1.First;
- while Not qry1.Eof do
- begin
- New(AddNodeInfo) ;// 生成结构体
- AddNodeInfo^.NodeID := qry1.FieldByName('NODE_ID').AsInteger;
- AddNodeInfo^.ParentID := qry1.FieldByName('PARENT_ID').AsInteger;
- AddNodeInfo^.NodeType := qry1.FieldByName('NodeType').AsInteger;
- AddNodeInfo^.ChnNodeTitle := qry1.FieldByName('ChnNodeTitle').AsString;
- AddNodeInfo^.ImageIndex := qry1.FieldByName('ImageIndex').AsInteger;
- AddNodeInfo^.SelectedIndex := qry1.FieldByName('SelectedIndex').AsInteger;
- AddTreeItem(Treeview,AddNodeInfo);// 把结构体的指针存到 Treeview 中
- qry1.Next;
- end;
- end;
- except
- Application.MessageBox('生成树结点失败',MB_ICONSTOP+MB_OK);
- raise;// 向上级抛异常
- end;
- qry1.Close;
- Result := True;
- finally
- Treeview.Items.EndUpdate;
- end;
- end;
- // 在加入结点时, 应先判断加入的是父结点还是子结点, 判断的依据是在已存在的树结点中是否存在该结点的 ParentID
- function TForm1.AddTreeItem(TreeView:TTreeView; AddNodeInfo:PNodeInfoEx):TTreeNode;
- var
- ParentNode: TTreeNode;
- begin
- ParentNode := FindTreeItem(Treeview,AddNodeInfo^.ParentID);
- If ParentNode <> nil then
- Result := Treeview.Items.AddChildObject(ParentNode, Trim(AddNodeInfo.ChnNodeTitle), Pointer(AddNodeInfo))
- else
- Result := Treeview.Items.AddObject(ParentNode, Trim(AddNodeInfo.ChnNodeTitle), Pointer(AddNodeInfo));
- if Result<>nil then
- begin
- Result.ImageIndex := AddNodeInfo.ImageIndex;
- Result.SelectedIndex := AddNodeInfo.SelectedIndex;
- end;
- end;
- // 这里是判断是否存在其父结点
- function TForm1.FindTreeItem(TreeView:TTreeView; CurNodeID:integer): TTreeNode;
- var
- i : Integer;
- begin
- Result := nil;
- for i := 0 to Treeview.Items.Count-1 do
- begin
- if CurNodeID=PNodeInfoEx(Treeview.Items[i].Data)^.NodeID then
- begin
- Result := Treeview.Items[i];
- Exit;
- end;
- end;
- end;
- // 生成树结构
- procedure TForm1.btn1Click(Sender: TObject);
- begin
- StaticBuildTree (tv1)
- end;
- // 在窗体释放时一定要把树结点中的结构体指针给释放掉, 对于在 Dispose 时为什么要进行强制转型后释放, 以前有专门的讲解, 在此不在累述
- procedure TForm1.FormDestroy(Sender: TObject);
- var
- i : Integer;
- begin
- for i := 0 to tv1.Items.Count-1 do
- begin
- Dispose( PNodeInfoEx(tv1.Items[i].Data) )
- end;
- end;
- end.
- // 如何访问树结点?
- procedure TForm1.tv1MouseDown(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X, Y: Integer);
- var
- pNode:TTreeNode;
- begin
- pNode:=tv1.GetNodeAt(x,y);
- if (pNode<>nil) and (Button=mbleft) then
- ShowMessage(PNodeInfoEx(pNode.Data)^.ChnNodeTitle);
- end;
来源: http://www.bubuko.com/infodetail-3524504.html