Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Mehrere Formulare schließen (mit Sicherheitsfrage) (https://www.delphipraxis.net/184337-mehrere-formulare-schliessen-mit-sicherheitsfrage.html)

ndy 18. Mär 2015 16:19

Mehrere Formulare schließen (mit Sicherheitsfrage)
 
Hallo,

folgendes wird wohl eher eine Verständnisfrage für mich persönlich. Eventuell ist sie sogar so trivial, dass ich hier gleich gesteinigt werde.

Ich bin ein Laie in Sachen Delphi-Programmierung und soll gerade mit Delphi XE2 ein bestehendes Programm "erweitern". Aus Gründen der Übersicht habe ich dazu eine neue Form erstellt (die Hauptform ist mit Labels, Edits und Images für meinen Geschmack schon ziemlich überladen). Das Programm soll auf beiden Formularen sicher beendet werden können. Im Hauptformular (das bereits existierte) wird das wohl so realisiert:

Delphi-Quellcode:
Function TFrm_Form1.Beenden():Boolean;
begin
  if Application.MessageBox('Wirklich beenden?','Berechnung',52) = 6 then
 begin
 ...
 Application.Terminate;
 result:=True;
 end else result:=false;
end; //TFrm_Form1.Beenden

...

procedure TFrm_Form1.Beenden1Click(Sender: TObject);
begin
  Beenden;
end;

...

procedure TFrm_Form1.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
CanClose:=Beenden;
end;
Mit der Prozedur "Beenden1Click" wird das Beenden mittels Button abgearbeitet. Ich gehe davon aus, dass Beenden mittels Rechtsklick in der Symbolleiste, Alt+F4, [X]-Button etc. über die FormCloseQuery-Prozedur abgearbeitet wird.

Nun gleich zu einer ersten Zwischenfrage zum persönlichen Verständnis:
(1) Wofür stehen die Konstanten bei Application.Messagebox? (52 und 6)
Hab auf die schnelle nur diese Übersicht gefunden. Die ist wohl aber etwas veraltet, da ich die Konstanten unter MessageBox nicht wiedergefunden habe.
Ich tippe jetzt einfach mal auf 52 = /!\ und 6 = MB_OK

Weiter im Text: Den Wechsel zwischen den Formularen realisiere ich wie folgt:

Delphi-Quellcode:
procedure TFrm_Form1.B_WechselZuForm2Click(Sender: TObject);
begin
  Frm_Form2.Top := Frm_Form1.Top;
  Frm_Form2.Left := Frm_Form1.Left;
  Frm_Form2.Height := Frm_Form1.Height;
  Frm_Form2.Width := Frm_Form1.Width;
  Frm_Form2.Show;
  Frm_Form1.Hide;
end;
Der Wechsel von Form2 zu Form1 ist analog aufgebaut.

Jetzt zum eigentlichen Problem: Das schließen dieser zweiten Form. Anfangs habe ich gedacht es würde reichen, wenn ich auf die Beenden-Prozedur von Form1 verweise, also quasi:

Delphi-Quellcode:
//////////Beenden via "Beenden"-Button
procedure TFrm_Form2.B_Form2BeendenClick(Sender: TObject);
begin
  Frm_Form1.Beenden;
end;

...

procedure TFrm_Form2.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
CanClose:=Frm_Form1.Beenden;
end;
Das würde für das Beenden über den entsprechenden Button auch funktionieren. Allerdings wird damit nicht das Beenden via Rechtsklick, Alt+F4, [X]-Button usw. abgefangen. Vermutlich wird das FormCloseQuery garnicht angelaufen (habe ich mittels Breakpoints untersucht). Hab gelesen, dass das wohl nur bei modalem Aufruf ginge oder so. Da ich die Formulare aber nicht schließen möchte wenn ich das jeweils andere Formular anzeigen will (in die Edits eingetragene/geänderte Werte sollen nicht verloren gehen), was ich wohl müsste wenn ich mit ShowModal arbeite, hab ich den Formularwechsel via Show und Hide realisiert (siehe oben).
Auch eine eigene Funktion Beenden für Form2 (im Prinzip exakt die gleiche wie für Form1) hat das Problem nicht behoben.

Im Internet bin ich dann auf diese Möglichkeit gestoßen so ziemlich alle Varianten des Programm beendens (außer via Button) abzufangen. Der Rohquelltext sieht so aus:

Delphi-Quellcode:
procedure WMSysCommand(var MSG: TWMSysCommand); message WM_SYSCOMMAND;

...

procedure TForm1.WMSYSCommand(var MSG: TWMSysCommand);
begin
  if MSG.CmdType = SC_CLOSE then
  begin
     //Closing from border icon
  end;
  inherited;
end;
Nun habe ich mir Gedanken gemacht, wie ich da noch die Abfrage (Wirklich Beenden?) dazwischenbekomme und auf ein Nein als Antwort reagiere. Dabei bin ich auf folgende Lösungen gestoßen:

Delphi-Quellcode:
Function TFrm_Form2.Beenden():Boolean;
begin
  if Application.MessageBox('Wirklich beenden?','Berechnung',52) = 6 then
 begin
...
 Application.Terminate;
 result:=True;
 end else result:=false;
end;

...

procedure TFrm_Form2.WMSysCommand(var MSG: TWMSysCommand);
begin
  if MSG.CmdType = SC_CLOSE then
  begin
    if Frm_Form2.Beenden = False then
    begin
      MSG.Result := 0;
      Exit;
    //  MSG.CmdType := SC_DEFAULT;
    end;
  end;
  inherited;
end;
Das letzte Stück Quelltext durchschaue ich noch nicht ganz, darum jetzt zur eigentlichen Thematik:
Als mögliche Werte für Msg:CmdType bin ich unter anderem auf SC_DEFAULT gestoßen (leider keine Ahnung mehr wo). Das war auch mein erster Lösungsansatz (siehe auskommentierte Zeile), der auch (scheinbar?) funktioniert hat. Jedoch bin ich mir nicht sicher, ob man MSG.CmdType einfach so einen neuen Wert zuweisen kann/sollte und ob SC_DEFAULT nicht vielleicht auch irgendwas anderes "auslöscht".
Die zweite Möglichkeit
(
MSG.Result := 0;
Exit;
)
habe ich zu einer anderen Thematik gefunden (irgendwas von wegen Maximieren, Minimieren verhindern oder so).
Nach ein wenig rumprobieren habe ich gemerkt, dass Exit allein auch funktioniert.

Nun (endlich :D) zu meinen Hauptfragen:

(2) Möglichkeit 1: Richte ich mit der Zuweisung von SC_DEFAULT ungewollt und unbewussten Schaden an? Oder anders gefragt: Würde das so funktionieren?

(3) Möglichkeit 2: Wenn Exit allein funktioniert, wozu dann MSG.Result := 0;? Und was bedeutet das?


Vielen Dank im Voraus! ;)


PS: Wie eingangs erwähnt bin ich ein absoluter Laie auf dem Gebiet Delphi-Programmierung (eigentlich auch allgemein auf dem Gebiet der Programmierung). Die einzigen Kenntnisse die ich habe liegen schon ein paar Jährchen zurück und waren recht simpel gehalten (ein oder ein halbes Jahr Informatikunterricht). Deshalb hab ich für mich persönlich bei der Fragestellung einfach beim Urschleim angefangen. Zum einen in der Hoffnung auf grobe Fehler hingewiesen zu werden :wink: und zum anderen um Fragen so gut es geht vorzubeugen.
Bei Fehlern bei der Fragestellung und Themeneröffnung bitte ich mich darauf hinzuweisen und sie mir nachzusehen :wink:

Der schöne Günther 18. Mär 2015 16:38

AW: Mehrere Formulare schließen (mit Sicherheitsfrage)
 
Hallo und Willkommen in den Heiligen Hallen des Wissens und des Wahnsinns. :drunken:

Zitat:

Zitat von ndy (Beitrag 1293958)
(1) Wofür stehen die Konstanten bei Application.Messagebox? (52 und 6)
Hab auf die schnelle nur diese Übersicht gefunden. Die ist wohl aber etwas veraltet

Die "magischen Nummern" wie 52 und 6 sind ein absolutes Verbrechen das dich jetzt schon viel unnötige Zeit gekostet hat! Das einzige was dir hier vielleicht noch helfen kann ist die Dokumentation zu den Befehlen: Die Hilfe versteckt sich hinter der F1-Taste und kann hier wirklich weiterhelfen:
Zu TApplication.MessageBox(..) findest du die Werte die sich als dritter Parameter ("Flags") angeben lassen und was man zurückbekommt: Es sind Konstanten aus der Unit "WinApi.Windows".

Die "52" steht für "Schaltfläche ja+nein und bitte ein Ausrufezeiche-Icon". Kann man das aus einer "52" herauslesen? Nein. Deshalb sollte man lieber die vorgefertigten Werte "MB_YESNO" und "MB_ICONEXCLAMATION" dafür verwenden.

Vernünftig geschrieben sähe die Zeile also so aus:
Delphi-Quellcode:
if Application.MessageBox('Wirklich beenden?', 'Berechnung', MB_YESNO or MB_ICONEXCLAMATION) = IDYES then [...]
oder noch besser:
Delphi-Quellcode:
const
   flags: DWORD = MB_YESNO or MB_ICONEXCLAMATION;
begin
   if Application.MessageBox('Wirklich beenden?', 'Berechnung', flags) = IDYES then [...]

Auch: Die offizielle Doku ist nicht perfekt, aber besser als sie auf den ersten Blick scheint. Grade bei Delphi sind die meisten Internet-Treffer die du finden wirst gerne 10-15 Jahre alt. Ich würde mich davor hüten.

Zu den weiteren Punkten bekommst du mit Sicherheit noch mehr Input

p80286 18. Mär 2015 17:53

AW: Mehrere Formulare schließen (mit Sicherheitsfrage)
 
von mir leider keine Antwort zu den eigentlichen Fragen sondern
Bitte nie so etwas
Delphi-Quellcode:
if Frm_Form2.Beenden = False then
nutzen, sondern immer
Delphi-Quellcode:
if not(Frm_Form2.Beenden) then
Ich vermute eine Modifizierung ist keine so gute Idee.

Gruß
K-H

BadenPower 18. Mär 2015 19:39

AW: Mehrere Formulare schließen (mit Sicherheitsfrage)
 
Zitat:

Zitat von p80286 (Beitrag 1293968)
Bitte nie so etwas
Delphi-Quellcode:
if Frm_Form2.Beenden = False then
nutzen, sondern immer
Delphi-Quellcode:
if not(Frm_Form2.Beenden) then

Weshalb?
Da sehe ich keinen Sinn, warum man nicht auch Variante 1 benutzen soll, wenn man dies bevorzugt.

Sir Rufo 18. Mär 2015 20:35

AW: Mehrere Formulare schließen (mit Sicherheitsfrage)
 
Zitat:

Zitat von BadenPower (Beitrag 1293978)
Zitat:

Zitat von p80286 (Beitrag 1293968)
Bitte nie so etwas
Delphi-Quellcode:
if Frm_Form2.Beenden = False then
nutzen, sondern immer
Delphi-Quellcode:
if not(Frm_Form2.Beenden) then

Weshalb?
Da sehe ich keinen Sinn, warum man nicht auch Variante 1 benutzen soll, wenn man dies bevorzugt.

Mal abgesehen davon das die Benutzung der globalen Form-Variablen in der Form-Klasse ein klassisches Eigentor werden kann und somit statt
Delphi-Quellcode:
Frn_Form2.Beenden
immer
Delphi-Quellcode:
Self.Beenden
oder schlicht und ergreifend
Delphi-Quellcode:
Beenden
benutzt werden sollte, ist gegen das Verwenden von
Delphi-Quellcode:
if Self.Beenden = False then
erst mal nichts einzuwenden.

Doof ist nur, dass diese Leute, die sich das angewöhnen eben dann an anderer Stelle analog auch
Delphi-Quellcode:
if Self.Beenden = True then
schreiben. Und dort liegen dann wieder potentielle Fehlerquellen (ist in diesem Forum schon bis zum Erbrechen durchgekaut worden und bei Interesse bitte die Forensuche benutzen und bitte hier nicht wieder aufwärmen).

Generell würde ich die Methode sogar umbenennen um zu verdeutlichen, dass hier in der Funktion noch eine Entscheidung getroffen wird:
Delphi-Quellcode:
if not Self.ShouldClose
then
  ...
// oder anders herum
if Self.ShouldClose
then
  ...
Schon liest sich das wie Prosa ... und darum geht es bei der Programmierung auch: Robuster und selbsterklärender Code

Dejan Vu 19. Mär 2015 04:00

AW: Mehrere Formulare schließen (mit Sicherheitsfrage)
 
Zitat:

Zitat von Sir Rufo (Beitrag 1293982)
...ist gegen das Verwenden von
Delphi-Quellcode:
if Self.Beenden = False then
erst mal nichts einzuwenden.

Doch: Schlechter lesbar, da keine Prosa. Es heißt doch 'Wenn ich nicht beenden will' und nicht 'Wenn 'Beenden' falsch ist'.

bcvs 19. Mär 2015 06:58

AW: Mehrere Formulare schließen (mit Sicherheitsfrage)
 
Zitat:

Zitat von ndy (Beitrag 1293958)
Aus Gründen der Übersicht habe ich dazu eine neue Form erstellt (die Hauptform ist mit Labels, Edits und Images für meinen Geschmack schon ziemlich überladen). Das Programm soll auf beiden Formularen sicher beendet werden können.

Du willst also eine mit Controls überladene Form für den Benutzer entzerren. Das ist schon mal ein guter Gedanke.
Ich würde das allerdings nicht über eine zweite Form lösen, die dann eifach über die erste Form drübergeblendet wird. Pack die Controls auf verschiedene Seiten eines TPageControl. Wenn du willst, kann man die Tab-Reiter mit
Delphi-Quellcode:
TabVisible:=false
unsichtbar machen. Umschalten zwischen den Tabs erfolgt dann mit
Delphi-Quellcode:
PageControl.ActivePage:=...
Du hast dann aber programmtechnisch immer noch ein Form, das ganz normal beendet werden kann, sparst dir das Gehampele mit WMSysCommand und die Circular Unit Reference, dass Form1 Form2 kennen muss und umgekehrt.

ndy 19. Mär 2015 09:07

AW: Mehrere Formulare schließen (mit Sicherheitsfrage)
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1293960)
Die "52" steht für "Schaltfläche ja+nein und bitte ein Ausrufezeiche-Icon". Kann man das aus einer "52" herauslesen? Nein. Deshalb sollte man lieber die vorgefertigten Werte "MB_YESNO" und "MB_ICONEXCLAMATION" dafür verwenden.

Vielen Dank!

Sieht auf den ersten Blick wirklich etwas besser aus. Außerdem braucht es nicht viel Fantasie um zu erahnen, dass eine Internetsuche nach "MB_YESNO", "MB_ICONEXCLAMATION" bzw. "MB_OK" vermutlich erfolgreicher / effizienter wäre als nach "52" und "6", womit sich das Problem wohl von selbst gelöst hätte.

Zitat:

Zitat von p80286 (Beitrag 1293968)
Bitte nie so etwas
Delphi-Quellcode:
if Frm_Form2.Beenden = False then
nutzen, sondern immer
Delphi-Quellcode:
if not(Frm_Form2.Beenden) then
Ich vermute eine Modifizierung ist keine so gute Idee.

Zitat:

Zitat von Sir Rufo (Beitrag 1293982)
statt
Delphi-Quellcode:
Frn_Form2.Beenden
immer
Delphi-Quellcode:
Self.Beenden

Alles klar, danke ;)

Ich vermute
Delphi-Quellcode:
if Frm_Form2.Beenden = False then
läuft unter der Rubrik "von hinten durch die Brust und durchs Auge ins Herz", also unnötig kompliziert. Liest sich jetzt verständlicher. Wobei das mit "self" im allerersten Moment etwas ungewohnt war. Klingt aber auch sinnvoll.


Zitat:

Zitat von bcvs (Beitrag 1293998)
Ich würde das allerdings nicht über eine zweite Form lösen, die dann eifach über die erste Form drübergeblendet wird. Pack die Controls auf verschiedene Seiten eines TPageControl. Wenn du willst, kann man die Tab-Reiter mit
Delphi-Quellcode:
TabVisible:=false
unsichtbar machen. Umschalten zwischen den Tabs erfolgt dann mit
Delphi-Quellcode:
PageControl.ActivePage:=...
Du hast dann aber programmtechnisch immer noch ein Form, das ganz normal beendet werden kann, sparst dir das Gehampele mit WMSysCommand und die Circular Unit Reference, dass Form1 Form2 kennen muss und umgekehrt.

Danke, das ist natürlich auch eine Möglichkeit die ich erstmal komplett nicht auf dem Schirm hatte. Allerdings funktioniert es ja grundsätzlich erstmal so, wie ich es realisiert habe. Mich würde nur interessieren, was da genau dahinter steckt ;)

Sir Rufo 19. Mär 2015 09:46

AW: Mehrere Formulare schließen (mit Sicherheitsfrage)
 
Zitat:

Zitat von ndy (Beitrag 1294019)
Zitat:

Zitat von Sir Rufo (Beitrag 1293982)
statt
Delphi-Quellcode:
Frn_Form2.Beenden
immer
Delphi-Quellcode:
Self.Beenden

Wobei das mit "self" im allerersten Moment etwas ungewohnt war. Klingt aber auch sinnvoll.

Es wird doch immer das ausgeführt, was man schreibt und nicht das was man sich beim Schreiben gedacht hat (die MindRead-API ist noch lange nicht fertig).

So und was hat man geschrieben, wenn man das hier schreibt:
Delphi-Quellcode:
TFoo = class
  procedure Bar();
  procedure FooBar();
end;

var
  Foo : TFoo;

procedure TFoo.Bar;
begin
  Foo.FooBar();
end;

procedure TFoo.FooBar;
begin
end;
Man hat geschrieben, dass beim Aufruf der Methode
Delphi-Quellcode:
TFoo.Bar
die Methode
Delphi-Quellcode:
TFoo.FooBar
im Kontext der Instanz ausgeführt werden soll, deren Referenz in der Variablen
Delphi-Quellcode:
Foo
hinterlegt ist.

Und jetzt:
Delphi-Quellcode:
procedure TFoo.Bar;
begin
  {Self.}FooBar();
end;
Man hat geschrieben, dass beim Aufruf der Methode
Delphi-Quellcode:
TFoo.Bar
die Methode
Delphi-Quellcode:
TFoo.FooBar
im eigenen (
Delphi-Quellcode:
Self
) Instanz-Kontext ausgeführt werden soll.

Gibt es nur eine Instanz von der Klasse und wird die Referenz auf diese Instanz auch zuverlässig in der Variablen
Delphi-Quellcode:
Foo: TFoo
gespeichert, dann funktionieren beide Ansätze.

Gibt es mehr als eine Instanz, dann habe ich die Torte im Auge.

BadenPower 19. Mär 2015 10:02

AW: Mehrere Formulare schließen (mit Sicherheitsfrage)
 
Zitat:

Zitat von Sir Rufo (Beitrag 1293982)
Doof ist nur, dass diese Leute, die sich das angewöhnen eben dann an anderer Stelle analog auch
Delphi-Quellcode:
if Self.Beenden = True then
schreiben. Und dort liegen dann wieder potentielle Fehlerquellen (ist in diesem Forum schon bis zum Erbrechen durchgekaut worden und bei Interesse bitte die Forensuche benutzen und bitte hier nicht wieder aufwärmen).

Ich wollte hier ja keine Grundsatzdebatte auslösen, sondern lediglich darlegen, dass es grundsätzlich ersteinmal nicht falsch ist, das so zu machen.

Dass die Prüfung auf "true" eine Fehlerquelle sein kann, wenn man nicht weis was man da prüft, ist auch richtig.

Aber es kann auch vorkommen, dass man bewußt auf die Konstante "True"
Delphi-Quellcode:
if (RückgabeWert() = true) then
oder "False"
Delphi-Quellcode:
if (RückgabeWert() = false) then
prüfen MUSS, damit man das richtige Ergebnis erhält und nicht auf irgendetwas was Wahr
Delphi-Quellcode:
if (RückgabeWert()) then
oder Falsch
Delphi-Quellcode:
if not (RückgabeWert()) then
ERGIBT.

Und dies wird meist in den ganzen Diskussionen vergessen zu erwähnen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:41 Uhr.
Seite 1 von 2  1 2      

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