7

Delphiでの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;

これに伴う問題は、デストラクタが実行されるまでに、フレームのコントロールが破棄され、無効になっていることです。

この理由は、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でのOnDestroyイベントをシミュレートするにはどうすればよいですか?TFrame

も参照してください

4

4 に答える 4

11

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で解放されたものは無視されます)。 。

于 2010-10-20T16:37:19.520 に答える
1

OnCloseよりも似ているように聞こえOnDestroyます。

とにかく、私はすべてのフレームとフォームをベースの祖先から継承し、フォームのoncloseは、コンポーネント階層内のすべてのフレームを呼び出します。

于 2010-10-20T15:21:35.963 に答える
0

(これは単なるアイデアですが、概念実証を構築する時間が今のところありませんが、それでも共有します:)

Windowsハンドルに問題がある場合は、フレームのWindowsハンドルが存在しなくなったときに呼び出されるWindowsのイベントコールバックポインタをアタッチできるかどうかを確認する必要があります。おそらくRegisterWaitForSingleObjectのような関数で

于 2010-10-20T16:33:28.043 に答える
0

別のオプションは、オーバーライド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;
于 2010-10-20T21:14:33.170 に答える