代码之家  ›  专栏  ›  技术社区  ›  Ian Boyd

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

  •  6
  • Ian Boyd  · 技术社区  · 14 年前

    我怎样才能模拟 OnDestroy 事件为 TFrame 在德尔福?


    我还加了一个 constructor destructor 在我的框架内,认为这就是 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;
    

    问题在于,到我的析构函数运行时,帧上的控件已被破坏,不再有效。

    原因是在包含窗体的析构函数中,它用来激发 毁灭 事件:

    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销毁窗体的窗口句柄。这会递归地破坏所有子窗口——包括我框架上的子窗口。

    所以当我的相框 析构函数 运行时,我尝试访问不再处于有效状态的控件。


    我怎样才能模拟 毁灭 事件为 T帧 在德尔福?

    也见

    4 回复  |  直到 14 年前
        1
  •  9
  •   Zoë Peterson RRUZ    14 年前

    您需要添加一个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_destroy消息返回后调用的,因此窗体及其所有子代句柄此时仍应有效(忽略在窗体OnDestroy中释放的任何句柄)。

        2
  •  1
  •   Ian Boyd    14 年前

    听起来更像 OnClose OnDestroy .

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

        3
  •  0
  •   Stijn Sanders    14 年前

    (这只是一个想法,但我现在没有时间来构建概念证明,但我会毫不犹豫地与大家分享。)

    如果Windows句柄有问题,您应该检查是否能够附加Windows的事件回调指针,该指针在框架的Windows句柄不再存在时被调用。也许有一个函数 RegisterWaitForSingleObject

        4
  •  0
  •   Daniel Maurić    14 年前

    另一种选择是重写 AfterConstruction BeforeDestruction

    像这样:

      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;