您的位置:首页 > 编程语言 > Delphi

Delphi实现树型结构

2012-02-21 11:01 274 查看
生成树型结构有2种方法:

1.动态生成树结点

2.静态生成树结点

这里暂不讨论动态生成树,先实现静态生成!

所谓静态生成树结点是指通过遍历数据源的方式一次性把所有树结点全部加载,说起生成树避免不了谈起数据库结构的设计。

数据库设计的方法有2种:

1.单编号法

单编号法是以每个类为统一编号,如其有子类,则顺着该编号向后排。如水果编号为001,则苹果为水果的一类,则应为001001等等,这种方法易于统计,但不易于维护!如:想要将苹果类变为其它的类,且苹果类下有N层,那会是一件比较麻烦的事情!

2.双编号法

双编号也就是我们经常说的用ID与PARENTID来表示其父子关系,维护起来比较方便,但遍历会稍稍复杂一些!

无论哪种方法,一般情况下都要创建结构体,并把结构体指针放置到树结点中!因为Treeview的树结点不可能放

置更多的信息,我们通常要存该结点的名称(中英文)、结点ID、是否为功能结点、父结点、图标、选中结点后的图标、dll的名称等等等...

以下例子:

01.unit Unit1;
02.interface
03.uses
04.  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
05.  Dialogs, StdCtrls, ComCtrls, DB, ADODB;
06.type
07.  PNodeInfoEx = ^TNodeInfoEx;
08.  TNodeInfoEx = Packed Record
09.      NodeID    : Integer;
10.      ParentID  : Integer;
11.      NodeType  : Integer;
12.      ChnNodeTitle : String;
13.      ImageIndex: SmallInt;
14.      SelectedIndex: SmallInt;
15.   end;
16.  TForm1 = class(TForm)
17.    tv1: TTreeView;
18.    btn1: TButton;
19.    qry1: TADOQuery;
20.    procedure btn1Click(Sender: TObject);
21.    procedure FormDestroy(Sender: TObject);
22.  private
23.    { Private declarations }
24.    function StaticBuildTree(TreeView:TTreeView ):Boolean;
25.    function AddTreeItem(TreeView:TTreeView; AddNodeInfo:PNodeInfoEx):TTreeNode;
26.    function FindTreeItem(TreeView:TTreeView; CurNodeID:integer): TTreeNode;
27.  public
28.    { Public declarations }
29.  end;
30.var
31.  Form1: TForm1;
32.implementation
33.{$R *.dfm}
34.
35.function TForm1.StaticBuildTree(TreeView:TTreeView ):Boolean;
36.var
37.  AddNodeInfo : PNodeInfoEx;
38.begin
39.  Result := False;
40.  qry1.LoadFromFile('c:/AdminixTree.xml');//这里以XML文件做为数据源
41.  Treeview.Items.BeginUpdate;//记住:在进行批量添加数据时要使用BeginUpdate,来暂时关闭由于添加数据而触发的某些事件(如OnChange事件等)
42.  Treeview.Items.Clear;//清空Treeview
43.  try
44.    try
45.      if qry1.RecordCount >0 then
46.        begin
47.          qry1.First;
48.          while Not qry1.Eof do
49.          begin
50.            New(AddNodeInfo) ;//生成结构体
51.            AddNodeInfo^.NodeID := qry1.FieldByName('NODE_ID').AsInteger;
52.            AddNodeInfo^.ParentID := qry1.FieldByName('PARENT_ID').AsInteger;
53.            AddNodeInfo^.NodeType := qry1.FieldByName('NodeType').AsInteger;
54.            AddNodeInfo^.ChnNodeTitle := qry1.FieldByName('ChnNodeTitle').AsString;
55.            AddNodeInfo^.ImageIndex := qry1.FieldByName('ImageIndex').AsInteger;
56.            AddNodeInfo^.SelectedIndex := qry1.FieldByName('SelectedIndex').AsInteger;
57.            AddTreeItem(Treeview,AddNodeInfo);//把结构体的指针存到Treeview中
58.            qry1.Next;
59.          end;
60.        end;
61.    except
62.      Application.MessageBox('生成树结点失败',MB_ICONSTOP+MB_OK);
63.      raise;//向上级抛异常
64.    end;
65.    qry1.Close;
66.    Result := True;
67.  finally
68.    Treeview.Items.EndUpdate;
69.  end;
70.end;
71.//在加入结点时,应先判断加入的是父结点还是子结点,判断的依据是在已存在的树结点中是否存在该结点的ParentID
72.function TForm1.AddTreeItem(TreeView:TTreeView; AddNodeInfo:PNodeInfoEx):TTreeNode;
73.var
74.    ParentNode: TTreeNode;
75.begin
76.    ParentNode := FindTreeItem(Treeview,AddNodeInfo^.ParentID);
77.    If ParentNode <> nil then
78.        Result := Treeview.Items.AddChildObject(ParentNode, Trim(AddNodeInfo.ChnNodeTitle), Pointer(AddNodeInfo))
79.    else
80.        Result := Treeview.Items.AddObject(ParentNode, Trim(AddNodeInfo.ChnNodeTitle), Pointer(AddNodeInfo));
81.    if Result<>nil then
82.    begin
83.        Result.ImageIndex    := AddNodeInfo.ImageIndex;
84.        Result.SelectedIndex := AddNodeInfo.SelectedIndex;
85.    end;
86.end;
87.//这里是判断是否存在其父结点
88.function TForm1.FindTreeItem(TreeView:TTreeView; CurNodeID:integer): TTreeNode;
89.var
90.    i : Integer;
91.begin
92.  Result := nil;
93.  for i := 0 to Treeview.Items.Count-1 do
94.  begin
95.      if CurNodeID=PNodeInfoEx(Treeview.Items[i].Data)^.NodeID then
96.      begin
97.          Result := Treeview.Items[i];
98.          Exit;
99.      end;
100.  end;
101.end;
102.//生成树结构
103.procedure TForm1.btn1Click(Sender: TObject);
104.begin
105.   StaticBuildTree (tv1)
106.end;
107.//在窗体释放时一定要把树结点中的结构体指针给释放掉,对于在Dispose时为什么要进行强制转型后释放,以前有专门的讲解,在此不在累述
108.procedure TForm1.FormDestroy(Sender: TObject);
109.var
110.    i : Integer;
111.begin
112.  for i := 0 to tv1.Items.Count-1 do
113.  begin
114.       Dispose( PNodeInfoEx(tv1.Items[i].Data)  )
115.  end;
116.end;
117.end.
01.//如何访问树结点?
02.procedure TForm1.tv1MouseDown(Sender: TObject; Button: TMouseButton;
03.  Shift: TShiftState; X, Y: Integer);
04.var
05.  pNode:TTreeNode;
06.begin
07.  pNode:=tv1.GetNodeAt(x,y);
08.  if (pNode<>nil) and  (Button=mbleft) then
09.   ShowMessage(PNodeInfoEx(pNode.Data)^.ChnNodeTitle);
10.end;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: