【发布时间】:2021-12-29 13:27:53
【问题描述】:
深表歉意,我很努力,但我找不到任何合理的解释。
还有我自己的TMyTreeNode类:
TMyTreeNode = class (TTreeNode)
private
FFont:TFont;
FBrush:TBrush;
public
constructor Create;
destructor Destroy; override;
property Font:TFont read FFont write FFont;
property Brush:TBrush read FBrush write FBrush;
end;
constructor THierarchyTreeNode.Create(AOwner: TTreeNodes);
begin
inherited Create(AOwner);
FFont := TFont.Create;
FBrush := TBrush.Create;
end;
destructor TMyTreeNode.Destroy;
begin
FFont.Free;
FBrush.Free;
inherited;
end;
和TTreeView 的后代,其中TMyTreeNode 是动态创建的。
当要删除 TMyTreeNode 时,我会覆盖动态方法 procedure TMyTreeview.Delete(Node: TTreeNode); 以实现特定行为。我需要遍历所有其他 TMyTreeNode 对象来更改它们的属性。为简单起见,我强迫他们展示他们的文字:
TMyTreeview = class(TTreeView)
protected
function CreateNode: TTreeNode; override;
procedure Delete(Node: TTreeNode); override;
public
destructor Destroy; override;
end;
function TTreeViewHierarchy.CreateNode: TTreeNode;
// var LClass: TTreeNodeClass;
begin
// LClass := THierarchyTreeNode;
// if Assigned(OnCreateNodeClass) then
// OnCreateNodeClass(Self, LClass);
// Result := LClass.Create(Items);
// The constructor of THierarchyTreeNode is not called, because constructor of TTreeNode is not virtual !!!;
Result := THierarchyTreeNode.Create(Items);
end;
procedure TMyTreeview.Delete(Node: TTreeNode);
var
i: Integer;
begin
inherited;
for i := 0 to Items.Count-1 do ShowMessage(Items[i].Text); //Example
end;
destructor TMyTreeview.Destroy;
begin
inherited;
end;
假设 5 个 TMyTreeNode 对象被添加到 TMyTreeview 中。当myTreeview.Items.Delete(myTreeview.Selected); 987654331 TMyTreeNode首先被调用默认的析构函数时,然后TMyTreeview.Delete()。
ShowMessage() 出现 5 次。这表明,将被删除的节点和所有其他 TMyTreeNode 对象都存在并且被正确引用。
这是预期的行为。
但是当我关闭应用程序时,我收到一条错误消息:
...class ETreeViewError with message 'Invalid index'
在TMyTreeview.Delete() 方法中。
有两件事让我很困惑:
-
如果关闭(销毁)应用程序的
MainForm,TMyTreeNode.Destroy()在TMyTreeview.Destroy()之前被调用,为什么?TTreeNodes的所有者是TCustomTreeView,我希望TTreeNodes会在祖先的析构函数中被释放 (TTreeView.Destroy())。 -
如果我承认上述奇怪的事实,那么
procedure TMyTreeview.Delete(Node: TTreeNode);会失败。Items似乎已经被取消引用,Items.Count没有提供正确的结果(它包含取消引用的指针)。但这没有任何意义。
提前致谢。我花了几个小时来调试它,但尽管我在 Delphi 有长期经验,但我无法得到它。
【问题讨论】:
-
如果你把继承放在你的showmessage循环之后会有什么不同吗?
-
@whosrdaddy 不......我试过......顺便说一句,我承认似乎合乎逻辑
-
你不是要重写 TTreeNode 的虚拟构造函数,并获取树视图类来实例化你的派生类吗?有一个我不记得的机制。如果您想知道析构函数为何按此顺序运行,请查看使用调试器和调用堆栈的代码。这将很容易理解。
-
@DavidHeffernan 我不能强制调试器跳转到 ComCtrls.pas,它总是跳过。
-
@DavidHeffernan 。大卫,我还重写了 TMyTreeNode 的构造函数(见上文),但奇怪的是,我不能在那里设置断点。字体和画笔为零....为什么?我在网上找不到任何东西,看起来你可能是对的,但无论如何它令人困惑