![]() |
TForm Freigeben
Hallo,
Ich hab da ml eine einfache Frage zum Thema Forms im BDS 2006: Ich Habe mir eine eigene Klasse geschrieben :
Delphi-Quellcode:
type
TMeinForm = class(TForm) private { Private-Deklarationen } U_Ist_Destroy : Boolean; U_Ist_Close : Boolean; U_WarDeactivate : Boolean; U_Activate_Arbeitet : Boolean; U_DeActivate_Arbeitet : Boolean; ..... protected { Protected-Deklarationen } .... public Fensternr : Integer; DSFensterEinstellungen : TIBDataSet; constructor Create(AOwner : TComponent); override; destructor Destroy; override; published { Published-Deklarationen } end; constructor TMeinForm.Create(AOwner: TComponent); begin U_Ist_Destroy := false; U_Ist_Close := False; U_WarDeactivate := False; U_Activate_Arbeitet := False; U_DeActivate_Arbeitet := False; // Hier ist das Fenster noch nicht erzeugt inherited; // Hier ist das Fenster erzeugt -> nach dieser Proc (Create) kommt erst FormCreate aus dem jeweiligen Fenster U_Fensternr := FensterNr(Self); DSFensterEinstellungen := TIBDataSet.Create(Self); ..... end; destructor TMeinForm.Destroy; Var I : Integer; OBJ : TObject; warStamm : Boolean; begin U_Ist_Destroy := true; { For i := Self.ComponentCount -1 downto 0 do Begin OBJ := Self.Components[I]; FreeAndNil(OBJ); End; } FreeAndNil(DSFensterEinstellungen ); inherited; // if warStamm then Self := NIL; end; Aus dieser Fenstervorlage wird dann ein Fenster gebaut, wie man es in Delphi gewöhnt ist. Mit Panels, Buttons usw..... bsp:
Delphi-Quellcode:
type
TForm1 = class(TMeinForm) OpenDialog1: TOpenDialog; Tabelle_Gestalten: TMenuItem; PopUpINS: TMenuItem; PopUpDEL: TMenuItem; PopUpSAVE: TMenuItem; Panel1: TPanel; N1: TMenuItem; .... das Fenster wird mit "Application.CreateForm(TForm1, Form1)" erzeugt und anschliesend mit Form1.Show; angezeigt. Beim beenden des Fensters wird in FormClose Action auf CAFree gesetzt. Und jetzt kommt das Phänomen: Wenn der destructor komplett abgearbeitet worden ist haben einige Objecte auf Form1 haben noch einen Wert. (Form1.OpenDialog1 hat "$2621000"). Obwohl es das Fenster und damit auch semtliche Objecte auf ihm ja nichtmehr geben dürfte.Da Alle Objecte Form1 als Owner haben. Und genauso ist es auf mit der Variable "Form1". Wenn ich jetzt also Abfragen möchte
Delphi-Quellcode:
bekomme ich nur Leider bekomme ich dann bei "Form1.show;" eine Zugriffsferletzung.if not Assigned(Form1) then Application.CreateForm(TForm1, Form1); Form1.show; Da Form1 nicht Nil wird es nicht erzeugt. Obwohl es ja nicht da sein dürfte/ ist. Wenn ich jetzt aber in den destructor nach inherited; Self:= NIL; rein schreibe bekomme ich eine Zugriffsverletzung.(Was ja klar ist, da es ja auch eigentlich unsinn ist) Ich hoffe ihr könnt mir Dabei helfen, wie ich alle Objecte auf dem Form "Sauber" Zerstören kann und die Variable "Form1" auf NIL bekomme. |
Re: TForm Freigeben
Man sollte mit FreeAndNil() Freigeben, wenn man die Variable wiederverwenden will.
|
Re: TForm Freigeben
Aber wann bzw wo?
Im destructor kann ich Form1 nicht auf NIL setzten da anschließend eien Zugriffsverletzung kommt. |
Re: TForm Freigeben
Deshalb sollst du den Destruktor auch nicht direkt aufrufgen, sondern immer .Free() aufrufen. In diesem Fall
dann
Delphi-Quellcode:
statt
FreeAndNil( Form1);
Delphi-Quellcode:
oder gar
Form1.Free();
Delphi-Quellcode:
Form1.Destroy();
|
Re: TForm Freigeben
Das Fenster wird aber mit Form1.CLose geschlossen. Und nicht mit Destroy oder Free.
|
Re: TForm Freigeben
Im Event onCloseAction kannst du Steuern, was beim Close geschehen soll
|
Re: TForm Freigeben
Ich habe bei mir im BDS2006 kein Event "onCloseAction".
Ich habe nur OnClose:
Delphi-Quellcode:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin Action := CAFree; end; |
Re: TForm Freigeben
Den meinte ich :oops:
Dort caHide nehmen, dann wird Fenster nicht geschlossen sondern nur ausgeblendet und kann mit .Show wieder geöffnet werden |
Re: TForm Freigeben
Ich will das Fenster aber "Richtig" schließen um den Speicher wieder frei zu geben. Da das Programm aus ca 150 Fenstern besteht.
|
Re: TForm Freigeben
Wenn du .free machst ist der Speicher ja Freigegeben, nur stehen halt immernoch Werte drin.
Freigeben heist nur das andere Programme den Speicher neu beschreiben dürfen. Mit FreeAndNi(form1) wird auch nur der Pointer vom Form auf nil gesetzt. Wenn du den Speicher neu verwenden willst musst du ihn schon explizit auf 0 bzw das setzen was halt drinstehen soll. Wenn du auf nicht alocierten speicher zugreifst steht da halt drin was zuletzt reingeschrieben wurde. |
Re: TForm Freigeben
Zitat:
Ich habe es auch gerade mal mit der normalen Klasse TForm getestet. Hier tritt genau das gleiche Phänomen auf. Ich dachte erst das es an der neuen Klasse liegt aber dem ist nicht so. |
Re: TForm Freigeben
PS: es ist egal ob das Fenster über Application.CreateForm(TForm1, Form1) oder Form1 := TForm1.Create(); erzeugt wird.
Die Frage ist nur wir kann ich nach dem Schließen des Fensters die Variable Form1 wider auf NIL setzen? |
Re: TForm Freigeben
Aus der Klasse heraus nicht.
|
Re: TForm Freigeben
Zitat:
Aber wann könnte ich dann die Variable Form1 wieder auf nil setzten? |
Re: TForm Freigeben
Die Klasse kennt die Referenzvariablen, die zur Laufzeit existieren ja nicht.
|
Re: TForm Freigeben
AHHH :idea: :idea: jetzt hab ich verstanden wo das eigentliche Problem liegt.
Gibt es eine möglichkeit die die Referenzvariablen zu ermitteln? Wer ruft eigentichlich den destructor nach dem FormClose auf? |
Re: TForm Freigeben
Die Methode Close
|
Re: TForm Freigeben
und warum rufst du anstatt Form1.close nicht freeandnil(form1) auf? Da wird die Form doch auch vorher geschlossen und deine referenz ist nil.
|
Re: TForm Freigeben
Gibt es die möglichkeit sich eine Referenzvariablen zu speichern?
bsp. dem Constructor übergeben : CreatePCB(AOwner : TComponent; Var Reference); Diese Referenz im Object speichern und bei Destroy diese Referenz auf NIL setzten? geht sowas? |
Re: TForm Freigeben
Jein, nur unter gewissen Umständen. Aber das ergibt eine schöne Fehlerquelle, wenn diese Umstände nicht eingehalten werden. Und das ist meist der Fall.
==> Nein Edit: Von wo wird denn das Fenster geschlossen? |
Re: TForm Freigeben
Die Fenster werden Manuell(Über einen Beenden Button aufgerufen (Methode close)) über das "X oben Rechts" bzw. manchmal auch automatisch aus einer Aktion.
ABetr immer im Fenster selber. extrem selten das ein Fenster mal von einem anderen Fenster gesteuert wird. Gibt es eine möglichkeit abzuprüfen oder der wert noch gültig ist? if not Gültig(Form1) then Form1 := TForm1.Create; |
Re: TForm Freigeben
Du köntest ein spezielles Feld in die Klasse einbauen, dass du in einem try-except-Block abfragst. Aber 100% sicher und auch schön ist es nicht.
Wie wär es mit einem Ereignis, was ausgelöst wird, und die Referenz auf nil setzt? |
Re: TForm Freigeben
das Problem ist, das die Klasse die Referenzen nicht kennt.
Bsp: Ich weiß nicht,wer weiß wo ich Wohne. Und da bringt mir das Feld leider auch nichts, da es das ja auch nicht mehr gibt. |
Re: TForm Freigeben
Ich verstehe deinen Code nicht. Wieviele Referenzen erwartest du denn und warum?
|
Re: TForm Freigeben
Grundsätzlich erwarte ich nur eine Referenz.
|
Re: TForm Freigeben
Na dann brauchts du doch auch nur die auf Null setzen:
Concept-MainForm:
Delphi-Quellcode:
Form2:
type
TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } Form2:TForm2; //hier ist die wichtige Reference procedure DoClearReference; public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin if assigned(Form2) then Form2.BringToFront else begin Form2:=TForm2.Create(nil); Form2.clearReference:=DoClearReference; Form2.Show; end; end; procedure TForm1.DoClearReference; begin Form2:=nil; end;
Delphi-Quellcode:
type
TForm2 = class(TForm) procedure FormClose(Sender: TObject; var Action: TCloseAction); public ClearReference:procedure of object; end; implementation {$R *.dfm} procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin if assigned(clearReference) then ClearReference; end; end. |
Re: TForm Freigeben
die Idee ist an sich nicht verkehrt.
Das Problem ist, das ist bei 150 Fenster weder überschaubar noch pflegbar. Deswegen würde ich das ja gerne Automatisieren, bzw. dafür sorgen, das sich das ganze selber überwacht |
Re: TForm Freigeben
Wie jetzt? Wenn du 150 Fenster hast, müsstest du ja auch 150 Referenzen haben. Dann baust du sie halt in einer Liste, oder so.
|
Re: TForm Freigeben
ja klar ein Referenz pro Fenster.
Wie kann ich diese Referenzen in einer liste speichern? |
Re: TForm Freigeben
Vielleicht wie folgt:
Delphi-Quellcode:
type
TForm1 = class(TForm) Button1: TButton; SpinEdit1: TSpinEdit; procedure Button1Click(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private-Deklarationen } FForms:TComponentList; procedure DoClearReference(aFensterNr:Integer); procedure AddForm(aForm:TMeinForm); function ExistsForm(aFensterNr:Integer):boolean; function GetForm(aFensterNr:Integer):TMeinForm; procedure ClearForm(aFensterNr:Integer); public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var MeinForm:TMeinForm; begin if ExistsForm(SpinEdit1.Value) then GetForm(SpinEdit1.Value).BringToFront else begin MeinForm:=TMeinform.Create(self); MeinForm.ClearReference:=doClearReference; MeinForm.Fensternr:=SpinEdit1.Value; AddForm(MeinForm); MeinForm.Show; end; end; procedure TForm1.DoClearReference(aFensterNr:Integer); begin ClearForm(aFensterNr); end; procedure TForm1.FormDestroy(Sender: TObject); begin FForms.Free; end; procedure TForm1.FormCreate(Sender: TObject); begin FForms:=TComponentList.Create(false); end; procedure TForm1.AddForm(aForm: TMeinForm); begin FForms.Add(aForm); end; procedure TForm1.ClearForm(aFensterNr: Integer); var i:integer; begin for i:=FForms.count-1 downto 0 do if (FForms[i] as TMeinForm).Fensternr=aFensterNr then FForms.Delete(i); end; function TForm1.ExistsForm(aFensterNr: Integer): boolean; begin result:=GetForm(aFensterNr)<>nil; end; function TForm1.GetForm(aFensterNr: Integer): TMeinForm; var i:integer; begin result:=nil; for i:=0 to FForms.Count-1 do begin result:=(FForms[i] as TMeinForm); if result.Fensternr=aFensterNr then break; result:=nil; end; end;
Delphi-Quellcode:
Ob man die Listenverwaltung nochmal einzeln kapselt wäre sicher angebracht. Ich wollte es jetzt nicht zu umständlich/speziell machen.
type
TMeinForm = class(TForm) procedure FormClose(Sender: TObject; var Action: TCloseAction); public Fensternr : Integer; //habe ich mal als Erkennung von gleichen Fenstern genommen ClearReference:procedure(aFensterNr:Integer) of object; end; implementation {$R *.dfm} procedure TMeinForm.FormClose(Sender: TObject; var Action: TCloseAction); begin if assigned(clearReference) then ClearReference(FensterNr); end; |
Re: TForm Freigeben
Vielen dank
ich schaue mal ob ich die idee bei mir einbasteln kann. ich geb dir nochmal info. Danke aber schonmal für die ideeen |
Re: TForm Freigeben
Also ich habs jetzt mal bei mir Implementiert:
Ich habe 1. Alle Referenzen (Form1 : TForm1) rausgeschmissen. 2. eine Objectlist erstellt wo ich im Constructor von TMeinForm das neu erzeugte Fenster eintrage und im Destuctor aus dieser Liste wieder rausschmeiße. 3. Jedes DFenster hat eine eindeutige Nummer bekommen, welche ich in dem Object Speichere. 4. Es gibt nur noch eine Function, die mir an Hand der FensterNr das Object oder Nil zurück gibt. damit ist sichergestellt das keinerlei Referenzen hängen bleiben können. Einziger nachteil, Wenn ich auf Form1 zugreifen will muss ich jetzt immer TForm1(Fenster(123)) schreiben aber das ist ok. |
Re: TForm Freigeben
Den kleinen Nachteil könnte man jetzt auch noch umgehe,n indem man von der ComponentList eine eigene Liste ableitet, die nach außen hin mit TForm arbeitet. Aber da dürfte der Aufwand höher sein. Ich mach das nur ganz selten und meist, wenn ich sowieso die Listenklasse umschreiben muss.
|
Re: TForm Freigeben
Liste der Anhänge anzeigen (Anzahl: 1)
*altenThreadausgrab*
Das gleiche Thema mit dem Freigeben dynamisch erzeugter Forms hatte ich jetzt auch in meinem aktuellen Projekt. Zitat:
Ich hab die Klasse TDynamicFormManager von TObjectList abgeleitet und die Funktionen implementiert die ich brauchte:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:02 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