![]() |
Nochmal: Ermiteln ob Objekt freigegeben wurde
Hallo,
ich muß das Thema noch mal aufnehmen, da ich noch keine befriedigende Antwort / Lösung gefunden habe. Folgendes Problem: Ich habe ein von TForm abgeleitetes Objekt. Dieses Objekt wird erzeugt und dargestellt. Der Benutzer kann das Objekt schliessen und es soll dann auch Freigegeben werden. Es gibt eine Funktion um das Form anzuzeigen und falls nicht vorhanden neu zu erzeugen. Beispielcode:
Delphi-Quellcode:
Mein Problem ist nun folgendes:
// Unit1.pas
... procedure TForm1.Button1Click(Sender: TObject); begin if not Assigned(Form2) then begin Form2 := TForm2.Create(self); Memo1.Lines.Add(DateTimeToStr(now)+' Create'); end else Memo1.Lines.Add(DateTimeToStr(now)+' schon da'); Form2.Caption := 'Test'; Form2.Show; end; ... // unit2.pas ... type TForm2 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private-Deklarationen } public { Public-Deklarationen } end; ... procedure TForm2.Button1Click(Sender: TObject); begin Close; end; procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin // hier werden noch viele weitere Dinge freigegeben Action := caFree; end; ...
Delphi-Quellcode:
Hat jemand eine Idee?
...
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin FreeAndNil(Self); // oder Free; Self := nil; end; ... Folgende Beiträge habe ich auch schon gelesen, aber keine akzeptable Antwort erhalten: ![]() ![]() Danke für Eure Hilfe |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Evtl das
![]() |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Du musst die Methode Notification überschreiben. Da wirst du über das Freigeben des Formulares informiert:
Delphi-Quellcode:
Gruß, Frank
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private FForm2: TForm; { Private-Deklarationen } protected procedure Notification(AComponent : TComponent; Operation : TOperation); override; public constructor Create(AOwner: TComponent); override; { Public-Deklarationen } end; var Form1: TForm1; implementation uses Unit2; {$R *.dfm} constructor TForm1.Create(AOwner: TComponent); begin inherited; FForm2 := nil; end; procedure TForm1.Button1Click(Sender: TObject); begin // Form erzeugen, wenn nicht vorhanden if not Assigned(FForm2) then begin FForm2 := TForm2.Create(Self); // FForm2.FreeNotification(Self); FForm2.Show; end; end; procedure TForm1.Notification(AComponent : TComponent; Operation : TOperation); begin inherited Notification( AComponent, Operation); if Assigned(FForm2) then if (Operation = opRemove) and (AComponent = FForm2) then FForm2 := nil; end; end. |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Im FormClose der Objekte solltest Du folgendes machen:
Delphi-Quellcode:
Dann genügt es, später die globale Variable auf nil abzufragen:
Procedure MyForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin Action := caFree; end;
Delphi-Quellcode:
if frmMyForm = nil then
frmMyForm := TMyForm.Create(Application); frmMyForm.Show; |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
oder ganz einfach so:
Delphi-Quellcode:
Falls Form2 modal dargestellt wird, besser nach Schema
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin // hier werden noch viele weitere Dinge freigegeben Action := caFree; Form2 := nil; end; Create Showmodal Free vorgehen |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Eine Idee, wie es auf alle Fälle immer klappt, ist, einfach die Caption (z.B.) des Formulars zu ermitteln ... und das in einem try except block. Falls es schief geht, gibt es kein Objekt mehr. Falls es funktioniert ist dein Objekt noch da.
ist aber, zugegeben, nicht sehr elegeant.... aber funzt |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Zitat:
Bekomme dann bei manchen Aktionen allgemeine Schutzverletzungen. :-( Form ist nicht Modal. |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Zitat:
Das hatte ich ja auch schon im 1. Beitrag geschrieben.
![]() Hier ein Auszug des Quelltextes der TCustomForm zum Nachvollziehen:
Delphi-Quellcode:
[edit] Hatte Hagen statt negaH geschrieben[/edit]
{*******************************************************}
{ Borland Delphi Visual Component Library } { Copyright (c) 1995-2002 Borland Software Corporation } {*******************************************************} unit Forms; ... type TCustomForm = class(TScrollingWinControl) private ... procedure CMRelease(var Message: TMessage); message CM_RELEASE; ... protected ... procedure DoClose(var Action: TCloseAction); dynamic; ... public ... procedure Close; ... procedure Release; ... end; ... procedure TCustomForm.CMRelease; begin Free; end; ... procedure TCustomForm.DoClose(var Action: TCloseAction); begin if Assigned(FOnClose) then FOnClose(Self, Action); end; ... procedure TCustomForm.Close; begin ... DoClose(CloseAction); if CloseAction <> caNone then if Application.MainForm = Self then Application.Terminate else if CloseAction = caHide then Hide else if CloseAction = caMinimize then WindowState := wsMinimized else Release; ... end; ... procedure TCustomForm.Release; begin PostMessage(Handle, CM_RELEASE, 0, 0); end; ... |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Hi MaBuSE,
was stört dich daran, die Methode Notification zu verwenden. Die ist dafür da und wird vor allem in der Komponentenentwicklung für solche Fälle benutzt. Cu, Frank |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Zitat:
Ich bin gerade am ausprobieren und debuggen. Ich wollte erst was dazu schreiben, wenn ich mir das angeschaut habe :stupid: Aber Danke schon mal für die Antwort :thumb: |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Zitat:
Ich hab mir dazu mal einen "Objectbroker" gebastelt, der die ganze arbeit übernimmt. Dort meldet sich ein Object an oder ab. alle Zeiger auf objekte werden da verwaltet. Ein anderes Object fragt jetzt nicht mit assigned(Referenz) die Gültigkeit ab, sondern fragt den Objectbroker, ob objekt noch gültig ist. Zusätzlich kann man dem Objektbroker noch sagen, von welchem Objekt man die Abmeldenachricht in einem Event bekommen will ( um die eigene Referenz auf nil zu setzen). (Observer) Der Objektbroker löscht sich auch gegenseitig korrekt die Referenzen, da ein Objekt ja aus der Benachrichtigungsliste entfernt werden muss, wenn es gelöscht wird. |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Hi Mabuse,
es geht dir sicherlich um den Zeiger des Formulars, richtig? Legst du dir zusätzlich eine Zeiger-Variable an? Oder wird das Formular automatisch durch die Projektdatei erzeugt und besitzt "keine" Variable auf die du direkt zurückgreifen kannst? Hast du die Zeiger-Variable auch global definiert? |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Zitat:
|
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Zitat:
Das Programm ist nicht von mir. Es ist relativ komplex. Es werden mehrere 100 Forms verwendet, die von TBasisForm (Forms) oder TBasisClientForm (Frames) abgeleitet sind, in TBasisForm und TBasisClientForm ist ein eigenes "Festerverwaltungssystem" implementiert. Dort wird noch einiges gemacht. Ich muß da erst mal durchsteigen. Mir ist nur aufgefallen, das teilweise GPF auftreten, da obiges Problem besteht. Das Problem muß ich nun zuerst lösen. (Anforderung der Anwender) Danke für Eure Anregungen, ich werde nun mal einen Weile debuggen und dann berichten wie ich es gelöst habe. mfg MaBuSE |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Du darfst die Variable Form2 nicht verwenden!!!
Empfehlung: globale Variable Form2 löschen.
Delphi-Quellcode:
function FindOrCreateForm(FormClass: TFormClass; var Reference):Boolean;
var i : Integer; begin for i := Screen.CustomFormCount-1 downto 0 do begin if Screen.CustomForms[i].ClassType = FormClass then begin TCustomForm(Reference) := Screen.CustomForms[i]; Result := True; // gefunden Exit; end; end; Application.CreateForm(FormClass, Reference); Result := False; // neu erzeugt end; procedure TForm1.Button1Click(Sender: TObject); var frm : TForm2; begin if FindOrCreateForm(TForm2, frm) then begin Memo1.Lines.Add(DateTimeToStr(now)+' Create'); end else begin Memo1.Lines.Add(DateTimeToStr(now)+' schon da'); end; Frm.Caption := 'Test'; Frm.Show; Frm.WindowState := wsNormal; // falls minimiert -> sichtbar machen end; |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Zitat:
Aber keine Angst, sie wird im Projekt nicht verwendet. Ich habe aber ein anderes Problem entdeckt. Einige Forms werden mehrfach (in versch. Variablen) erzeugt. Bsp:
Delphi-Quellcode:
In dem Form2 habe ich keinen Zugriff auf privateForm1Var.
...
// in unit1.pas procedure TForm1.methode; begin if not assigned(privateForm1Var) then begin privateForm1Var := TForm2.Create(self); end; privateForm1Var.show end; // in unit3.pas procedure TForm3.andereMethode; begin if not assigned(privateForm3Var) then begin privateForm3Var := TForm2.Create(self); end; privateForm3Var.show end; ... 1. ist die Unit1 und Unit3 nicht in der uses des Form1 und 2. ist die Variable privat (lokal) Außerdem weis ich ja gar nicht in welcher Variable das TForm2 enthalten ist. Damit es nicht langweilig wird, sind manchmal auch mehrere Instanzen gleichzeitig aktiv. (also privateForm1Var <> privateForm3Var und beide <> nil) Ich kann also folgenden SourceCode nicht ausführen:
Delphi-Quellcode:
Folgendes funktioniert auch nicht, da dann zwar self auf nil gesetzt wird, aber privateForm1Var immer noch auf den "alten" Speicherbereich zeigt.
...
// Vorschlag von [user]tomsel[/user] procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin // hier werden noch viele weitere Dinge freigegeben Action := caFree; privateForm1Var := nil; end; ...
Delphi-Quellcode:
Der Lösungsansatz von shmia gefällt mir prinzipiell gut, aber es kann nur ein Form pro Typ erzeugt werden. Das Form muss aber auch mehrmals "sichtbar" sein.
...
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin // hier werden noch viele weitere Dinge freigegeben Action := caFree; self := nil; end; ... Die Idee von Bernhard Geyer das ![]() Der Lösungsansatz von dataspider scheint wohl der Beste zu sein. Das Problem dort ist allerdings, dass die lokale Variable im Form definiert sein muss und das bei jedem Objekt das eine Instanz erzeugt die Notification abgeleitet werden muss. Ich werde mit wohl eine FormFactory bauen müssen, die mir die Forms erzeugt und intern in einer Liste abspeichert. Diese FormFactory muß dann auch das Notification implementieren und dann die entsprechenden Speicherbereiche auf Nil setzen. Mal schauen ob das funktioniert. Danke an alle für die Anregungen |
Lösung: Nochmal: Ermiteln ob Objekt freigegeben wurde
Hallo,
ich habe eine einfache Lösung für mein Problem gefunden. Man muß dem Objekt nur bekannt machen welche Variable es referenziert. Diese kann man dann in onClose auf nil setzen. Man muß nur darauf achten, das man sich keine Kopie der Instanzvariablen, sondern die Adresse selber merkt. (Pointer auf Form2 vom Typ ^TForm2) Diesem Pointer weist man dann die Adresse zu := @Form2. Das war's. Relativ einfach, oder? ps: Vielen Dank an NicoDE, es war eigentlich seine Idee :thumb: Unit1 mit dem MainForm:
Delphi-Quellcode:
Und hier ist die Unit2 mit dem SubForm:
...
procedure TForm1.Button1Click(Sender: TObject); begin if not assigned(Form2) then begin Form2 := TForm2.Create(self); Form2.MyInstance := @Form2; end; form2.show; end; ...
Delphi-Quellcode:
...
unit Unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TForm2 = class(TForm) procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private-Deklarationen } public { Public-Deklarationen } MyInstance: ^TForm2; end; var Form2: TForm2; implementation {$R *.dfm} procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; MyInstance^ := nil; end; end. ... |
Re: Lösung: Nochmal: Ermiteln ob Objekt freigegeben wurde
Zitat:
Für die konkrete Problemstellung war es die schnellste (und 'dreckigste' ;)) Lösung mit möglichst wenig Änderungen am bestehenden Projekt. Kommt bei neuen Projekten bitte nicht auf die Idee diesen Lösungsweg als Vorlage zu verwenden. |
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Begründung?????
|
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Zitat:
Zitat:
|
Re: Nochmal: Ermiteln ob Objekt freigegeben wurde
Was machst du zum Beispiel, wenn du mehrere Referenzen auf das gleiche Objekt hast ;) Da hast ein kleines Problem mit nur einer Instanz Variable. Richtiger ist, über Events zu arbeiten. Ich habs so gelöst, dass ich mir eine Klasse gebastelt habe, mit der ich sehr einfach Events verwalten kann. So können dann auch mehrere Funktionen aufgeraufen werden, wenn ein Objekt zerstört wird.
Jeder der ne Referenz anlegt registriert sich auf das OnDestroy-Event und räumt dann auf, wenn es aufgerufen wird :) Das verwende ich natürlich nicht nur für OnDestroy sondern mittlerweile für alle Events. Falls interesse besteht, kann ich ja mal meine Klasse TNotifyList zur Verfügung stellen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:31 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz