繁体   English   中英

如何在Delphi中模拟TFrame上的OnDestroy事件?

[英]How to simulate an OnDestroy event on a TFrame in Delphi?

如何在Delphi中为TFrame模拟OnDestroy事件?


我简单地在我的框架中添加了一个constructordestructor ,认为这就是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销毁表单的窗口句柄。 这会递归地破坏所有子窗口 - 包括我框架上的窗口。

因此,当我的框架的destructor运行时,我尝试访问不再处于有效状态的控件。


如何在Delphi中为TFrame模拟OnDestroy事件?

也可以看看

您需要添加WM_DESTROY处理程序并检查ComponentState中的csDestroying,以便它仅在实际销毁时捕获,而不是在重新创建句柄时捕获。

type
  TCpFrame = class(TFrame)
  private
    FOnDestroy: TNotifyEvent;
    procedure WMDestroy(var Msg: TWMDestroy); message WM_DESTROY;
  published
    property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
  end;

procedure TCpFrame.WMDestroy(var Msg: TWMDestroy);
begin
  if (csDestroying in ComponentState) and Assigned(FOnDestroy) then
    FOnDestroy(Self);
  inherited; 
end;

这只有在实际创建了框架的窗口句柄时才有效。 没有其他好的挂钩点,所以如果你想确保它总是被调用,你需要在WMDestroy中设置一个标志,如果没有被击中则回退到在析构函数中调用它。

窗口句柄本身都在WM_NCDESTROY中清除,WM_NCDESTROY在所有后代WM_DESTROY消息返回后调用,因此表单及其所有childens的句柄在此时仍应有效(忽略表单的OnDestroy中释放的任何句柄) 。

听起来更像OnClose不是OnDestroy

无论如何,我只是从基础祖先继承了我的所有框架和表单,然后表单的onclose调用组件层次结构中的所有框架。

(这只是一个想法,但我现在没有时间来构建一个概念证明,但我会分享它:)

如果它是Windows句柄的问题,你应该检查你是否能够附加一个Windows'事件回调指针,当框架的Windows句柄不再存在时,它会被调用。 也许使用像RegisterWaitForSingleObject这样的函数

另一种选择是覆盖AfterConstructionBeforeDestruction

像这样的东西:

  TMyFrame = class(TFrame)
  private
    FOnCreate: TNotifyEvent;
    FOnDestroy: TNotifyEvent;
  protected
    procedure DoCreate; virtual;
    procedure DoDestroy; virtual;
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
    property OnCreate: TNotifyEvent read FOnCreate write FOnCreate;
    property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
  end;

  implementation

  procedure TMyFrame.AfterConstruction;
  begin
    inherited;
    DoCreate;
  end;

  procedure TMyFrame.BeforeDestruction;
  begin
    inherited;
    DoDestroy;
  end;

  procedure TMyFrame.DoCreate;
  begin
    if Assigned(FOnCreate) then
      FOnCreate(Self);
  end;

  procedure TMyFrame.DoDestroy;
  begin
    if Assigned(FOnDestroy) then
      FOnDestroy(Self);
  end;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM