我有一个应用程序,从二进制日志文件加载记录,并在虚拟TListView中显示它们.文件中可能有数百万条记录,用户可以过滤显示,因此我不会一次加载内存中的所有记录,并且ListView项目索引不是一对一的关系.文件记录偏移(例如,列表项1可以是文件记录100).我使用ListView的OnDataHint事件来加载ListView实际感兴趣的项目的记录.当用户滚动时,OnDataHint指定的范围发生变化,允许我释放不在新范围内的记录,并分配新记录如所须.
这样工作正常,速度可以忍受,并且内存占用非常低.
我目前正在评估TVirtualStringTree作为TListView的替代品,主要是因为我想添加扩展/折叠跨越多行的记录的能力(我可以通过动态递增/递减项目计数来使用TListView来捏造它,但这不是像使用真正的树一样直接).
在大多数情况下,我已经能够移植TListView逻辑并让一切工作正常.我注意到TVirtualStringTree的虚拟范例有很大的不同.它没有与TListView相同的OnDataHint功能(我可以使用OnScroll事件伪造它,这允许我的内存缓冲逻辑继续工作),我可以使用OnInitializeNode事件将节点与分配的记录相关联.
但是,一旦树节点初始化,它就会看到它在树的生命周期内保持初始化状态.这对我不好.当用户滚动并从内存中删除记录时,我需要重置那些非可视节点,而不是完全从树中删除它们,或者丢失它们的展开/折叠状态.当用户将它们滚动回视图时,我可以重新分配记录并重新初始化节点.基本上,就虚拟化而言,我希望尽可能使TVirtualStringTree像TListView一样.
我已经看到TVirtualStringTree有一个ResetNode()方法,但每次尝试使用它时都会遇到各种错误.我一定是错了.我还想过将每个节点内的数据指针存储到我的记录缓冲区中,然后分配并释放内存,相应地更新这些指针.最终效果也不是很好.
更糟糕的是,我最大的测试日志文件中有大约500万条记录.如果我一次初始化具有那么多节点的TVirtualStringTree(当日志显示未经过滤时),那么树的内部开销就会占用高达260MB的内存(还没有分配任何记录).而使用TListView,加载相同的日志文件及其背后的所有内存逻辑,我可以使用几个MB.
有任何想法吗?
我正在尝试使用VirtualStringTree而不是Listview来构建我的项目,因为速度差异巨大.事情是,即使在通过演示看之后,我也无法弄清楚我将如何将其用作ListView.比如,添加,删除,基本上只是使用ListView项目是如此简单,但是当我看到VT时,它变得非常复杂.
我正在寻找的是一个看起来像ListView的VT,子项目等.
以下是使用ListView的一些例程,我想与VT一起使用(这只是一个伪示例:
procedure Add;
begin
with ListView.Items.Add do
Begin
Caption := EditCaption.Text;
SubItems.Add(EditSubItem.Text):
End;
end;
Procedure ReadItem(I : Integer);
begin
ShowMessage(ListView.Items[I].Caption);
ShowMessage(ListView.Items[I].SubItems[0]);
end;
Run Code Online (Sandbox Code Playgroud)
当然,也是删除功能,但由于那就像1行,我没有打扰:P
任何人都可以将上面的例子翻译成使用ListView风格的VT吗?
谢谢!
好吧,我在这里得到了一些非常棘手的东西...我想将一个或者使用Header给一个ChildNode.我认为这个想法是合理的,因为在子节点中有标题会让人看起来很棒,所以可以在表格中指定子节点.是否存在VST具有或根本不可能的功能?
谢谢你的帮助.
Mike Lischke在VirtualTreeView中有广泛的拖放支持,我使用的是TVirtualStringTree,它有一些拖放事件,但我无法弄清楚如何让它接受shell拖放从Windows资源管理器shell到我的应用程序的一些文件.我想加载文件,当它们被拖动到放置控件上时.
我尝试使用Anders Melander的第三方代码来处理拖放操作,但是因为VirtualTreeView已经将自己注册为放置目标,所以我无法使用它.
编辑:我找到了一个简单的解决方法:在VT.TreeOptions.MiscOptions中关闭toAcceptOLEDrop.如果有人知道如何使用VirtualTreeView而不使用第三方OLE-shell-drag-drop库并使用其广泛的OLE拖放支持来提取从Shell中拖入的文件名列表,那将会很酷.
我想每个曾经使用过Delphi的VirtualStringTree的人都会同意它是一个很棒的控件.它是一个"虚拟"控件(您的数据必须保存在其他位置)所以我在想什么数据结构最适合这样的任务?IMO数据结构必须支持层次结构,它必须快速且易于扩展.最简单的实现是使用记录,这就是可以找到的大多数文档所暗示的内容.但是如果你需要做一些快速查找,计算总数等怎么办?您与VirtualStringTree一起使用的数据结构是什么?
编辑1:我正在使用Delphi 2010.
好的,我会尝试提供一些有关我的要求的更多细节.数据大小可以变化很大,从1到数千个项目.每个项目可以包含多个字符串,整数值.我需要随机访问,我的数据可以在应用程序生命周期中多次更改.良好的性能是非常理想的.我还需要数据保存和重新加载.
EDIT2:得到1个答案,所以我会试着评论我的意见.谢谢,Dorin的答案,但我不认为你的结构很方便.1)它不处理层次结构.2)为每个节点分别设置TStringList或TList不是非常有效的IMO.通过这种实现,我只能查找当前节点的数据,但不能有效地搜索整个树.
我认为这个数据结构必须像一棵树.它必须具有能够添加子节点的节点.然后我就可以在OnInitNode事件中获取节点的数据,检查我的节点是否有一些子节点,如果是,则设置ivsHasChildren标志,然后在OnInitChildren事件中设置正确的子节点数.稍后在OnGetText事件中,我可以从我的节点结构中获取所需的数据,并根据Column索引将其设置为CellText.我的想法是拥有一个单独的数据结构,并使用它完成所有需要的操作,而无需使用VirtualStringTree.希望有人得到我的观点:).
EDIT3:我发现了非常有趣的JclTrees单元,乍一看可以用来实现我正在寻找的东西.它属于JCL library.缺乏体面的文档使得很难快速调查它的功能.当我有更多时间时,我可能会更深入地研究它.
所以我一直在搞乱创建自己独立的数据结构.我终于让它工作了,但后来我发现与旧方法相比,内存使用率高得离谱.
为了测试这个,我创建了相同的测试应用程序,但我会将数据存储在我的PVirtualNodes中.
当添加1000个根,每个1000个子节点时,单独的数据结构使用大约208 MB,而PVirtualNode只使用大约160 MB,并且它也快一点.
我认为使用单独的数据结构应该使用更少的内存,并且更快,但我想这是代价?
以下是"在PVirtualNode中存储数据"的来源:http://pastebin.com/j6L2eHJt
以下是"在单独数据结构中存储数据"的来源:http://pastebin.com/iSwR0hW1
TVirtualStringTree行为默认情况下,如果它的重点是 - 它会在鼠标滚轮滚动即使鼠标不在控制(除非它是对另一TVirtualStringTree).
是否有一种快速而优雅的方法来禁用此行为?
我已经这样做与OnMouseWheel事件,并检查PtInRect是否Mouse.CursorPos如果是在控制,但我有一种感觉,有一种更好的方式做同样的,因为这样,我不得不定义每个树视图我想补充,也是一个新的事件处理何时聚焦/取消聚焦控件,所以我希望必须有更好的方法来禁用它.
所以要清楚,我希望鼠标滚轮功能像往常一样工作,但只有当鼠标在VirtualTreeView上时.
delphi c++builder virtualtreeview delphi-2010 c++builder-2010
我正在尝试基于VirtualTreeView构建一个简单的2列网格"属性编辑器".
(我想模仿在Delphi的IDE对象检查器上看到的外观和用户体验)
该组件几乎可以工作,可以处理多个编辑器, 但我面临一个恼人的错误:
当我单击一个新节点(一个新行)时,无论我点击了哪一列,都会选择该节点并显示编辑器.这是预期的和好的.
然后,当我单击同一行的第一列时,我希望看到我的编辑器内容得到验证,编辑器保持焦点(就像在delphi的对象检查器中一样).
但编辑器内容已经过验证,然后消失,整个节点(行)被选中.编辑器将不会返回(即使我单击第二列),直到我选择另一个节点并单击以前选择的节点.
编辑:添加了关于我的代码的插图和精度.

关于代码: 我没有在这里插入代码,因为我使用(作为起点)与高级演示(属性页面)上的代码完全相同的代码
我尝试并发现了什么:
在这里找到的2003年编译的高级演示(属性树页面)似乎与我对组件(以及虚拟树视图)的期望一样.
但是当我编译这个相同的演示时(我尝试使用版本4.5.2,4.8.7甚至5.0.0来自谷歌代码的当前主干,在delphi 2007和2009上),错误再次出现!
我首先想到2003年和更新版本之间有一个记录在案的重大变化,但我找不到任何东西.我也玩过所有可用的选项试图解决这个问题,但没有成功.
我仍然不知道这个问题是来自新的delphi RTL还是虚拟视图中的重大变化(bug?).
所以我的问题:
作为旁注,我今天下午几乎放弃了virtualtreeview,我想尝试另一个组件的解决方案......我发现这个有趣的问题,并决定尝试berg的组件,但在阅读建议时在购买过程中停止了他们的主页(见我对相关问题的评论)
当我使用toUseExplorerTheme在TVirtualStringTree.PaintOptions它绘制这样的选择:

请注意,选择从控件的左侧延伸到任何节点标题的最右侧范围的位置; 选择的宽度都相同.
我希望它看起来像这个图像(其他人的项目,使用Virtual TreeView),其中选择仅涵盖节点标题的文本:

除非Virtual TreeView中有回归(我使用5.2.2),否则这一定是可能的,但我找不到正确的选项组合.
这是我的设置代码:
fTree := TVirtualStringTree.Create(Self);
fTree.Parent := Self;
fTree.Align := alClient;
fTree.OnGetText := TreeGetText;
fTree.OnInitNode := TreeInitNode;
fTree.OnInitChildren := TreeInitChildren;
fTree.OnChange := TreeSelectionChange;
fTree.RootNodeCount := 1;
fTree.DrawSelectionMode := smBlendedRectangle;
fTree.TreeOptions.PaintOptions := fTree.TreeOptions.PaintOptions
+ [toUseExplorerTheme];
fTree.TreeOptions.SelectionOptions := fTree.TreeOptions.SelectionOptions
+ [toMultiSelect];
Run Code Online (Sandbox Code Playgroud) 我想为我的整个应用程序使用自定义Hint窗口类.我使用Application.OnShowHint,分析THintInfo,并返回我自己TMyHintWindow的HintInfo.HintWindowClass.这适用于所有控件,但我只有TVirtualStringTree Columns提示有一个奇怪的问题.
VT使用它自己的提示窗口和自己的结构HintInfo.HintData.我研究代码,并知道它使用了VTHintData.到现在为止还挺好.问题是,当我返回自己的提示窗口类(派生自THintWindow)时,它仅显示提示窗口一瞬间消失!
为树节点返回的提示没有问题.他们使用相同的方法/结构(VTHintData).
这是一个非常简单的MCVE:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, VirtualTrees, StdCtrls;
type
TForm1 = class(TForm)
VirtualStringTree1: TVirtualStringTree;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
public
procedure ApplicationShowHint(var HintStr: string; var CanShow: Boolean;
var HintInfo: THintInfo);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TMyHintWindow = class(THintWindow)
public
{ nothing special here for now } …Run Code Online (Sandbox Code Playgroud) delphi ×10
virtualtreeview ×10
c++builder ×2
delphi-2007 ×1
delphi-2009 ×1
delphi-2010 ×1
delphi-7 ×1
delphi-xe2 ×1
listview ×1
vcl ×1