当我需要找到TTreeView
中的第一个节点时,我会调用TTreeNodes.GetFirstNode
。但是,我有时需要在树中找到最后一个节点,并且没有相应的TTreeNodes.GetLastNode
函数。
我不想使用Items[Count-1]
因为这会导致整个树都与Result := Result.GetNext
一起走。当然,这仅在树视图具有大量节点时才有意义。我完全理解虚拟容器控件的优点,但我还没有切换到Virtual TreeView。
到目前为止,我已经提出以下建议:
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;
任何人都可以:
修改1
我不愿意保留自己的节点缓存。我一直这样做直到最近,但发现一些难以跟踪非常间歇性的AV,我认为这必定是由于我的缓存不同步。显然,一个解决方案是让我的缓存同步代码正常工作,但我厌恶缓存,因为很难跟踪错误时出现的错误。
答案 0 :(得分:6)
虽然我不是非退出纯粹主义者,但我认为如果在没有退出的情况下可行,同时保持可读性不变,则可能更喜欢该选项。
所以这里的代码完全相同,因为我认为你不能以任何其他方式(更快)到达终端节点,但没有退出并且稍微紧凑:
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;
答案 1 :(得分:2)
我之前使用的方法是使用OnAddition事件上的List.Add和OnDeletion事件上的List.Remove维护TList(OnRemove?)。您可以立即访问List.Count-1(或任何您需要的东西)。
发布编辑 - 我不得不说虽然这很好用但我还是长大了并转移到虚拟树视图: - )
答案 2 :(得分:2)
如果我要实施它,这可能是我的初稿。
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;
我发现这稍微更具可读性。但它可能稍慢一点。
我不确定这种方法是否比项[Count-1]更快,在某些情况下,它可能更慢,因为TTreeNodes实际缓存通过items属性访问的最后一个节点。