Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Die Delphi-IDE (https://www.delphipraxis.net/62-die-delphi-ide/)
-   -   Prüfen ob ein Objekt freigegeben wurde (Assigned geht nicht) (https://www.delphipraxis.net/193151-pruefen-ob-ein-objekt-freigegeben-wurde-assigned-geht-nicht.html)

Getox 27. Jun 2017 13:18

Prüfen ob ein Objekt freigegeben wurde (Assigned geht nicht)
 
Hallo mal wieder.

Ich habe ein Problem mit einem Objekt, dass freigegeben wurde, wo aber die variable nicht auf nil gesetzt wurde.

Code:
procedure TFormToast.showMessage(sMitteilung: String; aForm: TForm);
begin
  if Assigned(messageBoxToast) and (aCenterForm <> aForm) then
  begin
    messageBoxToast.HideAll;
    FreeAndNil(messageBoxToast);
  end;

  if not Assigned(messageBoxToast) then
  begin
    messageBoxToast := TAdvSmartMessageBox.Create(aForm);
    aCenterForm := aForm; //aCenterForm ist Klassenvariable
    messageBoxToast.DisplayLocation := dlbottomCenter;
    messageBoxToast.DisplayRelative := drForm;
  end;

  with MessageBoxToast.Messages.Add do
  begin
    Text := sMitteilung;
    Show;
  end;
end;
Der Sinn dahinter:
Es sollen an verschiedenen Stellen im Programm so Infoboxen erscheinen, die ich ganz im Android-Style einfach Toast nenne. Diese Nachrichten werden am Owner ausgerichtet, welcher immer ein anderes Form sein kann - aber nicht muss. Deshalb merke ich mir in einer Klassenvariable das übergebene Form und wenn ein anderes rein kommt, wird die TAdvSmartMessageBox freigegeben und mit dem neuen Form als Owner wieder erzeugt - an dem dann wieder die Nachrichten ausgerichtet werden.

jetzt habe ich das Problem, dass die übergebenen Forms oft (nicht immer) außerhalb wieder freigegeben werden und somit dürfte auch das Objekt hinter der Variable MessageBoxToast automatisch vom Owner freigegeben werden, ohne dass die Variable selber auf nil gesetzt wird.

Wenn ich jetzt eine neue Instanz des vorherigen Forms übergebe, sagt die Abfrage "(aCenterForm <> aForm)" false weil es angeblich das gleiche Form ist (trotz neuer Instanz) und die Variable von MessageBoxToast ist auch noch irgendwie assigned, weil sie ja noch nicht auf nil gesetzt wurde.

Dann scheint irgendwie im Speicher auf den MessageBoxToast zeigt nur blödsinn zu stehen, auf den ich zugreifen will und dann knallt es.

Wie kann ich also überprüfen, ob hinter der (nicht auf nil gestetzten) Variable noch ein intaktes Objekt hängt?

Zacherl 27. Jun 2017 13:25

AW: Prüfen ob ein Objekt freigegeben wurde (Assigned geht nicht)
 
Zitat:

Zitat von Getox (Beitrag 1375453)
Wie kann ich also überprüfen, ob hinter der (nicht auf nil gestetzten) Variable noch ein intaktes Objekt hängt?

Kurz und schmerzlos: Gar nicht ohne ekelhafte Hacks.

Stattdessen könntest du aber deinen Ansatz verfeinern, indem du beim Zuweisen des Formulars das
Delphi-Quellcode:
OnDestroy
Event einer Methode deiner
Delphi-Quellcode:
TAdvSmartMessageBox
Instanz zuweist und dort für das "nil-en" der entsprechenden Variable sorgst. Das wäre jetzt nur der einfachste Ansatz (welcher Probleme machen könnte, wenn du das
Delphi-Quellcode:
OnDestroy
Event bereits für irgendetwas Anderes im Formular verwendest, etc.).

Alternativ könntest du auch allen betroffenen Forms ein Interface verpassen, über welches du dein Destroy-Event sauber registrieren könntest. Gibt viele Möglichkeiten ... wichtig ist, dass du über irgendeinen Callback mitbekommst, wenn das Formular zerstört wird.

Edit: Dein
Delphi-Quellcode:
messageBoxToast
solltest du dann ggfls. auch selbst verwalten (also
Delphi-Quellcode:
AOwner
=
Delphi-Quellcode:
nil
).

Getox 27. Jun 2017 13:44

AW: Prüfen ob ein Objekt freigegeben wurde (Assigned geht nicht)
 
Ich muss das Übergebene Form als Owner setzen, damit die Nachrichten ja daran ausgerichtet werden. Wenn ich als Owner nil übergebe und das selber verwalten möchte, erscheinen die Nachrichten irgendwo ScreenCentered und dass sollen sie ja eben nicht.

Leider kann ich auch nicht einfach zur Laufzeit den Owner wechseln...

Unsere Forms benutzen leider so gut wie alle das "onDestroy" event, so dass ich es nicht einfach neu zuweisen kann.

Bei jedem Form ein Interface hinzufügen würde klappen wäre aber auch wieder komisch umständlich :( Ich wollte ja im Grunde eine Unit bauen, wo man mit minimalem aufwand (meist 1 Funktion mit 2 Parametern) überall im Programm diese Nachrichten erzeugen kann.

sakura 27. Jun 2017 14:09

AW: Prüfen ob ein Objekt freigegeben wurde (Assigned geht nicht)
 
Zitat:

Zitat von Getox (Beitrag 1375458)
Unsere Forms benutzen leider so gut wie alle das "onDestroy" event, so dass ich es nicht einfach neu zuweisen kann.

Du kannst auch den
Delphi-Quellcode:
destructor Destroy; override;
nutzen ;)

...:cat:...

Neumann 27. Jun 2017 14:15

AW: Prüfen ob ein Objekt freigegeben wurde (Assigned geht nicht)
 
Ich würde es vielleicht so machen:

Alternative 1
In jedem form.create auch gleich die box mit erzeugen, die Box unsichtbar setzten.
Wenn die Box angezeigt werden soll, Text zuweisen und showmodal;
Wir das Formular geschlossen dann auch freeandnil für die Box.

Alternative 2
Man könnte auch eine Box für alle Meldungen erzeugen und die wird dann immer nur mit Text versorgt und angezeigt.
Anstatt Owner könnte die Box dann eine Variable FromForm haben, eben die Form die die Box aufgerufen hat, müsste dann bei Aufruf gesetzt werden.
Positionieren sollte nicht das Problem sein, geht auch über FromForm. Natürlich geht dann nur eine Meldung zur Zeit.

Würde wohl Alternative 2 einsetzten.

Uwe Raabe 27. Jun 2017 14:21

AW: Prüfen ob ein Objekt freigegeben wurde (Assigned geht nicht)
 
Da es sich sowohl bei
Delphi-Quellcode:
messageBoxToast
und
Delphi-Quellcode:
aCenterForm
um Nachfahren von
Delphi-Quellcode:
TComponent
handelt, kannst du dich über die Freigabe dieser Instanzen mittels
Delphi-Quellcode:
FreeNotification
benachrichtigen lassen.

Delphi-Quellcode:
procedure TFormToast.Notification(AComponent: TComponent; Operation: TOperation);
begin
  if Operation = opRemove then
  begin
    if AComponent = messageBoxToast then
    begin
      messageBoxToast := nil;
    end;
    if AComponent = aCenterForm then
    begin
      aCenterForm := nil;
    end;
  end;
end;

procedure TFormToast.showMessage(sMitteilung: String; aForm: TForm);
begin
  if Assigned(messageBoxToast) and (aCenterForm <> aForm) then
  begin
    messageBoxToast.HideAll;
    aCenterForm.RemoveFreeNotification(Self);
    messageBoxToast.RemoveFreeNotification(Self);
    FreeAndNil(messageBoxToast);
  end;

  if not Assigned(messageBoxToast) then
  begin
    messageBoxToast := TAdvSmartMessageBox.Create(aForm);
    aCenterForm := aForm; //aCenterForm ist Klassenvariable
    messageBoxToast.DisplayLocation := dlbottomCenter;
    messageBoxToast.DisplayRelative := drForm;
    aCenterForm.FreeNotification(Self);
    messageBoxToast.FreeNotification(Self);
  end;
...

Getox 27. Jun 2017 15:07

AW: Prüfen ob ein Objekt freigegeben wurde (Assigned geht nicht)
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1375465)
Da es sich sowohl bei
Delphi-Quellcode:
messageBoxToast
und
Delphi-Quellcode:
aCenterForm
um Nachfahren von
Delphi-Quellcode:
TComponent
handelt, kannst du dich über die Freigabe dieser Instanzen mittels
Delphi-Quellcode:
FreeNotification
benachrichtigen lassen.

Vielen vielen Dank! Das war des Rätsels Lösung!

Ich musste nur noch ein
Delphi-Quellcode:
inherited;
unten in die
Delphi-Quellcode:
Notification
-Prozedur hinzufügen, weil sonst alles gehangen hat, aber nun läuft es. :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:55 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz