Delphi-PRAXiS

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.

Dalai 2. Jul 2015 15:13

AW: dynamisch erzeugte Forms richtig freigeben
 
Außerdem kann man das Schließen eines Forms via [X] im OnCloseQuery "abfangen" oder besser gesagt be-/verarbeiten.

MfG Dalai

DeddyH 2. Jul 2015 15:15

AW: dynamisch erzeugte Forms richtig freigeben
 
Dann eben so, aber nicht mrOK. Und nur das sollte man im Normalfall prüfen.

BadenPower 2. Jul 2015 15:21

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von DeddyH (Beitrag 1307487)
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?

Die Antwort bezog sich jetzt nicht auf dieses Fenster/Problem, sondern rein auf den Beitrag von mm1256.

Er wollte doch alle BorderIcons und das Systemmenu verbannen und noch ALT+F4 abfangen.

In diesem Falle, wenn er verhindern wollte, dass das [X] angeklickt werden kann, finde ich es praktischer nur das [X] zu deaktivieren, damit alles andere rund um die Titelleiste aktiv bleibt.

baumina 2. Jul 2015 15:21

AW: dynamisch erzeugte Forms richtig freigeben
 
Ich ärger mich aber auch immer, dass man anhand des ModalResults keinen Unterschied erkennen kann, ob der Button "Abbrechen" geklickt wurde, oder nur das Formular geschlossen wurde.

baumina 2. Jul 2015 15:24

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von BadenPower (Beitrag 1307496)
... finde ich es praktischer nur das [X] zu deaktivieren, damit alles andere rund um die Titelleiste aktiv bleibt.

Wie macht man das?

Sir Rufo 2. Jul 2015 15:26

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von baumina (Beitrag 1307497)
Ich ärger mich aber auch immer, dass man anhand des ModalResults keinen Unterschied erkennen kann, ob der Button "Abbrechen" geklickt wurde, oder nur das Formular geschlossen wurde.

Ja, wenn es mal so etwas wie Delphi-Referenz durchsuchenmrAbort geben würde, dann könnte man ja das an den Button klatschen :stupid:

Hier die Liste aller ModalResult Werte http://docwiki.embarcadero.com/Libra...ogs.MessageDlg

baumina 2. Jul 2015 15:35

AW: dynamisch erzeugte Forms richtig freigeben
 
Das ist mir sowieso schon immer schleierhaft, warum der eine Knopf "Abbruch" und der andere "Abbrechen" heißt, ist das denn Windows oder ist das Delphi?

Nachtrag: Ich glaube sogar, dass in den ganz frühen Delphiversionen der Knopf für Kind=bkCancel "Abbruch" und nicht "Abbrechen" hieß, kann mich aber auch irren.

BadenPower 2. Jul 2015 15:39

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von baumina (Beitrag 1307498)
Zitat:

Zitat von BadenPower (Beitrag 1307496)
... finde ich es praktischer nur das [X] zu deaktivieren, damit alles andere rund um die Titelleiste aktiv bleibt.

Wie macht man das?

So wie Du jeden MenuEintrag manipulieren kannst:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure DoFormCloseButtonEnable(AHandle: HWND; AEnable: Boolean);
var
  lMenue: Integer;
begin
  lMenue := Windows.GetSystemMenu(AHandle, LongBool(False));
  if (lMenue <> 0) then
   begin
    if (AEnable) then
     begin
      Windows.EnableMenuItem(lMenue, SC_CLOSE, MF_BYCOMMAND or MF_SYSMENU);
     end
    else
     begin
      Windows.EnableMenuItem(lMenue, SC_CLOSE, MF_BYCOMMAND or MF_GRAYED);
     end;
   end;

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  DoFormCloseButtonEnable(Handle,false);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  DoFormCloseButtonEnable(Handle,true);
end;

end.

Stevie 2. Jul 2015 15:52

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von baumina (Beitrag 1307501)
Das ist mir sowieso schon immer schleierhaft, warum der eine Knopf "Abbruch" und der andere "Abbrechen" heißt

Weil das die Übersetzung von Abort und Cancel ist? :stupid:

Sir Rufo 2. Jul 2015 17:23

AW: dynamisch erzeugte Forms richtig freigeben
 
Eine dynamische Dialog-Form gibt man einfach wieder frei:
Delphi-Quellcode:
procedure Foo;
var
  LForm: TForm;
begin
  LForm := TFooDialo.Create(nil);
  try
    case LForm.ShowModal of
      mrOK :
        begin
          ...
        end;
      mrCancel :
        begin
          ...
        end;
      ...
    end;
  finally
    LForm.Free;
  end;
end;
Wenn in dem Dialog noch weitere Daten erfasst werden sollen, dann übergibt man vor dem Anzeigen diese Daten und holt sich diese im Erfolgsfall wieder ab:
Delphi-Quellcode:
type
  TFooData = class( TPersistent )
  public
    property SomeStr: string;
    property SomeBool: Boolean;
  end;

type
  TFooDialog = class( TForm )
    Edit1: TEdit;
    Checkbox1: TCheckBox;
  private
    procedure AssignTo( FooData: TFooData ); overload;
    procedure AssignFrom( FooData: TFooData );
  protected
    procedure AssignTo( Dest: TPersistent ); overload; override;
  public
    procedure Assign( Source: TPersistent ); override;
  end;

procedure TFooDialog.AssignTo( FooData: TFooData );
begin
  FooData.SomeStr := Edit1.Text;
  FooData.SomeBool := CheckBox1.Checked;
end;

procedure TFooDialog.AssignFrom( FooData: TFooData );
begin
  Edit1.Text := FooData.SomeStr;
  CheckBox1.Checked := FooData.SomeBool;
end;

procedure TFooDialog.AssignTo( Dest: TPersistent );
begin
  if Dest is TFooData then
    AssignTo( TFooData( Dest ) )
  else
    inherited;
end;

procedure TFooDialog.Assign( Source: TPersistent );
begin
  if Source is TFooData then
    AssignFrom( TFooData( Source ) )
  else
    inherited;
end;
und dann so
Delphi-Quellcode:
procedure Foo( FooData: TFooData );
var
  LDialog: TForm;
begin
  LDialog := TFooDialog.Create( nil );
  try
    LDialog.Assign( FooData ); // Daten an die Form schreiben
    if LDialog.ShowModal = mrOK then
      FooData.Assign( LDialog ); // Daten von der Form lesen
  finally
    LDialog.Free;
  end;
end;

Hansa 2. Jul 2015 19:56

AW: dynamisch erzeugte Forms richtig freigeben
 
Wenn man von der Überschrift ausgeht :

Zitat:

dynamisch erzeugte Forms richtig freigeben
dann bin ich etwas erstaunt, dass bisher kein einziges mal das Wort
Delphi-Quellcode:
caFree
vorkam.

Wenn das OnClose so aussieht :

Delphi-Quellcode:
procedure Tfrm.FormClose(Sender: TObject; var Action: TCloseAction);
var FensterIni,
    SonstIni : TIniFile;
begin
  inherited;
// wenn nötig hier noch andere Aktionen ausführen.
  Action := caFree;
end;
dann ist die Form freigegeben und fertig. Egal, ob sie mit Alt-F4, Schliess-x usw. geschlossen wird.

Sir Rufo 2. Jul 2015 20:23

AW: dynamisch erzeugte Forms richtig freigeben
 
Was sich bei einem Dialog - der auch noch dynamisch erzeugt wird und man den direkt an der festen Leine hat - richtig gut macht. Da ist der weg, bevor ich mir das Ergebnis nach dem
Delphi-Quellcode:
ShowModal
holen kann.

BadenPower 2. Jul 2015 20:46

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von Sir Rufo (Beitrag 1307520)
Da ist der weg, bevor ich mir das Ergebnis nach dem
Delphi-Quellcode:
ShowModal
holen kann.

Dann gehst Du den anderen Weg und läßt die Modal-Form vorher die Werte an den Aufrufer übergeben.

Sir Rufo 2. Jul 2015 20:57

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von BadenPower (Beitrag 1307521)
Zitat:

Zitat von Sir Rufo (Beitrag 1307520)
Da ist der weg, bevor ich mir das Ergebnis nach dem
Delphi-Quellcode:
ShowModal
holen kann.

Dann gehst Du den anderen Weg und läßt die Modal-Form vorher die Werte an den Aufrufer übergeben.

Ja, das würde schon gehen, allerdings ist es schwierig, das in einem robusten Code zu gießen.

Hier wird die Dialog-Instanz immer freigegeben:
Delphi-Quellcode:
LDialog := TDialog.Create(nil);
try
  LDialog.Assign( LDialogData );
  if LDialog.ShowModal = mrOK then
    LDialogData.Assign( LDialog );
finally
  LDialog.Free;
end;
wenn der Dialog sich selber aus dem Speicher räumt und vorher aber noch die Daten irgendwo hinschreiben soll, dann kann es aufgrund einer Exeption dazu kommen, dass die Instanz doch nicht freigegeben wird.

Gut ich kann dort natürlich im Dialog die Exception fangen und dann irgendwie durchreichen, oder so ... oder ich mache es mir einfach (s.o.) und bekomme dort alles mit und trotzdem ist alles immer sauber.

Jeder wie er mag, aber ich mag halt robust und sauber ...

Stevie 2. Jul 2015 21:32

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von Sir Rufo (Beitrag 1307522)
ich mag halt robust und sauber ...

Ich auch, aber bisher seh ich da eher 8 Zeilen Boilerplate code. Das kannst du doch besser, oder? ;)

redox 3. Jul 2015 00:36

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von Stevie (Beitrag 1307525)
Zitat:

Zitat von Sir Rufo (Beitrag 1307522)
ich mag halt robust und sauber ...

Ich auch, aber bisher seh ich da eher 8 Zeilen Boilerplate code. Das kannst du doch besser, oder? ;)

..und vor Allem mit einem Backup zu viel als einem Backup zu wenig :!:

Wer weiß schon, was sich der ursprüngliche Programmierer gedacht hat bei seinem (eventuell bewußten?) Verzicht auf ShowModal...

LG

BadenPower 3. Jul 2015 08:37

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von redox (Beitrag 1307531)
Wer weiß schon, was sich der ursprüngliche Programmierer gedacht hat bei seinem (eventuell bewußten?) Verzicht auf ShowModal...

Unter Umständen, sogar sehr viel.

Ich für meinen Teil benutze auch nie ShowModal und keine Standard-Dialog-Fenster, da sonst der Rest der Anwendung nicht mehr bedient werden kann.

Beispiel:
Die Anwendung hat ein Hauptfenster, welches oben an Bildschirm angezeigt wird und einfach (fast) nur ein Menu hat.

Wenn ich jetzt aber ein Fenster Modal aufrufen würde (auch zum Beipiel ein Unterfenster eines Unterfensters), dann könnte ich kein anderes Fenster öffnen und müsste die Bearbeitung abbrechen um nur einmal schnell einem Kunden an Telefon eine andere Auskunft geben zu können.

mm1256 3. Jul 2015 10:27

AW: dynamisch erzeugte Forms richtig freigeben
 
Hallo,

es geht wieder zurück zur ursprünglichen Problematik und da hab ich in #7 schon geschrieben

Zitat:

Also weg mit allen BorderIcons und Alt+F4 abfangen, und gut isses. Dann wird auch sauberer Code daraus.
Damit ist es so was von egal, ob ich das Fenster modal anzeige, wobei in dem Fall vom ursprünglichen Programmierer modale Anzeige aus welchen Gründen auch immer nicht gewollt war, oder ob das Fenster normal angezeigt wird. Und wenn ich das Verhalten öfter brauche, vererbe ich das Fenster einfach. Ich hab noch keine Uni von innen gesehen, und mir das Programmieren selber beigebracht. Meine Kenntnisse sind daher mit Euren nicht vergleichbar, aber das wäre für mich - in diesem speziellen Fall - wiederverwendbarer, flexibler, leicht nachvollziehbarer und lesbarer Code. Wir wissen ja, Code wird öfter gelesen als geschrieben :roll:

Delphi-Quellcode:
unit Foo;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TFoo = class(TForm)
    ButtonSave: TButton;
    ButtonClose: TButton;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure ButtonSaveClick(Sender: TObject);
    procedure ButtonCloseClick(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

implementation

{$R *.dfm}

procedure TFoo.ButtonCloseClick(Sender: TObject);
begin
  // wenn Daten verändert, dann User fragen, ob er speichern möchte
  // und dann schließen
  Close;
end;

procedure TFoo.ButtonSaveClick(Sender: TObject);
begin
  // Daten speichern
end;

procedure TFoo.FormClose(Sender: TObject; var Action: TCloseAction);
begin // Formular freigeben
  Action := caFree;
end;

procedure TFoo.FormCreate(Sender: TObject);
begin // Formulareigenschaften vorbereiten
  BorderIcons := [];
  KeyPreview := true;
end;

procedure TFoo.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin // Schließen des Fensters mit [Alt] + [F4] verhindern
  if ((ssAlt in Shift) and (Key = VK_F4)) then Key := $0000;
end;

end.
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  with TFoo.Create(Application) do ShowModal;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  with TFoo.Create(Application) do Show;
end;

BadenPower 3. Jul 2015 11:44

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von mm1256 (Beitrag 1307555)
Hallo,

es geht wieder zurück zur ursprünglichen Problematik und da hab ich in #7 schon geschrieben

Zitat:

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

Auch wenn Du das in #7 schon geschrieben hast, es wird nicht besser.

Durch das Entziehen aller BorderIcons nimmst Du dem Benutzer, welcher mit der Tastatur arbeitet, unnötigerweise (weil Du es so willst), einfach die Möglichkeit seine gewohnte Weise ein Fenster zu verschieben oder in der Größe zu ändern.

mm1256 3. Jul 2015 12:43

AW: dynamisch erzeugte Forms richtig freigeben
 
Da mag die Frage erlaubt sein: Wie viele Anwender wenden es in der Praxis an, bzw. wissen überhaupt, dass man mit [Alt]+[Leertaste] das Menü öffnen, hier "Verschieben" auswählen, und dann das Fenster mit den Pfeiltasten verschieben kann? Und für den Fall, dass das gewünscht ist, dann reicht eine einzige Zeile Code, ohne dass die übrige Funktionalität/logik verändert werden muss:

Delphi-Quellcode:
BorderIcons := [biSystemMenu];

BadenPower 3. Jul 2015 13:01

AW: dynamisch erzeugte Forms richtig freigeben
 
Zitat:

Zitat von mm1256 (Beitrag 1307559)
Und für den Fall, dass das gewünscht ist, dann reicht eine einzige Zeile Code, ohne dass die übrige Funktionalität/logik verändert werden muss:

Delphi-Quellcode:
BorderIcons := [biSystemMenu];

Und schon hast Du wieder Dein [X] und den Menueintrag "Fenster schließen" über welche Dein Fenster geschlossen werden könnte.


Zitat:

Zitat von mm1256 (Beitrag 1307559)
Da mag die Frage erlaubt sein: Wie viele Anwender wenden es in der Praxis an, bzw. wissen überhaupt, dass man mit [Alt]+[Leertaste] das Menü öffnen, hier "Verschieben" auswählen, und dann das Fenster mit den Pfeiltasten verschieben kann?

Ausserdem geht es ja nicht nur um die Tastaturbedienung.

Wenn Du biSystemMenu nicht setzt, dann hast Du niemals die Icons für Minimieren Maximieren und Hilfe und natürlich auch kein ProgrammIcon.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:29 Uhr.

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