加载到树中的所有数据都来自数据库.对于树示例,我有一个parentId字段来区分层次结构,对于网格示例,我只使用带有每个树的自定义记录的SQL语句(这是唯一的).
我的问题与填充树的首选/最佳方式有关.我从VST文档中读到,您应该使用onInitNode事件和rootnodecount.但是我发现使用AddChild()方法非常相似,即使不鼓励它.
让我展示一些(简化的)示例:
Heirarchy
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的ram.我想知道我使用VST的方式是否与最小化内存使用量有关?
我会更好地为树的生命周期创建查询并使用onInitNode事件吗?因此,当树请求数据时,它使用onInitNode / OnInitChildren事件(即树的纯虚拟范例)从TQuery中获取数据?因此,我需要在表单的持续时间内保持TQuery活着.以这种方式使用它会有任何内存效益/性能优势吗?
在上面的情况中,我可以看到网格示例的差异远远小于层次结构(如果有的话) – 因为所有节点在填充时都需要初始化.
不鼓励AddChild()的原因是它打破了组件的虚拟范例 – 即使您可能永远不需要它们,也会创建所有节点.假设查询返回100条记录,但树当时显示10个节点.现在,如果用户向下滚动,则浪费了90个节点的资源,因为它们从不需要(不会变得可见).因此,如果你担心内存使用,AddChild()是个坏主意.另一件事是,如果结果集很大,填充树需要时间,并且您的应用程序当时没有响应.使用虚拟方式(RootNodeCount和OnInitNode)时,树立即“准备就绪”,用户不会遇到任何延迟.然后,如果使用AddChild()(相对)小的结果集可能是最好的选择 – 它将允许您在一个短事务中加载数据.即在树结构的情况下,当用户扩展父节点时,立即加载整个“级别”是有意义的.
使用带有VT的DB有点棘手,因为DB查询也是特殊资源,它有自己的约束(你希望保持事务简短,它相对较慢,DB可能只支持单向游标等).
所以我要说这是你必须根据用例和数据量决定每个案例的事情,即
>小结果集可以用AddChild()一次加载到内部数据结构,然后通过VT的事件使用它;>按时加载一个级别可能是对树木的良好妥协;>如果非常大的结果集批量加载可能会提供良好的性能和内存使用损失,但会增加管理VT的代码的复杂性.