Autor Beitrag
Holgerwa
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 325

WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
BeitragVerfasst: Sa 09.04.05 20:19 
Hallo,

ich erstelle eine Form während des Programmablaufs:
ausblenden Delphi-Quelltext
1:
Application.CreateForm(TMyForm, MyForm);					

Die Form wird also nicht automatisch beim Programmstart erzeugt.
Kann man davon ausgehen, daß die Variable MyForm bis zum ersten Createn der Form auf NIL steht?
Es geht mir um eine Abfrage, ob die Form zur Zeit existiert, also etwas wie:
ausblenden Delphi-Quelltext
1:
2:
if MyForm <> nil then
...

Oder sollte die Variable MyForm bei Programmstart auf NIL gesetzt werden, um sicherzugehen?

Holger
WeBsPaCe
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 2322
Erhaltene Danke: 1

FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
BeitragVerfasst: Sa 09.04.05 20:57 
:gruebel: Du gibtst dir doch selber die Antwort auf deine Frage, wenn du das einfach mal ausprobierst... ;)

Natürlich kannst du deine Variable "zur Sicherheit" nochmal auf nil setzen, aber normalerweise ist sie das. Das ist genau das selbe, wie wenn du ne Integer deklarierst und sie dann auf 0 steht... ;)
Holgerwa Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 325

WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
BeitragVerfasst: Sa 09.04.05 21:07 
Hallo,

danke Dir für die Antwort.
user profile iconWeBsPaCe hat folgendes geschrieben:
:gruebel: Du gibtst dir doch selber die Antwort auf deine Frage, wenn du das einfach mal ausprobierst... ;)

Hast Du Recht, ich möchte nur sichergehen, denn wenn der Inhalt der Variablen erstmal undefiniert wäre, dann könnte ja mein Ausprobieren auch zufällige Ergebnisse liefern.
Holger
WeBsPaCe
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 2322
Erhaltene Danke: 1

FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
BeitragVerfasst: Sa 09.04.05 21:14 
Stimmt. Deshalb tu's doch einfach vordefinieren... ;)
hansa
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: Sa 09.04.05 21:51 
Wenn eine Form schon nicht beim Programmstart automatisch erzeugt wird, warum dann später doch mit Application.CreateForm ??? Application würde ich nicht einfach mal so als Variable benutzen. Es gilt übrigens die Faustformel : je globaler um so schlechter. Übertreiben sollte man das natürlich auch nicht.

Warum nicht so, bei irgendwas, was die Form anzeigen soll :

ausblenden Delphi-Quelltext
1:
  frm := Tfrm.Create(self);					


und das :

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
procedure Tfrm.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  Action := caFree;
end;


beim Schließen der Form. Dann ist sie da, oder eben nicht. Was gibts da noch abzufragen ? Warum darf die Form eigentlich nicht sofort erzeugt werden ?

_________________
Gruß
Hansa
Holgerwa Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 325

WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
BeitragVerfasst: Sa 09.04.05 22:17 
Hallo Hansa,

ich muß zugeben, ich habe mir noch nie darüber Gedanken gemacht, wie die Form erzeugt wird.
Application.CreateForm nehme ich, weil ich den Befehl einfach aus der Projekt-Source-Datei rausgenommen habe (damit sie dort nicht erzeugt wird), und wenn die Erzeugung dort so durchgeführt wird, warum dann nicht auch woanders? :oops:

Warum die Form nicht gleich beim Start erzeugen? Naja, mein Projekt hat nun ca. 40 Formen, und einige werden fast nie benötigt. Warum denn alle Formen im Projekt erzeugen, und Zeit beim Starten und Resourcen verschwenden, wenn's nicht nötig ist (Beispiel: Form zum Einstellen von Programmoptionen - wird nur selten verwendet, und nur bei Bedarf erzeugt).

Was gibts da noch abzufragen? Naja, der in mir eingebaute Drang zur Sicherheit. Natürlich weiß ich normalerweise, ob eine Form existiert oder nicht, aber bevor ein Zugriff auf sie eine Exception erzeugt, stelle ich lieber vorher sicher, daß sie existiert. Warum Fehler nach deren Auftreten beheben, wenn man das Auftreten verhindern kann?

Aber noch ne Frage: Was ist denn eigentlich der Unterschied zwischen Application.CreateForm und Tform.Create(self)?
Gibts da Vor- und Nachteile?

Danke!
Holger
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Sa 09.04.05 22:55 
Application.CreateForm erzeugt ein Formular mit dem Owner Application. Diese Form wird benutzt wenn ein Formular irgendwann erzeugt wird, und erhalten bleiben soll, bis die Application beendet wird.

Mit Form1 := TForm.Create(AOwner); hast du dagegen die Freiheit, festzulegen, wem das Formular gehört, d.h. du kannst festlegen, wer das Formular wann freigibt. Das ist der wesentliche Unterschied.
hansa
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: So 10.04.05 00:41 
War mir fast schon klar, daß das ganze aus der DPR abgekupfert wurde. Ich kann auch nur meine Erfahrungen weitergeben. Ob Du die nutzt, das bleibt dir überlassen. Intuitiv rate ich dir aber dringend davon ab, so was mit Application.CreateForm zu machen, sondern auf dem von mir beschriebenen Weg. Und 40 Forms sind nicht ganz ohne, um die Gefahr einzugehen, mit globalen Sachen Sphagetti-Code zu erzeugen ! Bei mir sind es ca. 200 Forms (kleinere wie Suchforms habe ich nicht mal mitgezählt), also noch einige mehr. Und auch bei 40 würde ich die eingebauten Sachen benutzen und nicht dauernd dran denken, eine Form auch wieder zu zerstören.

Wie sieht es denn damit eigentlich aus? Nachdem Application.CreateForm ausgeführt wurde ? Wie kriegst du die Form wieder aus dem Speicher ? Application.DestroyForm o.ä. habe ich noch nicht gesehen. Du wirst ja wohl nicht voraussetzen, daß nicht jemand alle Forms mal durchguckt ? Dann ist dein "Vorteil", die Forms zur Laufzeit zu erzeugen nämlich völlig uninteressant.

_________________
Gruß
Hansa
Holgerwa Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 325

WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
BeitragVerfasst: So 10.04.05 08:50 
Hallo Hansa,

ich bin doch für jede Verbesserung dankbar!
Habe mir einfach noch nie über diese spezielle Sache Gedanken gemacht, weil es für mich logisch klang. Aber wenn es da etwas zu verbessern gibt... sofort!

Im Moment mach ich das so, z.B. ein Button, der bei Click eine solche Form anzeigen soll:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
Application.CreateForm (Tfrm, frm);
...
frm.ShowModal;
...
frm.Release;

Das Release gibt dann den Speicher wieder frei. Sah für mich bis jetzt ganz sauber aus: Erzeugen, Benutzen, Entfernen.

Du sagst, daß die Verwendung von frm := CreateForm... besser ist. Das muß ich natürlich verstehen, denn nur so lernt man was :wink:
Warum ist es denn interessant, "wem" diese Form gehört (wie wdbee gesagt hat)? Ob das die Application ist, oder die Form durch die aufgerufen wird?
Was meinst Du mit Spaghetticode? Wo entsteht der?
Danke für Deine Hilfe!
Holger
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: So 10.04.05 10:39 
Lass dich nicht verwirren! Es ist durchaus richtig, folgendes zu machen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure TForm1.Button1Click(Sender: TObject);
var
  ModalForm: TModalForm;                  // Temp. Zeiger
begin
  ModalForm := TModalForm.Create(nil);// Gehört niemandem, mache alles selbst
  ModalForm.ShowModal; // Formular benutzen
  ModalForm.Release;   // Release statt free ist richtig und wichtig!
end;

Da du das Formular hier nur kurzzeitig benötigst, machst du das in der Regel so, um Resourcen zu sparen.

Ein anderer Fall sind z.B. MDI-Child-Fenster: Analog zu Word weißt du am Anfang ja garnicht, wie viele Child-Fenster du brauchst. Deshalb erzeugt du sie bei Bedarf.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure TForm1.CreateMDIChild(const Name: string);
var
  Child: TMDIChild;                       // Temp. Zeiger
begin
  Child := TMDIChild.Create(Application); // Gehört Application
  Child.Caption := Name;                  // Freigeben durch Application
end;

Der Zeiger auf das Formular kann temporär sein, weil die Application bzw. das MDIFrame-Formular sich um das Freigeben des Child-Formulars kümmert.

Es gibt also genügend Fälle wo man Formulare bei Bedarf erzeugt.

Das Owner-Prinzip in Delphi soll sicherstellen, dass die Verwendung von kopierten Zeigern nicht zu ungültigen Zeigern führt. Also angenommen, do erstellst ein Objekt und kopierst den erhaltenen Zeiger, weil das Objekt von zwei anderen, übergeordneten Objekten verwendet werden soll. Wenn nun eines der beiden übergeordneten Objekte freigegeben wird, muss klar sein, ob das untergeordnete Objekt auch freigegeben werden muss oder nicht. Wenn keines der übergeordneten Objekte dein Objekt löscht, gäbe es eine Leiche. Wenn es beide machen eine Exception. Also muss geklärt werden, wem das Objekt gehört:
    Keinem der übergeordneten Objekte (Dann muss ein Dritter das machen)
    Einem der übergeordneten Objekte (Dann muss dies das erkennen können)


// Edit: Obwohl hier in beiden Fällen temp. Zeiger verwendet werden, spielt es keine Rolle, dass die Zeiger NICHT nil sind, bevor Create aufgerufen wird, denn sie werden nicht vorher verwendet.
Anders ist es, wenn du globale oder Instanz-Variablen-Zeiger auf Objekte verwendest, die nur einmal erzeugt werden sollen. In diesem Fall musst du ja wissen, ob die Objekte schon erzeugt wurden, die Zeiger also schon gültig sind. Netter Weise initialisiert Delphi solche Zeiger aber auf nil, weshalb das so geht:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
  if MyObject = nil then
    MyObject := TMyObject.Create(aOwner);

  MyObject.UseIt;

Um die Freigabe muss sich dann AOwner kümmern.

Verstanden?

@hansa
ausblenden Delphi-Quelltext
1:
2:
3:
4:
procedure TModalForm.FormDestroy(Sender: TObject);
begin
  ShowMessage('ModalForm wird freigegeben');
end;

Wenn du das oben verwendest, siehst du, dass das unten richtig arbeitet:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure TForm1.Button1Click(Sender: TObject);
begin
  Application.CreateForm(TModalForm,ModalForm);
  ModalForm.Release;
  ModalForm := nil;
end;


Bei deinen Ratschlägen frage ich mich wieder mal ob du das ernst meinst: Je mehr Formulare, umso eher alle Formulare gleich automatisch erzeugen und sich den Speicher zumüllen, obwohl man nicht weiß, ob der Anwender das Formular jemals benutzt???

Traust du deinen Programmierkünsten so wenig, dass du dir nichtmal die Verwaltung deiner Formulare zutraust, oder bist du da nur einfach zu faul/beschäftigt um dich selbst drum zu kümmern und gehst da den Weg, nichts denken, einfach benutzen, hat ja Borland/Delphi schon realisiert???
Holgerwa Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 325

WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
BeitragVerfasst: So 10.04.05 11:24 
Hallo webee,

na, das war eine super Erklärung, vielen Dank! :idea:
Und daß Delphi noch nicht verwendete Zeige in diesem Fall mit NIL initialisiert, ist auch genau das, worüber ich mich anfänglich gewundert habe.
Man muß dann nur noch nach dem Form.Release den Zeiger wieder auf NIL setzen, damit beim nächsten Aufruf wieder erkannt werden kann, daß das Objekt nicht existiert, denn Release macht das nicht.
Ich hatte das mit dem Erzeugen von Formen so gelernt, daß man möglichst nur die Formen AutoCreated, die man während des gesamten Programmlaufs benötigt, oder die sehr oft aufgerufen werden. Alles Andere ist nur Verschwendung, und es ist den geringen Aufwand wert, das so zu programmieren, anstatt sich einfach auf das AutoCreate zu verlassen, weil es einfacher ist.

Danke Dir für die ausführliche Erklärung!
Holger
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: So 10.04.05 11:44 
Du siehst dir das im Moment aus dem Blickwinkel TForm an. Aber im Prinzip gilt das auch für alle Objekte! Der gewaltige Unterschied ist hierbei der, dass die VCL da einiges an Funktionalität realisert hat, damit das so bequem geht:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
procedure TCustomForm.Release;
begin
  PostMessage(Handle, CM_RELEASE, 00);
end;


So rufst du z.B. ModularForm.Release auf und setzt den gloabel Zeiger auf nil. Der Aufruf von Release setzt aber nur eine Meldung ab, dass das Formular freigegeben werden soll. Aber dennoch wird das Formular freigegeben, weil die TApplication eine interne Liste mit allen Formularen verwaltet (kopierte Zeiger!), die ihm gehören.
Das kann im allgemeinen Fall nur zuverlässig funktionieren, wenn der Destruktor deines Objektes weiß, bei wem er sich abmelden muss, falls er direkt aufgerufen wird. Deshalb hat der Constructor einen Parameter Owner!

Wenn du das mit anderen Objekten genauso sicher und bequem machen willst (die nicht gerade TComponents sind), dann musst du einen "Manager" realisieren, der das genauso oder ähnlich macht. Der Manager ist dann der Owner des Objekts.
hansa
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: So 10.04.05 13:50 
Wir reden konkret über TForm ? Oder eher darüber, daß man fast alles zur Laufzeit erzeugen kann ?

user profile iconwdbee hat folgendes geschrieben:


Traust du deinen Programmierkünsten so wenig, dass du dir nichtmal die Verwaltung deiner Formulare zutraust, oder bist du da nur einfach zu faul/beschäftigt...


Letzteres ist der Fall. :lol: Ich bin sogar so faul, daß ich die Forms zwar zur Laufzeit erzeuge, mich aber nicht mehr drum kümmere, daß sie wieder entfernt werden. Trotzdem ist zu 100 % sichergestellt, daß alles so richtig ist. :shock:

_________________
Gruß
Hansa