【发布时间】:2011-11-29 06:33:55
【问题描述】:
我已经使用 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 处于活动状态。以这种方式使用它会有任何内存优势/性能优势吗?
在上述情况下,我可以看到网格示例的差异远小于(如果有的话)层次结构 - 因为所有节点都需要在填充时进行初始化。
【问题讨论】:
-
您使用这么多内存的主要原因之一是您将数据复制到每个节点;如果您只存储一个引用(例如 ID(在您的示例中为整数),您可以在 OnGetText 等事件的记录集中寻找正确的记录。这样您将节省 大量 内存和坚持虚拟范式。
-
如果您认为我在完成记录集后释放了记录集,会是这种情况吗?所以要坚持虚拟范式,我需要随时准备好记录集。我当前的方法在填充树后完成并释放它。我需要用来在记录集中查找记录的 Locate 的性能如何?
-
我个人使用内存数据集将数据保存在内存中,这对字符串非常有效(每个单元格没有单独的字符串对象;字符串的开销对于短字符串(例如 memmanager header ,字符串标题和零终止符))。性能完美;绘制网格时通常会消耗不到 1% 的额外 CPU 功率。
标签: performance delphi virtualtreeview tvirtualstringtree