首页 文章

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

提问于
浏览
6

如何在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;

当表单's destructor runs. Problem with this is that it'太迟时,我的框架对象的析构函数被调用 . 该表单调用 DestroyWindowHandle ,要求Windows销毁表单的窗口句柄 . 这会递归地破坏所有子窗口 - 包括我框架上的窗口 .

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


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

另见

4 回答

  • 1

    您需要添加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中释放的任何内容) .

  • 0

    听起来更像 OnClose 而不是 OnDestroy .

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

  • 9

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

    如果's a problem with the Windows handle(s), you should check wether you'能够附加Windows ' event callback pointer that gets called when the frame'的Windows句柄不再存在 . 也许像RegisterWaitForSingleObject这样的功能

  • 0

    另一种选择是覆盖 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;
    

相关问题