Formular als Dialog

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
wolfdec
Beiträge: 15
Registriert: Di 3. Feb 2009, 10:19

Formular als Dialog

Beitrag von wolfdec »

Hallo,

bastel gerade an einem kleinen Dialog. Der soll auch wieder verwendbar sein

Normal werden Forms in der lpr erzeugt, ich will aber nicht jedes mal dort rein, nur für ein Dialog.
Wo muss ich also mein Application.CreateForm hin packen?

Meine Idee war, ich erzeuge eine separate Prozedur.

Code: Alles auswählen

procedure MeinDialogShow():string;
begin
   Application.CreateForm(TMeinDialog, MeinDialog);
   MeinDialog.Show;
 
end;
Das Funktioniert auch für das erstellen, nur steigt der Speicherverbrauch der Anwendung bei jedem öffnen an. Stehen dann viele gleiche Dialoge im Raum, wenn man mehrmals drauf klickt und über ShowModal geht. Wo muss ich destroy plazieren, damit beim schliessen des Dialogs der Speicher wieder frei gegeben wird?

Im FormClose() bekomme ich einen Zugriffsfehler, wenn ich dort ein self.destroy() rein packe.
Als Notlösung setze ich beim CreateForm eine Variable auf True und lasse in MeinDialogShow() nur eine neue Form erzeugen, wenn die auf False ist.

Oder bin ich auf einem komplett falschem Weg?

Benutzeravatar
theo
Beiträge: 10871
Registriert: Mo 11. Sep 2006, 19:01

Re: Formular als Dialog

Beitrag von theo »

Es gibt sicher verschiedene Wege.

Code: Alles auswählen

Procedure TForm1.Button1Click(Sender: TObject);
Var Dial: TForm;
Begin
  Dial := TForm.CreateNew(Nil,0);
  Dial.Caption := 'Test';
  Dial.Position := poScreenCenter;
  With TButtonPanel.Create(Dial) Do
    Parent := Dial;
  Dial.ShowModal;
  Dial.free;
End;

Kunstbanause
Beiträge: 8
Registriert: Mi 14. Jan 2009, 11:48

Re: Formular als Dialog

Beitrag von Kunstbanause »

wolfdec hat geschrieben:Hallo,

bastel gerade an einem kleinen Dialog. Der soll auch wieder verwendbar sein

Normal werden Forms in der lpr erzeugt, ich will aber nicht jedes mal dort rein, nur für ein Dialog.
Wo muss ich also mein Application.CreateForm hin packen?

Meine Idee war, ich erzeuge eine separate Prozedur.

Code: Alles auswählen

procedure MeinDialogShow():string;
begin
   Application.CreateForm(TMeinDialog, MeinDialog);
   MeinDialog.Show;
 
end;
Das Funktioniert auch für das erstellen, nur steigt der Speicherverbrauch der Anwendung bei jedem öffnen an. Stehen dann viele gleiche Dialoge im Raum, wenn man mehrmals drauf klickt und über ShowModal geht. Wo muss ich destroy plazieren, damit beim schliessen des Dialogs der Speicher wieder frei gegeben wird?
Das mit der eigenen Procedure sollte funktionieren. Allerdings solltest Du dann im OnClose-Ereignis von TMeinDialog folgendes machen:

Code: Alles auswählen

procedure TMeinDialog.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  CloseAction := caFree;
end;
Dann wird der Speicher gleich frei gegeben, wenn der Anwender den Dialog schliesst. Dann ist es egal, wieviele davon geöffnet werden. Wenn es aber ein Dialog ist, der den Anwender auf irgendwas hinweisen soll und das weitere Ausführen des Programms solange "unterbrechen" soll, dann solltest du ShowModal nehmen (in dem Fall dann CloseAction nicht auf caFree setzen):

Code: Alles auswählen

procedure MeinDialogShow():string;
begin
   Application.CreateForm(TMeinDialog, MeinDialog);
   MeinDialog.ShowModal;
   MeinDialog.Free;
 end;
wolfdec hat geschrieben: Im FormClose() bekomme ich einen Zugriffsfehler, wenn ich dort ein self.destroy() rein packe.
Als Notlösung setze ich beim CreateForm eine Variable auf True und lasse in MeinDialogShow() nur eine neue Form erzeugen, wenn die auf False ist.

Oder bin ich auf einem komplett falschem Weg?
Destroy sollte NIEMALS direkt aufgerufen werden. Dafür ist die "Free"-Methode da. Und ausserdem solltest du ein Objekt niemals sein eigenes Free aufrufen lassen, da das Objekt sonst sprichwörtlich den Ast absägt, auf dem es sitzt.

wolfdec
Beiträge: 15
Registriert: Di 3. Feb 2009, 10:19

Re: Formular als Dialog

Beitrag von wolfdec »

Warum sollte man bei Modal kein caFree im FormClose setzen?

gilt das dann auch, wenn ich über eine Funktion mir etwas zurück geben lassen will?

Kunstbanause
Beiträge: 8
Registriert: Mi 14. Jan 2009, 11:48

Re: Formular als Dialog

Beitrag von Kunstbanause »

Ich muss mich übrigens korrigieren. TObject.Free ruft selber auch Self.Destroy auf, prüft aber vorher, ob Self<>nil ist. Sollte also Object nie assigned worden sein (=nil) dann wird mit Free keine Exception ausgelöst.
wolfdec hat geschrieben:Warum sollte man bei Modal kein caFree im FormClose setzen?
Solltest du ModalResult auswerten wollen, so könnte MeinDialog möglicherweise bereits freigegeben worden sein und du würdest eine Fehlermeldung bekommen (in der Theorie).

wolfdec hat geschrieben:gilt das dann auch, wenn ich über eine Funktion mir etwas zurück geben lassen will?
Was genau meinst du damit?

Lord Horazont
Beiträge: 13
Registriert: Mi 4. Feb 2009, 11:27
OS, Lazarus, FPC: Linux (L: 0.9.29; FPC: 2.2.4)
CPU-Target: 64-bit

Re: Formular als Dialog

Beitrag von Lord Horazont »

Natürlich kann ein Objekt bei sich selber Free aufrufen. In einigen Fällen kann das sinnvoll sein (z.B.: Threads, sieht man mal von FreeOnTerminate ab). Nur sollte man danach nicht mehr auf die Felder des Objektes zugreifen, das ist logisch.

Aber ich denke, die Form beim Start zu initialisieren und dann nur zu zeigen, wenn es nötig ist, ist der einfachste, sicherste und unkomplizierteste. Wenn du den Dialog unbedingt erst später erzeugen willst, würde ich das so machen, dass ich die Variable mit der Form am Anfang auf Nil setze (entweder per Initialization oder per = nil hinter der deklaration). Dann noch eine Prozedur, die für das anzeigen der Form zuständig ist und die, wenn die Form noch nil ist, selbige erstellt und danach anzeigt.

Gruß Lord Horazont

KOBOLD Messring GmbH
Beiträge: 155
Registriert: Mi 22. Aug 2007, 14:52
OS, Lazarus, FPC: Mandriva Linux 2008 (L 0.9.28 FPC 2.2.4)
CPU-Target: 32Bit
Wohnort: 65719 Hofheim am Taunus
Kontaktdaten:

Re: Formular als Dialog

Beitrag von KOBOLD Messring GmbH »

Also ich mach das so (kurz und schmerzlos - für den Speicher):

Code: Alles auswählen

Function TForm1.Konfiguriere (Const sID : String) : String;
Begin
  Form2 := TForm2.Create (NIL);
  IF Form2.BeginneKonfig (sID) AND (Form2.ShowModal = mrOK)
    THEN Result := Form2.sSachNr + ' {' + Form2.sSpeziIDs + '}'
    ELSE Result := '';
  Form2.Free;
End; { Konfiguriere }
Das ist eine kleine Funktion, welche die Form2 (in meinem Fall einen Konfigurationsdialog) erzeugt, dann eine dort deklarierte Funktion aufruft (BeginneKonfig), den Dialog Modal anzeigt und dann auf die Felder (der noch existierenden) Form zugreift (sSachnr und sSpeziIDs). Zum Schluss einfach Form2.Free - kurz und schmerzlos.

Antworten