Question

Comment puis-je simuler un événement OnDestroy pour un TFrame à Delphes?


i nievely a ajouté un constructor et destructor à mon cadre, pensant que c'est ce que TForm fait:

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;

Le problème est que le temps que mes courses destructor, les contrôles sur le châssis ont été détruits et ne sont plus valides.

La raison est dans la destructor de forme contenant, qu'il utilise pour déclencher un événement de 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;

Le destructor de mon objet cadre est appelé lors de l'exécution de destructor du formulaire. Problème est qu'il est trop tard. Le formulaire appels DestroyWindowHandle, qui demande à Windows de détruire la poignée de fenêtre du formulaire. Cela détruit récursive toutes les fenêtres de l'enfant -. Y compris ceux sur mon cadre

Alors, quand mon runs de destructor de cadre, je tente de contrôles d'accès qui ne sont plus dans un état valide.


Comment puis-je simuler un événement OnDestroy pour un TFrame à Delphes?

Voir aussi

Était-ce utile?

La solution

Vous devez ajouter un gestionnaire WM_DESTROY et vérifier csDestroying dans le ComponentState il est donc pris alors qu'en réalité la destruction, et non lors de la recréation de la poignée.

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;

Cela ne fonctionnera que si la poignée de fenêtre du cadre a été effectivement créé. Il n'y a pas un autre bon point de crochet, donc si vous voulez vous assurer qu'il est toujours appelé, vous aurez besoin de mettre un drapeau dans WMDestroy et revenir à l'appeler dans le destructor si ce n'est pas touché.

Les poignées de fenêtre se sont effacés dans WM_NCDESTROY, qui est appelé après que tous les descendants des messages WM_DESTROY retour, de sorte que la forme et toutes les poignées de ses childens restent valides à ce stade (sans tenir compte qui ont été libérés dans la OnDestroy de forme).

Autres conseils

Ressemble plus OnClose que OnDestroy.

Quoi qu'il en soit, je viens tous mes cadres hérité et les formes d'un ancêtre de base, et les appels OnClose puis tous les cadres du formulaire dans la hiérarchie du composant.

(Il est juste une idée, mais je n'ai pas eu le temps en ce moment pour construire une preuve de concept, mais je vais le partager pas moins:)

Si c'est un problème avec la poignée de Windows (s), vous devriez vérifier Que vous êtes en mesure de joindre un pointeur de rappel d'événement Windows qui est appelée lorsque Windows poignée cesse de existe du cadre. Peut-être avec une fonction comme RegisterWaitForSingleObject

Une autre option consiste à remplacer AfterConstruction et BeforeDestruction

Quelque chose comme ceci:

  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;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top