我已经使用 virtualstringtree 一段时间了。我将它用于两件不同的事情,首先作为用于选择、显示数据的普通树,其次作为显示 SQL 语句输出的网格。
我加载到树中的所有数据都来自数据库。对于树示例,我有一个 parentId 字段来区分层次结构,对于网格示例,我只需使用 SQL 语句为每棵树(这是唯一的)定制记录。
我的问题与填充树的首选/最佳方式有关。我从 VST 文档中读到,您应该将 onInitNode 事件与 rootnodecount 一起使用。但是我发现使用 AddChild() 方法非常相似,即使不鼓励这样做。
让我展示一些(简化的)示例:
1. 层次结构
type PData = ^rData;
rData = packed record
ID : Integer;
ParentID : Integer;
Text : WideString;
end;
procedure Loadtree;
var Node : PVirtualNode;
Data : PData;
begin
Q1 := TQuery.Create(Self);
try
Q1.SQL.Add('SELECT * FROM Table');
Q1.Open;
Q1.Filter := 'ParentID = -1'; //to get the root nodes
Q1.Filtered := True;
while not Q1.Eof do
begin
Node := VST.AddChild(nil);
Data := VST.GetNodeData(Node);
Data.ID := Q1.Fields[fldID].AsInteger;
Data.ParentID := Q1.Fields[fldParentID].AsInteger;
Data.Text := Q1.Fields[fldText].AsString;
//now filter the query again to get the children of this node
PopulateChildren(Data.ParentID,Node); //add children to this node and do it recursively
Q1.Next;
end;
finally
Q1.free;
end;
end;
2.网格
procedure LoadGrid;
var Node : PVirtualNode;
Data : PData;
begin
Q1 := TQuery.Create(self);
try
Q1.SQL.Add('SELECT * FROM Table');
Q1.Open;
while not Q1.eof do
begin
Node := VST.AddChild(nil);
Data.ID := Q1.Fields[fldID].AsInteger;
Data.Text := Q1.Fields[fldText].AsString;
Q1.Next;
end;
finally
Q1.Free;
end;
end;
所以基本上我绕过了 RootNodeCount 和 OnInitNode 方法/属性,并使用老式的方法将节点添加到树中。它似乎工作正常。请注意,在示例中,我在运行时创建和销毁我的查询。
我开始以这种方式使用树的原因是我可以一次加载树中的所有数据,然后在我完成使用后释放 TQuery。我在想,不管 TQuery 保持活动/创建,我仍然需要使用我的 rData 记录来存储数据,因此如果我不销毁 TQuery 会占用更多内存。目前,我的应用程序在完全加载时使用大约 250+MB,并且当我运行 SQL 报告并将它们显示在 VST 中时会增加。当我运行包含 20000 多个节点和 50 多列的 SQL 报告时,我已经看到它使用了大约 1GB 的内存。我想知道我使用 VST 的方式在最小化内存使用方面是否不正确?
我会更好地为树的生命周期创建一个查询并使用 onInitNode 事件吗?这样当树请求数据时,它会使用 onInitNode/OnInitChildren 事件(即树的纯虚拟范例)从 TQuery 中获取数据?因此,我需要在表单期间保持 TQuery 处于活动状态。以这种方式使用它会有任何内存优势/性能优势吗?
在上述情况下,我可以看到网格示例的差异将远远小于(如果有的话)层次结构 - 因为所有节点在填充时都需要初始化。