如何在Delphi中模拟TFrame上的OnDestroy事件?
如何在 Delphi 中模拟 TFrame
的 OnDestroy
事件?
我天真地将构造函数
和析构函数
添加到我的框架中,认为这就是TForm
所做的:
TframeEditCustomer = class(TFrame)
...
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
...
end;
constructor TframeEditCustomer.Create(AOwner: TComponent)
begin
inherited Create(AOwner);
//allocate stuff
end;
destructor TframeEditCustomer.Destroy;
begin
//cleanup stuff
inherited Destroy;
end;
问题是,到我的析构函数时运行时,框架上的控件已被破坏并且不再有效。
其原因在于包含表单的析构函数,它使用该析构函数来触发 OnDestroy
事件:
destructor TCustomForm.Destroy;
begin
...
if OldCreateOrder then DoDestroy; //-->fires Form's OnDestroy event; while controls are still valid
...
if HandleAllocated then DestroyWindowHandle; //-->destroys all controls on the form, and child frames
...
inherited Destroy; //--> calls destructor of my frame
...
end;
当表单的析构函数运行时,将调用我的框架对象的析构函数。问题是为时已晚。表单调用DestroyWindowHandle
,它要求Windows销毁表单的窗口句柄。这会递归地销毁所有子窗口 - 包括我框架上的子窗口。
因此,当我的框架的析构函数
运行时,我尝试访问不再处于有效状态的控件。
如何在 Delphi 中模拟 TFrame
的 OnDestroy
事件?
How can I simulate an OnDestroy
event for a TFrame
in Delphi?
I naively added a constructor
and destructor
to my frame, thinking that is what TForm
does:
TframeEditCustomer = class(TFrame)
...
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
...
end;
constructor TframeEditCustomer.Create(AOwner: TComponent)
begin
inherited Create(AOwner);
//allocate stuff
end;
destructor TframeEditCustomer.Destroy;
begin
//cleanup stuff
inherited Destroy;
end;
The problem with this is that by the time my destructor runs, controls on the frame have been destroyed and are no longer valid.
The reason for this is in the containing form's destructor, which it uses to fire an OnDestroy
event:
destructor TCustomForm.Destroy;
begin
...
if OldCreateOrder then DoDestroy; //-->fires Form's OnDestroy event; while controls are still valid
...
if HandleAllocated then DestroyWindowHandle; //-->destroys all controls on the form, and child frames
...
inherited Destroy; //--> calls destructor of my frame
...
end;
The destructor of my frame object is being called when the form's destructor runs. The problem with this is that it's too late. The form calls DestroyWindowHandle
, which asks Windows to destroy the form's window handle. This recursively destroys all child windows - including those on my frame.
So when my frame's destructor
runs, I attempt to access controls that are no longer in a valid state.
How can I simulate an OnDestroy
event for a TFrame
in Delphi?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您需要添加 WM_DESTROY 处理程序并检查 ComponentState 中的 csDestroying,以便仅在实际销毁时捕获它,而不是在重新创建句柄时捕获它。
仅当框架的窗口句柄已实际创建时,这才有效。没有其他好的挂钩点,因此如果您想确保它始终被调用,您需要在 WMDestroy 中设置一个标志,并在未命中时回退到在析构函数中调用它。
窗口句柄本身在 WM_NCDESTROY 中全部清除,该窗口句柄在所有后代 WM_DESTROY 消息返回后调用,因此此时窗体及其所有子句柄应该仍然有效(忽略在窗体 OnDestroy 中释放的任何句柄) 。
You need to add a WM_DESTROY handler and check for csDestroying in the ComponentState so it's only caught when actually destroying, and not when recreating the handle.
That will only work if the frame's window handle has actually been created. There isn't another good hook point, so if you want to ensure it's always called you'll need to set a flag in WMDestroy and fall back to calling it in the destructor if that isn't hit.
The window handles themselves are all cleared in WM_NCDESTROY, which is called after all of the descendant WM_DESTROY messages return, so the form and all of its childens' handles should still be valid at this point (ignoring any that were freed in the form's OnDestroy).
听起来更像是
OnClose
而不是OnDestroy
。无论如何,我只是从基础祖先继承了所有框架和表单,并且表单的 onclose 调用了组件层次结构中的所有框架。
Sounds more like
OnClose
thanOnDestroy
.Anyway, I just inherited all my frames and forms from a base ancestor, and the form's onclose calls then all frames in the component hierarchy.
(这只是一个想法,但我现在没有时间构建概念证明,但我仍然会分享它:)
如果是 Windows 句柄问题,您应该检查是否“能够附加一个 Windows”事件回调指针,当框架的 Windows 句柄不再存在时,该指针将被调用。也许使用像 RegisterWaitForSingleObject 这样的函数
(It's just an idea but I haven't got the time right now to construct a proof of concept, but I'll share it none the less:)
If it's a problem with the Windows handle(s), you should check wether you're able to attach a Windows' event callback pointer that gets called when the frame's Windows handle ceases to exists. Perhaps with a function like RegisterWaitForSingleObject
另一种选择是覆盖
AfterConstruction
和BeforeDestruction
如下所示:
Another option is to override
AfterConstruction
andBeforeDestruction
Something like this: