VirtualStringTree正确/推荐使用

现在我一直在使用virtualstringtree。 我使用它作为两个不同的东西,首先作为一个普通的树来选择,显示数据,然后作为一个网格来显示SQL语句的输出。

我加载到树中的所有数据都来自数据库。 对于树的例子,我有一个parentId字段来区分heirarchy,对于网格示例,我只是使用一个SQL语句和每个树(这是唯一的)的自定义记录。

我的问题涉及填充树的首选/最佳方式。 我从VST文档中读到应该使用onInitNode事件和rootnodecount。 不过,我发现使用AddChild()方法非常相似,即使它不被鼓励。

让我展示一些(简化的)例子:

1. 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中显示它们时增加。 我已经看到它使用大约1GB的RAM,当我运行SQL报告20000+节点和50 +列。 我想知道如果我使用VST的方式在减少内存使用方面不正确?

我会更好地创建一个查询树的生命周期,并使用onInitNode事件? 所以当数据被树请求时,它使用onInitNode / OnInitChildren事件(即树的纯虚拟范式)从TQuery中获取数据? 因此,我需要保持TQuery在表单持续时间内保持活动状态。 以这种方式使用它会有什么记忆效益?

在上述情况下,我可以看到网格示例的差异远小于平均值(如果有的话) - 这是由于所有节点在填充时都需要初始化。


AddChild()不被鼓励的原因是它打破了组件的虚拟范式 - 即创建所有节点,即使您可能永远不需要它们。 假设查询返回100条记录,但该树显示当时的10个节点。 现在,如果用户nevers向下滚动,则会浪费90个节点的资源,因为它们从不需要(不可见)。 所以,如果你担心内存使用情况, AddChild()不是个好主意。 另一件事是,如果结果集很大,填充树需要时间,并且当时您的应用程序没有响应。 当使用虚拟方式( RootNodeCountOnInitNode )时,树立即“就绪”,用户不会遇到任何延迟。

再次,如果使用AddChild()的(相对)小结果集可能是最好的选择 - 它将允许您在一个短的事务中加载数据。 即在树结构的情况下,当用户扩展父节点时,一次加载整个“级”是有意义的。

在数据库查询中使用数据库有点棘手,因为数据库查询也是特殊资源,它有自己的约束(您希望保持事务简短,速度相对较慢,数据库可能只支持单向游标等)。
所以我会说这是你必须根据用例和数据量决定每个个案的东西,也就是说

  • 小结果集可以使用AddChild()或者内部数据结构一次性加载,然后在VT事件中使用它;
  • 一次加载一个级别可能是妥协妥协的树木;
  • 如果结果集非常大,批量加载可能会导致良好的性能和内存使用方面的妥协,但会增加管理VT的代码的复杂性。

  • TQuery提供对记录的类似数组的访问。

    如果您检查文档,您可以使用RecNo属性跳转到每条记录,并且可以使用Fields[i] (通过它的索引)跳转到每个字段。

    使用TVirtualStringTree作为连接数据库的虚拟模式TVirtualStringTree

    一旦你执行查询,数据在内存中作为TDataSet ,那么为什么不把它用作数据容器?

    PS:使用索引访问字段比FieldByName快。

    链接地址: http://www.djcxy.com/p/5965.html

    上一篇: VirtualStringTree Correct/recommended use

    下一篇: Virtual String Tree Slow GetText Method At Large Amount Of Nodes