预步骤第一步,定义数据结构
type
PMyRec = ^TMyRec;
TMyRec = record
Caption: WideString;
end;
预步骤第二步,规定取得节点数据时候的大小
procedure
TMainForm.FormCreate(Sender: TObject);
begin
VST.NodeDataSize :=
SizeOf(TMyRec); // 如果没用到数据,貌似屏蔽也没关系
// VST.RootNodeCount := 20; //
可以尝试指定节点数据
end;
第一步,初始化节点的内容(赋值):
procedure
TMainForm.VSTInitNode(Sender: TBaseVirtualTree; ParentNode, Node:
PVirtualNode;
var InitialStates: TVirtualNodeInitStates);
var
Data:
PMyRec;
begin
with Sender do
begin
Data :=
GetNodeData(Node); // 只是取得当前节点的指针而已,其内容仍需程序员处理
//
建立每个节点的数据,注意每个节点只触发一次。
//
为数据赋值,一次赋值,永远拥有。而不是每次重复赋值。异步显示刚增加的数据
Data.Caption := Format(‘Level %d, Index
%d‘, [GetNodeLevel(Node), Node.Index]);
end;
end;
第二步,定义某个GetText函数,用来自动随时取得某个节点的数据:
procedure
TMainForm.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column:
TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
Data:
PMyRec;
begin
// A handler for the OnGetText event is always needed as
it provides the tree with the string data to display.
// Note that we are
always using WideString.
Data := Sender.GetNodeData(Node);
if
Assigned(Data) then Text := Data.Caption; //
这句非必要,是在写窗口的Caption,但很好的演示了取到数据以后可以做很多事情
end;
第三步,增加根节点,或者子节点。或者清除所有节点:VST.Clear;
procedure
TMainForm.AddButtonClick(Sender: TObject);
var
Start:
Cardinal;
begin
with VST do
begin
Start := GetTickCount; //
计算时间
case (Sender as TButton).Tag of
0: // add to root
begin
RootNodeCount :=
10; // 就这一句就足够增加节点了
end;
1: // add as child
if Assigned(FocusedNode) then
begin
ChildCount[FocusedNode]
:= ChildCount[FocusedNode] + 2; // ChildCount 和 FocusedNode
都是自带属性
Expanded[FocusedNode] := True; //
自带展开方法
InvalidateToBottom(FocusedNode); // 自带全部刷新
end;
end;
// 速度快啊,10万个节点32ms.
100万个节点200ms左右,1000万个节点40秒(内存不够,硬盘狂闪)
// Label1.Caption :=
Format(‘Last operation duration: %d ms‘, [GetTickCount - Start]);
end;
end;
最后,释放节点:
procedure TMainForm.VSTFreeNode(Sender: TBaseVirtualTree;
Node: PVirtualNode);
var
Data: PMyRec;
begin
Data :=
Sender.GetNodeData(Node);
// Explicitely free the string, the VCL cannot
know that there is one but needs to free
// it nonetheless. For more fields
in such a record which must be freed use Finalize(Data^) instead touching
// every member individually.
Finalize(Data^);
end;
TVirtualNode = packed record
Index,
// index of node with regard to its parent
ChildCount: Cardinal; //
number of child nodes
NodeHeight: Word; // height in pixels
States: TVirtualNodeStates; // states describing various properties of the node
(expanded, initialized etc.)
Align: Byte; // line/button
alignment
CheckState: TCheckState; // indicates the current check state
(e.g. checked, pressed etc.)
CheckType: TCheckType; // indicates which
check type shall be used for this node
Dummy: Byte; // dummy
value to fill DWORD boundary
TotalCount, // sum of this
node, all of its child nodes and their child nodes etc.
TotalHeight:
Cardinal; // height in pixels this node covers on screen including the height
of all of its
// children
// Note: Some
copy routines require that all pointers (as well as the data area) in a node
are
// located at the end of the node! Hence if you want to add new
member fields (except pointers to internal
// data) then put them
before field Parent.
Parent, // reference to the node‘s
parent (for the root this contains the treeview)
PrevSibling,
// link to the node‘s previous sibling or nil if it is the first node
NextSibling, // link to the node‘s next sibling or nil if it is the
last node
FirstChild, // link to the node‘s first
child...
LastChild: PVirtualNode; // link to the node‘s last child...
Data: record end; // this is a placeholder, each node gets extra data
determined by NodeDataSize
end;