Domanda

Come posso simulare un evento OnDestroy per un TFrame in Delphi?


i nievely aggiunto un constructor e destructor al mio telaio, pensando che è quello che fa 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;

Il problema è che per il momento le mie corse destructor, controlli sul telaio sono state distrutte e non sono più validi.

La ragione di questo è nel distruttore del modulo contenente, che utilizza per generare un evento 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;

Il distruttore della mia cornice oggetto viene chiamato quando distruttore del form viene eseguito. Problema con questo è che è troppo tardi. Le chiamate forma DestroyWindowHandle, che chiede a Windows di distruggere handle della finestra del modulo. Questo distrugge in modo ricorsivo tutte le finestre figlio -. Comprese quelle sul mio telaio

Così, quando viene eseguito destructor di mio telaio, tento di controlli di accesso che non sono più in uno stato valido.


Come posso simulare un evento OnDestroy per un TFrame in Delphi?

Vedi anche

È stato utile?

Soluzione

È necessario aggiungere un gestore WM_DESTROY e controllare csDestroying nel ComponentState in modo che sia catturato solo quando effettivamente distruggere, e non quando ricreare la maniglia.

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;

Questo funziona solo se handle della finestra del telaio è stato effettivamente realizzato. Non c'è un altro punto di aggancio buono, quindi se si vuole garantire che è sempre chiamata è necessario impostare un flag in WMDestroy e ripiegare a chiamarlo nel distruttore se non è colpito.

Le maniglie delle finestre stesse vengono cancellate in WM_NCDESTROY, che si chiama dopo tutto il discendente messaggi WM_DESTROY ritorno, così la forma e tutte le maniglie suoi childens dovrebbero essere ancora valido, a questo punto (senza tenere conto che sono stati liberati nel del modulo OnDestroy).

Altri suggerimenti

suona più come OnClose di OnDestroy.

In ogni caso, ho appena ereditato tutti i miei fotogrammi e le forme da un antenato di base, e le chiamate OnClose del form poi tutti i fotogrammi del gerarchia dei componenti.

(E 'solo un'idea, ma non ho avuto il tempo adesso di costruire una prova di concetto, ma io condividere nondimeno:)

Se è un problema con il manico di Windows (s), si dovrebbe verificare wether siete in grado di collegare puntatore evento di callback un Windows' che viene chiamato quando la maniglia di Windows del telaio cessa di esiste. Forse con una funzione come RegisterWaitForSingleObject

Un'altra opzione è quella di ignorare AfterConstruction e BeforeDestruction

Qualcosa di simile a questo:

  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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top