2010-07-28 54 views
3

我还没有非常丰富的TVirtualStringTree组件经验,因此也许我忽略了一些微不足道的东西。德尔福 - 虚拟字符串树缓慢GetText方法在大量的节点

我的应用程序将文件信息收集到记录(文件名,路径,大小)并显示在虚拟字符串树中的数据。

现在,当有很多节点(200K +)时,我经历了一个沉重的减速,整个树基本上滞后。我知道内存占用量非常大,只有记录数据,但我发现滞后是由VST的OnGetText方法引起的。 因此,如果方法读取实际数据或将CellText设置为静态字符串(例如,CellText:='Test';),则减速效果显着无关紧要。 如果我在不设置CellText的情况下退出OnGetText,它可以正常工作 - 即使在我的树中也有多达1,000,000个节点。 另外,如果我折叠Tree(FullCollapse)隐藏这种方式90%的节点,OnGetText表现还可以,或者至少好得多。

据我所知,OnGetText仅仅被称为实际可见的屏幕节点,因此我不明白为什么这是树中有大量节点的问题。

有人有任何提示让我指出我的方向?

编辑:

德尔福版本:D2010 VST版本:4.8.6

我以最简单的测试表单代码基本如下:

var 
    SkipGetText : boolean; 

procedure TXForm.VSTGetText(Sender: TBaseVirtualTree; 
    Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); 
begin 
    if SkipGetText then exit; 
    CellText := 'TEST'; 
    // actual code commented out to reduce complications 
end; 

如果我设置CELLTEXT,它滞后,如果我退出,它不会。 奇怪的是,越往下滚,情况越糟糕。

这里是什么分配为NODEDATA:

type 
    PVSData = ^Fi; 
    Fi = Packed Record 
    Name, Dir, Ext: String; 
    Size: Int64; 
    end; 

procedure TXForm.AddFile(const RootFolder:string; const SR: TSearchRec); 
var 
    FileInfo: PVSData; 
    FileSize: Int64; 
    Node: PVirtualNode; 
begin 
    Node   := VST.AddChild(nil); 
    INC(AllFiles); 
    FileInfo  := VST.GetNodeData(Node); 
    FileInfo^.Name := SR.Name; 
    FileInfo^.Dir := RootFolder; 

    Int64Rec(FileSize).Hi := SR.FindData.nFileSizeHigh; 
    Int64Rec(FileSize).Lo := SR.FindData.nFileSizeLow; 
    FileInfo^.Size   := FileSize; 
end; 

procedure TXForm.VSTPaintText(Sender: TBaseVirtualTree; 
const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); 
begin 
    if SkipPaintText then exit; 

    case ListView.GetNodeLevel(Node) of 
    0: TargetCanvas.Font.Color := Color1; 
    else TargetCanvas.Font.Color := Color2; 
    end; 
end; 

procedure TXForm.VSTBeforeCellPaint(Sender: TBaseVirtualTree; 
    TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; 
    CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); 
begin 
    case ListView.GetNodeLevel(Node) of 
    0: TargetCanvas.Font.Color := Color1; 
    else TargetCanvas.Font.Color := Color2; 
    end; 
end; 

我注意到,那展开/折叠和再膨胀在某种程度上似乎改善这种情况,但它超出了我知道为什么这样做可能会造成任何影响。

+0

如果您显示您的代码,至少您在OnGetText处理程序中拥有的代码,您将得到更好的答案。顺便说一句,我只有经历了缓慢的起伏,当我在一个方法中做了一些“愚蠢的事情”时,几乎每个鼠标移动都会被调用... – 2010-07-28 17:09:58

+0

Hi BlackOut!欢迎来到StackOverflow。这是一个很好的第一个问题。我对VirtualStringTree了解不多,因此我不会尝试发布真正的答案,但听起来您的性能随着开放节点数量的增加呈线性下降。这使得看起来像设置CellText必须扫描树的所有节点出于某种原因。尝试查看代码并查看在更改CellText时是否可以找到某种线性搜索。 – 2010-07-28 17:14:41

+0

我的代码非常基本,因为我已经删除了每个可能使事情复杂化以便进行调试的部分。 与此同时,我想我可能会看到一些东西,因为它似乎一旦我再次崩溃并展开树,它就可以正常工作。我会给它更多的测试和明天更新我的文章,或者如果我碰巧找出什么是负责任的,请添加一个答案。 – BlackOut 2010-07-28 23:54:07

回答

1

问题解决。事实证明,删除节点时可能会出现复杂情况。不是删除父节点的所有子节点,只有父节点已被删除。我预计子节点也会自动删除,但是当我更改代码以首先删除子节点时,父节点的滞后消失了。现在我可以无延迟地将一百万个文件名加载到树中。

1

你没有说你正在使用哪个版本的Delphi。在D2009之前的版本中,TVirtualTreeView使用WideString字符串类型,这种字符串类型通常本质上很慢,因为它没有AnsiString具有的引用计数,写时复制语义,因此尽量尽量减少字符串操作。在D2009及更高版本中,TVirtualTreeView使用较新的UnicodeString字符串类型而不是WideString

+0

是的,我应该提供该信息。 我使用Delphi 2010与虚拟字符串树版本4.8.6 – BlackOut 2010-07-28 23:48:00

3

如果您的任何列都是自动调整大小的,那么控件需要知道所有节点值的宽度以确定最大值。

1

奇怪的是,我认为这是VST的整个设计,只为活动视图中的节点加载cellnodes,而不是整个树。你确定它不是代码中的其他因素,你没有显示,比如为每个节点做一个文件存在的东西吗?