Delphi 如何为TTreeNodes实现GetLastNode?
当我需要在Delphi 如何为TTreeNodes实现GetLastNode?,delphi,Delphi,当我需要在TTreeView中查找第一个节点时,我调用TTreeNodes.GetFirstNode。但是,有时我需要定位树中的最后一个节点,并且没有相应的t reenodes.GetLastNode函数 我不想使用Items[Count-1],因为这样会导致整个树都被遍历Result:=Result.GetNext。当然,这只在树视图有很多节点时才重要。我完全理解虚拟容器控件的优点,但我现在还不打算切换到虚拟树视图 到目前为止,我已经得出以下结论: function TTreeNodes.Ge
TTreeView
中查找第一个节点时,我调用TTreeNodes.GetFirstNode
。但是,有时我需要定位树中的最后一个节点,并且没有相应的t reenodes.GetLastNode
函数
我不想使用Items[Count-1]
,因为这样会导致整个树都被遍历Result:=Result.GetNext
。当然,这只在树视图有很多节点时才重要。我完全理解虚拟容器控件的优点,但我现在还不打算切换到虚拟树视图
到目前为止,我已经得出以下结论:
function TTreeNodes.GetLastNode: TTreeNode;
var
Node: TTreeNode;
begin
Result := GetFirstNode;
if not Assigned(Result) then begin
exit;
end;
while True do begin
Node := Result.GetNextSibling;
if not Assigned(Node) then begin
Node := Result.GetFirstChild;
if not Assigned(Node) then begin
exit;
end;
end;
Result := Node;
end;
end;
任何人都可以:
我不愿意保留自己的节点缓存。我一直这样做,直到最近,但已经发现一些难以跟踪非常间歇性的AV,我相信这一定是由于我的缓存不同步。很明显,一个解决方案是让缓存同步代码正常工作,但我不喜欢缓存,因为当您出错时,很难跟踪错误。我以前使用的方法是使用列表维护TList。添加OnAddition事件和列表。在OnDeletion事件上删除(OnRemove?)。您可以立即访问List.Count-1(或任何您需要的内容)
后期编辑-我不得不说,虽然这很好,但我长大了,转到了虚拟树视图:-)如果我要实现它,这可能是我的第一稿
function TTreeNodes.GetLastNode: TTreeNode;
var
Node: TTreeNode;
function GetLastSibling(aNode : TTreeNode) : TTreeNode;
begin
if not Assigned(aNode) then
EXIT(nil);
repeat
Result := aNode;
aNode := Result.GetNextSibling;
until not Assigned(aNode) ;
end;
begin
Node := GetFirstNode;
if not Assigned(Node) then begin
exit;
end;
repeat
Result := GetLastSibling(Node);
Node := Result.GetFirstChild;
until not Assigned(Node);
end;
我觉得这更具可读性。不过可能会稍微慢一点
我不确定这种方法是否会比items[Count-1]快,在某些情况下,它可能会慢一些,因为TTreeNodes实际上缓存了通过items属性访问的最后一个节点。虽然我不是一个非退出纯粹主义者,但我认为当它在保持可读性不变的情况下无需退出即可实现时,人们可能更喜欢这种选择 这是完全相同的代码,因为我不认为您可以以任何其他方式(更快)到达结束节点,但不需要退出,也不需要稍微紧凑一些:
function TTreeNodes.GetLastNode: TTreeNode;
var
Node: TTreeNode;
begin
Node := GetFirstNode;
Result := Node;
if Result <> nil then
repeat
Result := Node;
if Node <> nil then
Node := Result.GetNextSibling;
if Node = nil then
Node := Result.GetFirstChild;
until Node = nil;
end;
函数TTreeNodes.GetLastNode:TTreeNode;
变量
节点:TTreeNode;
开始
节点:=GetFirstNode;
结果:=节点;
如果结果为零,则
重复
结果:=节点;
如果节点为nil,则
节点:=Result.GetNextSibling;
如果Node=nil,则
节点:=Result.GetFirstChild;
直到Node=nil;
结束;
非常感谢您的建议。我已经考虑过这一点(对不起,应该提到这一点),不愿意维护自己的节点缓存。事实上,我一直在这样做,直到最近才发现难以追踪的问题,我认为这是由于我的缓存不同步造成的。它不是节点缓存,只是一个尾部条目。每当在根节点或当前尾部节点附加节点时,您都会用新的尾部替换旧的尾部。@RRUZ:如果最后一个可见的节点是子节点呢?@NGLN我正要发表同样的评论,我想我可能可以在一小时内用虚拟树视图替换您的树视图,这样会更快,看起来更好,我不必担心让treeNodes与我的模型数据保持同步,事实上,这是许多细微错误的根源,因此,实际上,您已经在缓存您的模型,在您的treeview中,或者您正在使用您的treeview作为模型的关键元素。两者都有问题。(比如说线程。)@warren线程呢?另外,虚拟树视图不是我不喜欢的本机控件。+1我赞成对GetLastSibling进行分解,这使外部循环更具可读性。关于t绿色节点中的缓存
,只有当访问的最后一个节点是最后一个节点或前一个节点时,才会有帮助。在我的使用场景中不太可能出现这种情况。如果你打算使用迭代方法,我认为这接近最优。我刚刚又检查了一次,当树为空时,在Result.getFirstChild
处会出现访问冲突。