![]() |
2. Form schliessen Variable=Nil
Hallo,
ich glaube heute ist es zu warm.... oder ich sehe den Wald vor Bäumen nicht usw... daher brauche ich kurz Hilfe.... Szenario bisher: Form_1 erstellt zur Laufzeit eine Form_2 und zwar modal. Schön und gut. Saubere Sache.
Delphi-Quellcode:
unit1:
... Form2:=Tform.Create(nil); try Form2.ShowModal; finally FreeAndNil(Form2); end; ... Szenario jetzt: Die Form2 soll nicht mehr modal sein, kann aber jederzeit selber geschlossen oder erstellt werden oder Inhalte ändern sich oder wird bei Programmende einfach mit geschlossen. Form2 darf, wenn nur einmal existieren. Mein Problem gerade. Wenn die Form2 geschlossen wird dann bekommt unit1 das nicht mit und die Variable Form2 ist noch assigned, auch wenn in Form2 unter FormClose Action:=caFree; eingestellt ist.
Delphi-Quellcode:
Wie setze ich Form2=nil wenn der Anwender das Form_2 schliesst?
unit1:
uses uForm2,... Form2:TForm2; ... procedure TForm1.btnCreateForm2Click(Sender: TObject); begin if Assigned(Form2) then <--- hier knallts beim 2. Aufruf wenn Form2 geschlossen wurde, da Form2<>Nil ist! begin ShowMessage('schon da!'); Form2.BringToFront; end else begin Form2:=TForm2.Create(nil); Form2.Show; end; end; ... procedure TForm1.DingeDieDieWeltNichtBraucht; begin ... Form2.ZeigeWasAnderes; ... end; Ich möchte aber nicht FindComponent nutzen... Danke schon mal.... |
AW: 2. Form schliessen Variable=Nil
Setze Form2 einfach in OnDestroy von TForm2 auf nil. ;-)
|
AW: 2. Form schliessen Variable=Nil
Zitat:
|
AW: 2. Form schliessen Variable=Nil
setze in OnCreate/OnDestroy eine Klassenvariable auf true/false. Die kannst du dann abfragen.
|
AW: 2. Form schliessen Variable=Nil
Hallo,
das Form2 ist in den Optionen auf verfügbar eingestellt? Bis bald Chemiker |
AW: 2. Form schliessen Variable=Nil
Zitat:
Habe das jetzt so gelöst...
Delphi-Quellcode:
unit1;
.. type TForm1 = class(TForm) btnCreate: TButton; btnTest: TButton; procedure FormDestroy(Sender: TObject); procedure btnCreateClick(Sender: TObject); procedure btntestClick(Sender: TObject); private { Private-Deklarationen } Form2:TForm2; public { Public-Deklarationen } end; .. procedure TForm1.FormDestroy(Sender: TObject); begin Form2.free; end; procedure TForm1.btnCreateClick(Sender: TObject); begin if Assigned(Form2) then begin Form2.BringToFront; end else begin Form2 := TForm2.Create(nil); Form2.PFree := @Form2; Form2.Show; end; end; //////////////////////////////////////////////////////// unit2; .. type TForm2 = class(TForm) procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } PFree: ^TForm; // Adresse von end; .. procedure TForm2.FormCreate(Sender: TObject); begin PFree:=nil; end; procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin Action:=caFree; end; procedure TForm2.FormDestroy(Sender: TObject); begin if Assigned(PFree) then begin PFree^:=nil; end; end; |
AW: 2. Form schliessen Variable=Nil
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Aber eine andere Frage: Wozu zerstörst du das Formular eigentlich immer wieder? Es reicht doch, es bei der ersten Verwendung zu erstellen und danach einfach sichtbar oder unsichtbar zu machen. |
AW: 2. Form schliessen Variable=Nil
Na ja, wenn ich es schon dynamisch erstelle, dann auch richtig. Ansonsten kann ich in den Projektoptionen ja auch einstellen, dass es gleich erzeugt werden soll. Aber warum den Speicher unnütz belasten, wenn es nicht gebraucht wird?
|
AW: 2. Form schliessen Variable=Nil
Zitat:
Bei mir stehen die Formulare in den Optionen auf verfügbar! Zitat:
|
AW: 2. Form schliessen Variable=Nil
Hallo ipg,
reicht es nicht das Form2 statt mit From2.free einfach mit FreeAndNil(Form2) freizugeben? Bis bald Chemiker |
AW: 2. Form schliessen Variable=Nil
Zitat:
Schau mal hin wo ich Form2.free ausführe! ;-) |
AW: 2. Form schliessen Variable=Nil
Hallo ibp,
das Problem ist, dass Du in Form2.FormClose mit Action := caFree; den Speicher frei gibst, aber in Form1 noch auf das Form2 zeigt das nicht mehr vorhanden ist. Wenn Du das weglässt kannst Du doch jederzeit in Form1 mit FreeAndNil (Form2) das Form aus dem Speicher löschen und hast Form2 auf Nil gesetzt und kannst es anschließend wieder neu erzeugen. Bis bald Chemiker |
AW: 2. Form schliessen Variable=Nil
Zitat:
|
AW: 2. Form schliessen Variable=Nil
Hi,
Zitat:
Grüße |
AW: 2. Form schliessen Variable=Nil
So wie du das machst wird die Form TForm2 immer doppelt im Speicher vorhanden sein.
Einmal automatisch beim Programmstart und dann immer wieder beim Aufruf. Irgendwie nicht logisch. Also das Formular nicht automatisch erzeugen lassen. Um TForm2 Modal aufzurufen folgender Code:
Delphi-Quellcode:
Um die globale Variable "Form2" aus der Unit2 beim Free auf Nil zu setzen folgender Code
Procedure TForm1.OpenForm2Modal( Sender : TObject );
Var ModForm2 : TForm2; begin ModForm2 := TForm2.Create( Self ); Try ModForm2.ShowModal; Finally ModForm2.Free; end; end;
Delphi-Quellcode:
procedure TForm2.FormDestroy( Sender : TObject );
begin If Form2 = Self then Form2 := nil; end; |
AW: 2. Form schliessen Variable=Nil
Muss man nicht 'Release' anstelle von 'Free' aufrufen?
|
AW: 2. Form schliessen Variable=Nil
Hallo,
@Sir Rufo: Soweit ich das Verstanden habe wollte er kein Modal-Form haben. Ich würde es einfach so machen:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin if Assigned(TestForm) then begin ShowMessage('Schon da'); TestForm.Show; end else begin TestForm:=TForm2.Create(Self); end; end;
Delphi-Quellcode:
Bis bald Chemiker
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin Action := caFree; end; procedure TForm2.FormCreate(Sender: TObject); begin Caption:= 'Form1 - Test'; Show; end; procedure TForm2.FormDestroy(Sender: TObject); begin if Assigned(TestForm) then begin TestForm:=NIL; end; end; end. |
AW: 2. Form schliessen Variable=Nil
Zitat:
Zitat:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin if not Assigned( Form2 ) then begin Form2 := TForm2.Create( Self ); end else begin ShowMessage( 'Schon da' ); end; Form2.Show; end; Zitat:
Delphi-Quellcode:
procedure TForm2.FormDestroy(Sender: TObject);
begin // Nur wenn die aktuelle Instanz mit der in der globalen Variablen "Form2" gespeicherten übereinstimmt if Form2 = Self then begin Form2 := NIL; end; end; |
AW: 2. Form schliessen Variable=Nil
Was passiert, wenn Form2 zwischen Close und Destroy angezeigt werden soll?
Wieso nicht Form2 nicht einfach im FormClose auf Nil setzen? Weiterhin sollte das Anzeigen und die Logik, ob Form2 schon da ist, in TForm2 selbst implementiert werden. Entweder in einer Class Procedure 'ShowNonModal', oder in einer Funktion, die den Zugriff auf Form2 steuert (Ich würde Letzteres vorziehen)
Delphi-Quellcode:
Nun kann ich Form2 auch dann anzeigen, wenn es gerade geschlossen, aber noch nicht freigegeben wurde.
Function Form2 : TForm2;
Implementation Var _Form2 : TForm2; Function Form2 : TForm2; Begin If _Form2 = Nil Then _Form2 := TForm2.Create(Nil); Result := _Form2; End; ... Procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); Begin Action := caFree; If Self=_Form2 then _Form2 := Nil; End; [edit]Oh, die Verfeinerung von Sir Rufo fehlt[/edit] |
AW: 2. Form schliessen Variable=Nil
sehe ich das falsch oder nutzt ihr dazu eine globale Variable um in unit2 die Form beim beenden auf NIL zu setzen damit es dann in unit1 vorhanden ist?
Also bei mir ist das so, dass unit2 keinen Zugang zu unit1 hat. Wie macht das eigentlich TComponentList? Wenn dort ein Objekt sich selber zerstört, dann löscht sie den Eintrag selber. War spät gestern und bin nicht ganz hinter die Logik gestiegen. |
AW: 2. Form schliessen Variable=Nil
Ich weiß ja nicht mit welchem Delphi du programmierst, aber wenn ich einfach mal ein Formular neu erstelle, dann habe ich da folgenden Code
Delphi-Quellcode:
und nun rat mal, was die Variable "Form2" ist ... ein globale ;)
unit Unit2;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TForm2 = class(TForm) private { Private-Deklarationen } public { Public-Deklarationen } end; var Form2: TForm2; implementation {$R *.dfm} end. Und um von einer anderen Form diese steuern zu können muss ich ja idR dort die Unit einbinden:
Delphi-Quellcode:
und somit kennt die Unit1 auch die Variable "Form2"
unit Unit1;
interface ... implementation uses Unit2; ... end. |
AW: 2. Form schliessen Variable=Nil
Hallo,
für nichtmodale Forms müssen meiner Meinung eine globale Variabel erzeugt werden, wie soll das sonst funktionieren? Bis bald Chemiker |
AW: 2. Form schliessen Variable=Nil
@Sir Rufo,
die 2. Form soll dynamisch erzeugt werden und steht in den Optionen nicht unter automatisch erzeugen. Ist es dann wirklich so, dass dann die Variable Form2 in der unit1 direkt ansprechbar ist und wenn sie nil ist dass dann in unit1 übergibt? Was ist mit mehreren Instanzen von der Form2, wenn diese auch aus anderen Units genutzt wird? @Chemiker habe das ja auch schon gelöst, siehe ![]() |
AW: 2. Form schliessen Variable=Nil
Das hat ja nichts damit zu tun, ob es sich um ein Formular handelt oder nicht. Globale Variablen im interface-Abschnitt sind generell von überall erreichbar, sofern die enthaltende Unit eingebunden wird. Willst Du mehrere Instanzen erzeugen, solltest Du Dir diese unbedingt in einer Liste (TObjectList, Array etc.) merken, da die eine Variable ja sonst mit jeder weiteren Instanz überschrieben und die alte Instanz somit unerreichbar wird.
|
AW: 2. Form schliessen Variable=Nil
Zitat:
|
AW: 2. Form schliessen Variable=Nil
Dann nimm doch einfach verschiedene Variablen vom Typ TForm2.
|
AW: 2. Form schliessen Variable=Nil
Zitat:
(Zudem die automatische Erstellung des Formulars genau diese Variable benötigt -> s.u. ) Es reicht ja, wenn alle, die darauf zugreifen wollen den Zugriff haben und wenn diese Zugriffe nur innerhalb einer Unit passieren, dann würde ich keine globale Variable benötigen. Zitat:
Wenn du mehrere Instanzen benötigst, dann musst du dich um die Verwaltung dieser selber kümmern. Und ja, wird die Instanz von TForm2 nicht automatisch beim Start erzeugt, dann ist Form2 NIL.
Delphi-Quellcode:
program Test;
uses Forms, Unit1 in 'Unit1.pas' {Form1}, Unit2 in 'Unit2.pas' {Form2}; {$R *.res} begin Application.Initialize; Application.MainFormOnTaskbar := True; Application.CreateForm(TForm1, Form1); // <- da passiert die Zuweisung Application.CreateForm(TForm2, Form2); // <- und da auch Application.Run; end. |
AW: 2. Form schliessen Variable=Nil
eben und sie soll ja nicht automatisch erzeugt werden, sondern dynamisch im Bedarfsfall!
Spricht denn etwas gegen die Lösung in Post 6? Ja ich bekenne mich schuldig, ich hätte die Variablennamen anders benennen sollen! |
AW: 2. Form schliessen Variable=Nil
Wenn von dem Formular tatsächlich immer nur eine Instanz zur gleichen Zeit angezeigt werden soll macht der Vorschlag in Beitrag #19 für mich am ehesten Sinn. Das sieht mir wie eine abgewandelte Form des Singleton-Patterns aus.
|
AW: 2. Form schliessen Variable=Nil
Zitat:
|
AW: 2. Form schliessen Variable=Nil
so nun fasse ich zusammen...
Aufgabenstellung: Aus Unit_x wird zu Laufzeit eine Form_Y aus Unit_y erzeugt. Form_Y wird nicht automatisch erzeugt. Aus unit_x kann auf die Form_Y über eine private Variable zugegriffen werden. Die Form_Y kann durch den Schließen-Button nach Bedarf beendet werden, dabei wird die Variable in Unit_x auf Nil gestzt. Unit_y kennt nicht Unit_x. Es können mehrere Instanzen von Form_y aus anderen Units erzeugt werden. Meine Lösung:
Delphi-Quellcode:
unit Unit1;
interface uses Unit2, ... type TForm1 = class(TForm) btnCreate: TButton; btnTest: TButton; procedure FormDestroy(Sender: TObject); procedure btnShowTestFormClick(Sender: TObject); procedure btntestClick(Sender: TObject); private { Private-Deklarationen } TestForm:TForm2; public { Public-Deklarationen } end; var Form1: TForm1; ... procedure TForm1.FormDestroy(Sender: TObject); begin TestForm.free; end; procedure TForm1.btnShowTestFormClick(Sender: TObject); begin TestForm.DoShow(@TestForm); end; procedure TForm1.btnTestClick(Sender: TObject); begin if Assigned(TestForm) then ShowMessage('TestForm existiert') else ShowMessage('TestForm nicht existent') end;
Delphi-Quellcode:
unit Unit2;
type TForm2 = class(TForm) procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormDestroy(Sender: TObject); private { Private-Deklarationen } PCallVarAdr:^TForm; public { Public-Deklarationen } constructor Create(AOwner: TComponent; const SelfVarAdr:Pointer); overload; procedure DoShow(const SelfVarAdr:Pointer); end; implementation {$R *.dfm} constructor TForm2.Create(AOwner: TComponent; const SelfVarAdr:Pointer); begin inherited Create(AOwner); PCallVarAdr := SelfVarAdr; Show; end; procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin Action:=caFree; end; procedure TForm2.FormDestroy(Sender: TObject); begin if Assigned(PCallVarAdr) and Assigned(PCallVarAdr^) and (PCallVarAdr^=Self) then begin PCallVarAdr^:=nil; end; end; procedure TForm2.DoShow(const SelfVarAdr:Pointer); begin if Assigned(TForm(SelfVarAdr^)) then begin BringToFront; end else begin TForm2.Create(nil,SelfVarAdr); end; end; |
AW: 2. Form schliessen Variable=Nil
Hi,
Alternative zu deiner Zeiger-Geschichte wäre das OnDestroy-Event von Form2 auf eine Methode in Form1 umzuleiten und dort das Feld zu nillen:
Delphi-Quellcode:
Nachteil an der Geschichte wäre, wenn die OnDestroy schon durch was anderes belegt ist - hier könnte man diese Wert allerdings "zwischenspeichern" und dann im TEstFormDestroy aufrufen...if not Assigned(TestForm) then TestForm:=TForm2.Create(self); TestForm.OnDestroy:=TestFormDestroy; TestForm.Show; ... procedure TForm1.TestFormDestroy(Sender: TObject); begin TestForm:=nil; end; Grüße |
AW: 2. Form schliessen Variable=Nil
Hallo ibp,
nur wie willst Du das lösen, wenn Du von Form3 auf das Form2 zugreifen willst und das Form2 noch vorhanden ist? Bis bald Chemiker |
AW: 2. Form schliessen Variable=Nil
Zitat:
|
AW: 2. Form schliessen Variable=Nil
Also bei der Aufgabenstellung sollte man das vielleicht so lösen:
Delphi-Quellcode:
unit Unit1;
interface uses Unit2; type TForm1 = class( TForm ) private PrivateForm : TForm2; procedure SubFormDestroy( Sender : TObject ); procedure ErzeugeSubForm( Sender : TObject ); ... implementation procedure TForm1.ErzeugeSubForm( Sender : TObject ); begin PrivateForm := TForm2.Create( Self ); PrivateForm.OnDestroy := SubFormDestroy; end; procedure TForm1.SubFormDestroy( Sender : TObject ); begin PrivateForm := nil; end; |
AW: 2. Form schliessen Variable=Nil
Hallo ibp,
Zitat:
Bis bald Chemiker |
AW: 2. Form schliessen Variable=Nil
Ich weiss zwar nicht mehr, wo die Idee her ist, aber bei mir funktioniert das so: das bewusste Fenster bekommt einen wohldefinierten Namen - am Besten in einer Konstanten hinterlegt.
Diese Funktion findet ein Fenster mit einem bestimmten Namen:
Delphi-Quellcode:
Diese Funktion aktiviert das Fenster, wenn bereits vorhanden, ansonsten wird es erzeugt:
function FindFormByName(AFormName: string): TForm;
var li: integer; begin Result := nil; for li:= 0 to Screen.FormCount-1 do begin if (Screen.Forms[li].Name = AFormName) then begin Result := Screen.Forms[li]; break; end; end; end;
Delphi-Quellcode:
Hoffe, das hilft.
const
FORMNAME = 'MeinSuperFenster'; var lfrm : TMyForm; // das zu zeigende Fenster begin lfrm := TMyForm(FindFormByName(FORMNAME)); if Assigned(lfrm) then begin lfrm.Show; lfrm.BringToFront; end else begin lfrm := TMyForm.Create(Application); lfrm.Name := FORMNAME; lfrm.Show; end; |
AW: 2. Form schliessen Variable=Nil
@ConnorMcLeod
ich wollte keine Funktion à la FindXYZ nutzen! |
AW: 2. Form schliessen Variable=Nil
nächste Variante:
das zweite Fenster sendet eine userdefined message an seinen Owner (das erste Fenster) im OnDestroy und der Owner reagiert auf diese Message mit dem Nilen der Variable. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:53 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-2025 by Thomas Breitkreuz