Delphi-PRAXiS
Seite 1 von 4  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi dynamisch erzeugte Forms richtig freigeben (https://www.delphipraxis.net/185719-dynamisch-erzeugte-forms-richtig-freigeben.html)

die Suchende 1. Jul 2015 14:47

dynamisch erzeugte Forms richtig freigeben
 
Hallo zusammen,

vorn weg: ich arbeite mit Delphi 5 (arbeitgeberseitig vorgeschrieben) und bearbeite das Programm eines Kollegen (nicht mehr in der Firma)

Ich habe Verständnisprobleme wie er seine dynamisch erzeugten Seiten aufruft und schließt/terminiert?
Mein Ziel wäre es, die Seiten auch mit dem "Kreuzchen" schließen zu können ... wie ein Abbrechen-Button. Aber wie ist das genau richtig?


Folgendes:
Delphi-Quellcode:
   
procedure TfrmSplash.btnOKClick(Sender: TObject);
...
    frmSpeicherverzeichnis:=nil; //warum macht er das?
    if Speicherverzeichnis='' then
    begin
      Application.CreateForm(TfrmSpeicherverzeichnis, frmSpeicherverzeichnis);
      frmSpeicherverzeichnis.Show;
      self.Enabled:=False;
    end;

    while assigned(frmSpeicherverzeichnis) do
    begin
      Application.ProcessMessages;
    end;



    if (IRPort=0) or (ArduinoPort=0) then
    begin
      Application.MessageBox('Die Schnittstellen konnten nicht ermitteln. '+
        'Schalten Sie den Controller aus um im nächsten Schritt die korrekte '+
          'Erkennung zu gewährleisten.', 'Achtung', mb_OK + mb_ICONWARNING);
      Application.CreateForm(TfrmPortErkennung, frmPortErkennung);
      frmPortErkennung.Show;
      self.Release;
      exit;
    end
      else
      begin

      ...
              Application.CreateForm(TfrmStartseite1B, frmStartseite1B);
              frmStartseite1B.Show;
              self.Hide;
      end;
    end;
     
end;

______

procedure TfrmSpeicherverzeichnis.btnAbbrechenClick(Sender: TObject);
begin
  self.Release;
end;

procedure TfrmSpeicherverzeichnis.FormDestroy(Sender: TObject);
begin
  frmSpeicherverzeichnis:=nil;
end;
Warum das "Nil" der SpeicherverzeichnisOberfläche, wenn er es erst danach erzeugt? Warum kein "if not Assigned" wie unten beschrieben? Oder ist das nur Programmiererspezifisch?

Warum das "self.hide" seiner Startoberfläche? Da sind keine Elemente/ Objekte, die er nochmal benutzt.


bzw.


Delphi-Quellcode:
procedure TfrmStartseite1B.btnOptionenClick(Sender: TObject);
begin
  if not Messung.MessungLaeuft then
  begin
    Application.CreateForm(TfrmOptionen, frmOptionen);
    frmOptionen.show;
    self.Enabled:=False;
  end
    else
    begin
      Application.MessageBox('Das Fenster kann nur aufgerufen werden, wenn ' +
        'aktuell keine Messung läuft.', 'Achtung', mb_OK + mb_ICONWARNING);
    end;
end;

___________

procedure TfrmOptionen.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
  CanClose:=False;
  frmStartseite1B.Enabled:=True;
  self.Release;

  if assigned(frmStartseite1B) then
  begin
    frmStartseite1B.Enabled:=True;
  end;

  if assigned(frmStartseite2B) then
  begin
    frmStartseite2B.Enabled:=True;
  end;
end;

procedure TfrmOptionen.btnOKClick(Sender: TObject);
begin
  close;
end;

Ich habe im Forum so viel rausbekommen, dass
• Form.close = Form.Visible := false
• Form.release = setzt eine Application. Message ab/ gibt aber nix frei
• Form.Free ist was anderes als Form.freeAndNil


Meine Fragen:
• Ist es wirklich sinnvol, die aufrufende Form immer Enabled:=false zu setzen?
• Auf manchen Seiten steht bei CloseQuery nur CanClose:=false und beim Abbrechen-Button aber nur close; !? da kann ich doch das CloseQuery weglassen oder?
• Mir wiederstrebt es irgendwie die Form nicht in sich selbst zu beenden (Form.CloseQuery)... ist das nicht sauberer


reicht es nicht (so hab ich es bisher gemacht ... bin kein Programmierer):

Delphi-Quellcode:
procedure TfrmStartseite.MomentanwerteButtonClick(Sender: TObject);
begin

  if not Assigned(frmMomentanwerte) then begin
    Application.CreateForm(TfrmMomentanwerte,frmMomentanwerte);
  end;
  frmMomentanwerte.show;


  frmMomentanwerte.Button2Click(Self); //aktualisiert die Daten

end;
______


procedure TfrmMomentanwerte.Button1Click(Sender: TObject);
begin
  close; //Button "zur Startseite"
end;


procedure TfrmMomentanwerte.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
     frmMomentanwerte.Release;
     frmMomentanwerte := nil;
end;


______
procedure TfrmStartseite.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
...
         if Assigned(frmMomentanwerte) then frmMomentanwerte.Release;
         if Assigned(frmKundeneinstellungen) then frmKundeneinstellungen.Release;
         ...
         //für alle dynamischen Forms
         //falls noch was offen ist, wenn das Programm beendet wird
...
         //andere Variablen wieder freigeben

         //Messung ist bereits beendet
         CanClose := true;  

end;
...
So würde ich jetzt seine Forms anpassen. Da ich mir aber nicht sicher bin, ob das so korrekt ist (mal abgesehen von dem Programmierauffwand) möchte ich hier lieber nochmal nachfragen, wie man das eigentlich richtig macht.


Schon mal Danke im Vorraus
die Suchende

nuclearping 1. Jul 2015 17:01

AW: dynamisch erzeugte Forms richtig freigeben
 
Hello :)

Da hast du ja einen ganz schönen Brocken bekommen ...

Zitat:

Zitat von die Suchende (Beitrag 1307360)
Warum das "Nil" der SpeicherverzeichnisOberfläche, wenn er es erst danach erzeugt? Warum kein "if not Assigned" wie unten beschrieben? Oder ist das nur Programmiererspezifisch?

Ich vermute, dass
Delphi-Quellcode:
frmSpeicherverzeichnis
entweder eine globale Variable oder ein Property von
Delphi-Quellcode:
TfrmSplash
ist. Also existiert die Variable über den ganzen Programmablauf. Und er wollte damit wohl sicherstellen, dass der Programmablauf in der nachfolgenden Schleife nicht blockiert wird, wenn
Delphi-Quellcode:
Speicherverzeichnis
schon gesetzt wurde.

Weiterhin sieht es so aus, als ob er hier ein
Delphi-Quellcode:
ShowModal
"simuliert". Das lässt der darunterliegende Block vermuten:
Delphi-Quellcode:
while assigned(frmSpeicherverzeichnis) do
  begin
    Application.ProcessMessages;
  end;
Das ist sehr unsauber, da es den gesamten restlichen Programmablauf in der Schleife blockiert.

Warum er hier nicht einfach ...
Delphi-Quellcode:
if Speicherverzeichnis='' then
  begin
    frmSpeicherverzeichnis := TfrmSpeicherverzeichnis.Create(Self);
    frmSpeicherverzeichnis.ShowModal;
  end;
... verwendet, kann ich aus dem Code jedoch nicht ersehen.

Zitat:

Zitat von die Suchende (Beitrag 1307360)
Warum das "self.hide" seiner Startoberfläche? Da sind keine Elemente/ Objekte, die er nochmal benutzt.

Ich vermute, dass er hier das Elternformular (
Delphi-Quellcode:
frmSplash
) verstecken will?

Genauso auch hier:
Delphi-Quellcode:
procedure TfrmStartseite1B.btnOptionenClick(Sender: TObject);
begin
  if not Messung.MessungLaeuft then
  begin
    Application.CreateForm(TfrmOptionen, frmOptionen);
    frmOptionen.show;
    self.Enabled:=False;
  end
    else
    begin
      Application.MessageBox('Das Fenster kann nur aufgerufen werden, wenn ' +
        'aktuell keine Messung läuft.', 'Achtung', mb_OK + mb_ICONWARNING);
    end;
end;
Statt ...
Delphi-Quellcode:
Application.CreateForm(TfrmOptionen, frmOptionen);
frmOptionen.show;
self.Enabled:=False;
... kann man (theoretisch) auch ...
Delphi-Quellcode:
frmOptionen := TfrmOptionen.Create(Self);
frmOptionen.ShowModal;
... machen.

Zitat:

Zitat von die Suchende (Beitrag 1307360)
Ich habe im Forum so viel rausbekommen, dass ...

Delphi-Quellcode:
Form.close = Form.Visible := false

Jein, nicht ganz.
Delphi-Quellcode:
Form.Close
prüft über
Delphi-Quellcode:
Form.CloseQuery
, ob eine Form geschlossen werden kann. Wenn
Delphi-Quellcode:
Form.CloseQuery
Delphi-Quellcode:
CanClose := FALSE
setzt, bleibt die Form offen.

Delphi-Quellcode:
Form.release = setzt eine Application. Message ab/ gibt aber nix frei

Richtig.
Delphi-Quellcode:
Form.Release
setzt eine Message in die MessageQueue, die "irgendwann" verarbeitet wird und erst dann wird das Fenster geschlossen.
Ich habe aber auch mal gelernt, dass man nicht mit
Delphi-Quellcode:
Release
arbeiten sollte.

Delphi-Quellcode:
Form.Free ist was anderes als Form.freeAndNil

Gibt es
Delphi-Quellcode:
Form.FreeAndNil
in Delphi 5 wirklich (noch)? Ich habe das jedenfalls hier nicht. Es gibt die Funktion
Delphi-Quellcode:
FreeAndNil(var ObjectReference)
, die eine übergebene Variable des Typs
Delphi-Quellcode:
TObject
nach dem Freigeben auf
Delphi-Quellcode:
nil
setzt.
Delphi-Quellcode:
FreeAndNil
macht also nichts anderes als
Delphi-Quellcode:
ObjectReference.Free; ObjectReference := nil
Zitat:

Zitat von die Suchende (Beitrag 1307360)
Ist es wirklich sinnvol, die aufrufende Form immer Enabled:=false zu setzen?

Ohne den Rest zu kennen: Nein, sinnvoller wäre es, mit
Delphi-Quellcode:
ShowModal
zu arbeiten. Es sei denn es gibt zwingend Gründe, warum man das so machen müsste.

Zitat:

Zitat von die Suchende (Beitrag 1307360)
Auf manchen Seiten steht bei CloseQuery nur CanClose:=false und beim Abbrechen-Button aber nur close; !? da kann ich doch das CloseQuery weglassen oder?

Ich vermute, dadurch, dass der ursprüngliche Programmierer hier mit
Delphi-Quellcode:
Release
arbeit, er das
Delphi-Quellcode:
CloseQuery
"übergeht", um sicherzustellen, dass die Form nur dann geschlossen wird, wenn der Benutzer einen bestimmten Ablauf einhält. Zum Beispiel dass eine Form nicht über das [x] geschlossen werden darf, sondern nur über die zur Verfügung stehenden Buttons.

Zitat:

Zitat von die Suchende (Beitrag 1307360)
Mir wiederstrebt es irgendwie die Form nicht in sich selbst zu beenden (Form.CloseQuery)... ist das nicht sauberer

Wie schon gesagt: Wir kennen den Rest nicht und wissen auch nicht, was der Programmierer sich dabei gedacht hat. Aber ja, prinzipiell wäre es "sauberer", eine nicht mehr benötigte Form an der Stelle zu schliessen / freizugeben, wo sie ihren Zweck erfüllt hat.

Zitat:

Zitat von die Suchende (Beitrag 1307360)
reicht es nicht (so hab ich es bisher gemacht ... bin kein Programmierer):

Delphi-Quellcode:
procedure TfrmMomentanwerte.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
     frmMomentanwerte.Release;
     frmMomentanwerte := nil;
end;
Delphi-Quellcode:
CloseQuery
sollte nur am Ende
Delphi-Quellcode:
CanClose
setzen. Sonst nichts anderes.

Wenn es eine globale Variable
Delphi-Quellcode:
frmMomentanwerte
gibt, die unbedingt auf
Delphi-Quellcode:
nil
gesetzt werden muss, dann sollte das entweder in
Delphi-Quellcode:
OnClose
oder
Delphi-Quellcode:
OnDestroy
passieren.

Lange Rede, kurzer Sinn: Das was der ursprüngliche Programmierer da gemacht hat, erscheint mir recht unsauber und "brachial". Aber wie schon gesagt, er wird scheinbar seine Gründe dazu gehabt haben. Jedoch denke ich, dass man das Ganze viel eleganter löser kann, indem man die Formen-Logik nochmal überdenkt und an vielen Stellen
Delphi-Quellcode:
ShowModal
benutzt.

die Suchende 2. Jul 2015 08:41

AW: dynamisch erzeugte Forms richtig freigeben
 
Danke nuclearping,

für die ausführliche Antwort. Ich hatte meinem ehemaligen Kollegen auch eine E-Mail geschickt, woraufhin er nur antwortete, dass er nicht über das Kreuzchen schließen lassen will, da "man bei dieser Art des Schließens oft nicht weiß ob der Nutzer getätigte Änderungen übernehmen will oder eben nicht. Daher ist das meist nur über "OK" oder "Abbrechen" möglich." ...
Naja, ich bin halt anderer Meinung und habe Probleme damit in desen Verlaufsweg gezwungen zu werden. Ich möchte auch während einer Messung mal Parameter anschauen können ... vielleicht nochmal Diagrammeinstellungen ändern und dann wieder zu Parametern zurückkehren ... vielleicht war es auch nur der mangelnden Zeit geschuldet...

Ich werde das mit dem ShowModal mal probieren, ob ich das an diesen Stellen als bedienerfreundlich empfinde.

Also wenn ich es jetzt so Mache ist das OK?

Delphi-Quellcode:
procedure TfrmStartseite.MomentanwerteButtonClick(Sender: TObject);
begin

  if not Assigned(frmMomentanwerte) then begin
    Application.CreateForm(TfrmMomentanwerte,frmMomentanwerte);
  end;
  frmMomentanwerte.show;


  frmMomentanwerte.Button2Click(Self); //aktualisiert die Daten

end;
______


procedure TfrmMomentanwerte.Button1Click(Sender: TObject);
begin
  close; //Button "zur Startseite"
end;


procedure TfrmMomentanwerte.FormDestroy(Sender: TObject;  //oder kann ich mir das sparen
  var CanClose: Boolean);
begin
     frmMomentanwerte := nil;
end;


______
procedure TfrmStartseite.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
...
         if Assigned(frmMomentanwerte) then begin
            frmMomentanwerte.Close;  //statt Release ... besser als Release?
            //und anschließend noch "frmMomentanwerte := nil;" wenn es dort nicht in der FormDestroy steht?
            //oder doch lieber immer ein FormDestroy mit nil?
         if Assigned(frmKundeneinstellungen) then frmKundeneinstellungen.Release;
         ...
         //für alle dynamischen Forms
         //falls noch was offen ist, wenn das Programm beendet wird
...
         //andere Variablen wieder freigeben

         //Messung ist bereits beendet
         CanClose := true;

end;
Ich will einfach nur, dass meine Resourcen nach dem "Programm schließen" wieder sauber freigegeben werden. Die Forms sind halt dynamisch gedacht und wenn was nicht benutzt wird, muss es ja auch keinen Speicher/Arbeitsspeicher belegen. Ich hab mich mit der Resourcenverwaltung noch nicht weiter beschäftigt. Ich bin meist froh, wenn das Programm macht was es soll. Aber wenigstens die Forms sollten sauber erzeugt und geschlossen werden.

Grüße
die Suchende

DeddyH 2. Jul 2015 08:50

AW: dynamisch erzeugte Forms richtig freigeben
 
Wenn Du dynamische modale Fenster brauchst, geht das eigentlich ganz einfach.
Delphi-Quellcode:
procedure TMainForm.ButtonBlubbClick(Sender: TObject);
var
  frmSettings: TrmSettings;
begin
  frmSettings := TfrmSettings.Create(nil);
  try
    //Benutzer hat "OK" geklickt
    if frmSettings.ShowModal = mrOK then
      MachWas;
  finally
    frmSettings.Free;
  end;
end;
Dazu würde ich die entsprechenden Formulare erstens nicht automatisch erzeugen lassen (scheint ja schon so zu sein) und in deren Units die jeweilige globale Formular-Variable rigoros löschen, da sie nicht gebraucht wird und man so recht schnell merkt, wo überall davon Gebrauch gemacht wird. Dann muss man aber auch daran denken, dass die Buttons auch das ModalResult des Formulars setzen sollten (kann man im Objektinspektor einstellen), sonst funktioniert der obige Code nicht wie erwartet.

die Suchende 2. Jul 2015 09:13

AW: dynamisch erzeugte Forms richtig freigeben
 
Danke DaddyH,

ich hab jetzt 'ne Ahnung wie ich's machen kann. Für kleinere Anfragen werde ich demnächst das ShowModal nutzen und wie ich die Antworten auslese, hast du ja auch erklärt :) danke.

Perlsau 2. Jul 2015 09:22

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von die Suchende (Beitrag 1307431)
... dass er nicht über das Kreuzchen schließen lassen will, da "man bei dieser Art des Schließens oft nicht weiß ob der Nutzer getätigte Änderungen übernehmen will oder eben nicht. Daher ist das meist nur über "OK" oder "Abbrechen" möglich." ...

.
Mit Verlaub, aber dein Kollege erzählt Quatsch: Es liegt am Programmierer, wie ein Programm auf das Schließen eines Formulars in dessen OnClose-Ereignisbehandlung reagiert. Das Ereignis OnClose wird auch dann ausgelöst, wenn der Anwender auf das X in der Titelleiste klickt.

Wenn ein modales Fenster unter diversen Bedingungen mit je einem anderem Rückgabe-Wert geschlossen werden soll, spielt das X sowieso keine Rolle, weil bereits beim Setzen von Modalresult ungleich mrNone das modale Fenster geschlossen wird.

mm1256 2. Jul 2015 13:09

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von die Suchende (Beitrag 1307431)
... woraufhin er nur antwortete, dass er nicht über das Kreuzchen schließen lassen will, da "man bei dieser Art des Schließens oft nicht weiß ob der Nutzer getätigte Änderungen übernehmen will oder eben nicht. Daher ist das meist nur über "OK" oder "Abbrechen" möglich....

Da hat er prinzipiell auch recht. Aber, wenn man das Schließen eines Fensters sowieso nur über entsprechende Buttons ermöglichen will, wozu dann überhaupt das [X] anzeigen? Das ist meiner Meinung nach unsinnig.

Also weg mit allen BorderIcons und Alt+F4 abfangen, und gut isses. Dann wird auch sauberer Code daraus.

BadenPower 2. Jul 2015 14:19

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von mm1256 (Beitrag 1307474)
Aber, wenn man das Schließen eines Fensters sowieso nur über entsprechende Buttons ermöglichen will, wozu dann überhaupt das [X] anzeigen? Das ist meiner Meinung nach unsinnig.

Also weg mit allen BorderIcons und Alt+F4 abfangen, und gut isses. Dann wird auch sauberer Code daraus.

Einfach das [X] deaktivieren, dann kannst Du die restlichen BorderIcons und das Systemmenu immer noch benutzen und brauchst noch nicht einmal Alt+F4 abfangen.

DeddyH 2. Jul 2015 14:57

AW: dynamisch erzeugte Forms richtig freigeben
 
Wozu das "X" deaktivieren? Wird das Fenster einfach geschlossen, ist ModalResult mrNone, bei Abbrechen mrCancel und nur bei Bestätigung mrOK. Wo ist das Problem?

baumina 2. Jul 2015 15:12

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von DeddyH (Beitrag 1307487)
Wird das Fenster einfach geschlossen, ist ModalResult mrNone

Wird ein modales Fenster mit X oder Alt-F4 geschlossen, ist Modalresult = mrCancel, nicht mrNone.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:58 Uhr.
Seite 1 von 4  1 23     Letzte »    

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz