Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Form1 aus Form2 schluießen (https://www.delphipraxis.net/130248-form1-aus-form2-schluiessen.html)

BAMatze 5. Mär 2009 13:29


Form1 aus Form2 schluießen
 
Hallo nochmal,

hab ein weiteres Problem über welchem ich sitze, wo ich dachte, eigentlich ziemlich trivial, aber ist nicht so.

ersteinmal zur Erklärung der Programmaufbau:

-----------|--------------------Form1-------------------|--------------> // dient nur der Überwachung
| |
-----------|--------Thread---------|---------> // Arbeitsthread
| |
----------Form2---------> // Bedienoberfläche

Also hoffe mit dieser kleinen Grafik kann ich die jetzt folgenden Worte etwas anschaulischer darstellen. Ich möchte, dass sich mein Programm SAUBER schließt, wenn der Bediener die Form2 beendet. Ich habe versucht, dies mittels eines Events zu tun, was allerdings zu reihenweisen Fehlermeldungen führt. Bin jetzt auf dem Stand, dass anscheinend meine Art, d.h. so wie ich die Events derzeit verwende zwar funktionieren (es wird realisiert, dass die Form2 geschlossen wird) aber nachdem in der Form1 dieses realisiert wird:

Delphi-Quellcode:
procedure TForm1.Beenden; // Procedure, in die beim Auftreten des Events gesprungen wird
begin
  close;
end; <-- hier springt er anscheinend zurück in die Eventfunktion in Form2, obwohl sie geschlossen ist
scheint sie auf die Form2 nocheinmal zugreifen zu wollen, was nicht geht, da die Form2 schon geschlossen ist. Das Event wird bei mir wie folgt in der Form2 ausgelöst:

Delphi-Quellcode:
 
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if assigned(Schliessevent) then Schliessevent;
end;
Kann mir jemand sagen, wie ich dies eventuell abändern kann, damit sich das Programm vollständig schließt? oder hat jemand eventuell eine gängigere Methode, wie ich in z.B. meinem Thread überprüfen kann, ob die Form2 noch existiert oder schon geschlossen wurde?

Vielen Dank
BAMatze

Edit1: Die grafik wird leider nicht so dargestellt, wie ich mir das dachte. Im Endeffekt ist Form1 der Hauptthread, in dem der Arbeitsthread erzeugt wird und in diesem wird die Form2 erzeugt.

jaenicke 5. Mär 2009 13:37

Re: Form1 aus Form2 schluießen
 
Wenn du auf visuelle Elemente wie ein Formular aus dem Thread heraus zugreifst, dann musst du dich nicht wundern, wenn es Probleme gibt. Derlei Zugriffe müssen generell synchronisiert und damit im Kontext des Hauptthreads ausgeführt werden.

Wie genau erzeugst du da Form2? Tatsächlich direkt im Thread ohne Synchronisierung?

Wenn Form2 beim Schließen auch aus dem Speicher entfernt werden soll, dann kannst du in OnClose Action auf caFree setzen.

BAMatze 5. Mär 2009 13:42

Re: Form1 aus Form2 schluießen
 
Also der Thread erzeug nicht wirklich die Form2, die Form2 wird mehr oder weniger nur aktiviert im Thread. Die Form2 ist ganz normal über Datei>Neu in das Projekt eingearbeitet worden, damit die Benutzeroberfläche ordentlich erstellt werden konnte.

Edit1: Denke mal ein eventuell anderes Konzept müsste hier verwendet werden, als das was ich versucht hab. Vieleicht hat ja jemand schonmal eine ähnliche Programmarchitektur gehabt und diese SAUBER terminiert und kann mir da mal einen Tipp geben.

BAMatze 6. Mär 2009 08:34

Re: Form1 aus Form2 schluießen
 
Schreibe hier nochmal, damit das Thema nochmal aufgenommen wird. Habe mir jetzt den gestrigen Abend um die Ohren geschlagen und leider immer noch keine wirkliche Lösung gefunden.

bisher versucht: 1.) Event in Form2 sagt der Form1, dass sie geschlossen wird. Problem Procedure in Form1 springt anscheinend zurück in Form2 und dies erzeugt eine Exception.
2.) Form1 aus Form2 schließen und im onClose-Ereignis der Form1 versuchen alles zu schließen, leider auch nur Exceptions.
Hab diese beiden Methoden in unzähligen Varianten versucht und leider keinen Erfolg gehabt.

Hoffe jemand hat eine gängige Methode, mit der ich das Problem lösen kann.

Vielen Dank
BAMatze

ChrisE 6. Mär 2009 08:49

Re: Form1 aus Form2 schluießen
 
Zitat:

Zitat von BAMatze
bisher versucht: 1.) Event in Form2 sagt der Form1, dass sie geschlossen wird. Problem Procedure in Form1 springt anscheinend zurück in Form2 und dies erzeugt eine Exception.
2.) Form1 aus Form2 schließen und im onClose-Ereignis der Form1 versuchen alles zu schließen, leider auch nur Exceptions.
Hab diese beiden Methoden in unzähligen Varianten versucht und leider keinen Erfolg gehabt.

Hoffe jemand hat eine gängige Methode, mit der ich das Problem lösen kann.

Vielen Dank
BAMatze

Versuch mal folgendes:

In der OnClose von Form2
Delphi-Quellcode:
  PostMessage(Application.MainForm.Handle, WM_CLOSE, 0, 0);
Sollte funktionieren.

Gruß, Chris

BAMatze 6. Mär 2009 09:23

Re: Form1 aus Form2 schluießen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Versuch mal folgendes:

In der OnClose von Form2
Delphi-Quellcode:
  PostMessage(Application.MainForm.Handle, WM_CLOSE, 0, 0);
Sollte funktionieren.

Gruß, Chris[/quote]

bekomme ich leider auch Fehlermeldungen, aber ich denke mal ich stelle euch einfach mal das Projekt jetzt zur Verfügung, da macht sich die Fehlersuche vieleicht einfacher.

Edit 1: Hinweise zur Verbesserung der Programmiertechnik werden auch angenommen, da ich ja immer noch in der Anfangslernphase bin und mich mit der Programmiersprache Delphi erst seit gut 4Monaten auseinander setze.

Edit 2: Ich weiß es gibt einen Fehler, beim schreiben auf die Datei. Diesen Fehler kann ich beheben, wenn das TProtokoll richtig geschlossen wird. Um diesen Fehler geht es mir auch nicht, wenn man diese Schreib-procedure auskommentiert, dann bleibt ein Fehler:
Erste Gelegenheit für Exception bei $7C812AEB. Exception-Klasse EOSError mit Meldung 'Systemfehler. Code: 1400.
Ungültiges Fensterhandle'. Prozess Proj_EFPI.exe (2728)

BAMatze 6. Mär 2009 09:54

Re: Form1 aus Form2 schluießen
 
Ok kann schonmal den Fehler eingränzen, das Fenster-Handel ist ungültig und hab auch schon einige Varianten danach getestet.

getestet:

Delphi-Quellcode:
  PostMessage(Application.Form1.Handle, WM_CLOSE, 0, 0); // <--- diese Form gibt Fehlermeldung beim Compilieren
  PostMessage(Application.MainForm.Handle, WM_CLOSE, 0, 0); // <--- compilierbar aber falsches Handle
  PostMessage(Form1.Handle, WM_CLOSE, 0, 0); // <--- compilierbar aber falsches Handle
sieht jemand den Fehler?

ChrisE 6. Mär 2009 09:58

Re: Form1 aus Form2 schluießen
 
Hallo,

also ich habe mir das mal kurz angeschaut. Und jaenicke war eigentlich schon dabei dich in die richtige Richtung zu lenken.

In dem Execute deines UnterThreads rufst du Form2.ShowModal auf -> es befindet sich somit im Kontext des Threads. Das macht irgendwie schon Probleme.

Ich bin jetzt nicht ganz dahinter gekommen, warum du es so gelöst hast. Ich will jetzt nicht das ganze auflösen in Probleme aber generell gilt erstmal was jaenicke geschrieben hat: Aus Threads heraus solltest du nicht ohne weiteres auf visuelle Elemente zugreifen. Das sollte dem Hauptthread überlassen werden. Auch wenn du den Thread eine Methode ausführen läßt, die einem Formular gehört wird die Methode im Kontext des Threads ausgeführt. Das also irgendwie trennen bzw. per Syncronized aufrufen.

Dein Problem mit dem Schliessen des Forms dürfte sich beheben lassen, indem du den Thread arbeiten läßt und den Thread kurz vor ende eine Nachricht an das Hauptformular schicken läßt. Dieses Reagiert dann entsprechend darauf und versteckt sich und öffnet das Form2. Dann brauchst du nicht mal das PostMessage mit WM_CLOSE in Form2 an das MainForm zu senden.

Sieht dann ungefährt so aus:
Delphi-Quellcode:
unit ThreadUnit;
//...
procedure THUnterthread.Execute;
begin
  Protokoll.Protokolleingang('Unterthread', 'Execute-Fkt');
  ControlerBoard := TControlerBoard.create;
  ControlerBoard.Fehlerevent_ausloesen := Fehler_verifizieren;
  ControlerBoard.Initialising;
  V_Tische := TV_Tische.create;
  V_Tische.Fehlerevent_ausloesen := Fehler_verifizieren;
  V_Tische.Initialising;
  P_Tisch := TP_Tisch.create;
  P_Tisch.Fehlerevent_ausloesen := Fehler_verifizieren;
  P_Tisch.Initialising;
  Fehler_verifizieren(0);
//  Form1.visible := false;
//  Form2.ShowModal;
  Protokoll.Protokollausgang('Unterthread', 'Execute-Fkt');
  PostMessage(Form1.Handle, WM_MACH_WEITER, 0, 0);
end;
//...


unit LoaderUnit;
//...
const
  WM_MACH_WEITER = WM_USER +1;
//...
type
  TForm1 = class(TForm)
  //...
  private
    procedure WMMachWeiter(var MSG: TMessage);message WM_MACH_WEITER;
  //...
  end;

procedure TForm1.WMMachWeiter(Sender: TObject);
begin
  Self.Visible := FALSE;
  Form2.ShowModal;
  // wenn es geschlossen wird alles beenden
  Self.Close;
end;
Ich hoffe, das bringt dich weiter.

Aber wie gesagt, es ging erstmal nur darum das Problem zu lösen mit dem schliessen. Aber es ist an sich immer noch etwas merktwürdig mit dem Thread und so. Nur so als Info.

Gruß, Chris

BAMatze 6. Mär 2009 10:18

Re: Form1 aus Form2 schluießen
 
Das hört sich schonmal gut an. Löse ich dann mit der Postmessage aus der Form2-onClose-procedure das schließen der Form1 aus, ohne dass es zu einer Exception kommt?

Edit 1: Frage hat sich geklärt, hab dein Kommentar ebend erst gelesen. "Wer lesen kann ist klar im Vorteil" :lol:

BAMatze 6. Mär 2009 10:29

Re: Form1 aus Form2 schluießen
 
Dickes Danke an Chris mit dieser Vorgehensweise ist es wirklich einwandfrei gelöst.

Hab nur mal eine Bitte, weil ich ja noch viel lernen muss in Delphi, kannst du mir mal das mit der Postmessage erklären? Also nicht, was der Computer dabei macht, wenn der Befehl aufgerufen wird, sondern eher:

was bedeutet:
Delphi-Quellcode:
  M_MACH_WEITER = WM_USER +1;
verstehe das WM_User+1 nicht genau. Und wie wirken diese Konstante mit der Procedure zusammen?

Vielen Dank
BAMatze

jaenicke 6. Mär 2009 10:37

Re: Form1 aus Form2 schluießen
 
Es gibt einen Bereich mit Konstanten für Botschaften des Systems. Diese darf man natürlich nicht selbst nutzen, das wäre dann ja vielleicht z.B. der selbe Wert wie WM_PAINT. Deshalb gibt es die Grenze WM_USER, ab diesem Wert kann man eigene Konstanten definieren für die Botschaften.

Deshalb zählt man zu diesem ersten möglichen Wert noch etwas dazu um einen gültigen Konstantenwert für die eigenen Botschaften zu bekommen. ;-)

Wichtig:
Botschaften zwischen WM_USER und WM_APP dürfen nur innerhalb der Anwendung benutzt werden!
Sollen die Botschaften systemweit verwendet werden, dann müssen diese oberhalb von WM_APP liegen.

Mehr dazu findet sich in der Dokumentation von Microsoft:
http://msdn.microsoft.com/en-us/library/ms644931.aspx

ChrisE 6. Mär 2009 10:42

Re: Form1 aus Form2 schluießen
 
Also erstmal: Kein Problem. Hab gerne geholfen :thumb:

Zum Nächsten mit den Messages:

Aus der Hilfe:
Zitat:

The WM_USER constant is used by applications to help define private messages for use by private window classes, usually of the form WM_USER+X, where X is an integer value.
Es Basiert also darauf, dass es Nummern sind. Es gibt vergebene Nummern (unterhalb von WM_USER) wie z.B. WM_CLOSE. Diese dürfen halt nicht verwendet werden.
Du erzeugst dir als eine Konstante für eine Message im Bereich WM_USER +X und unterhalb von WM_APP um eigene Nachrichten zu verarbeiten - also solche die es noch nicht gibt.

Um jetzt auf so eine Nachricht reagieren zu können muss man ein paar Regeln einhalten. Ich denke aber, da gibt es weit aus qualifiziertere Leute hier die das erklären könnten. Im groben kann ich dir aber erklären was ich gemacht habe.

Die Methode
Delphi-Quellcode:
procedure WMMachJetztWeiter(var Msg: TMessage);
selber dürfte ja klar sein. Durch das dahinter schreiben von
Delphi-Quellcode:
message WM_MACH_JETZT_WEITER;
erkläre ich, dass diese Methode ausgelöst werden soll, wenn eine Nachricht mit dieser Nummer - WM_MACH_JETZT_WEITER - kommt.

Und das ist alles.

Und den Aufwand betreiben wir quasi nur, um den Thread von dem MainThread zu entkoppeln :-)

Gruß, Chris

BAMatze 6. Mär 2009 10:53

Re: Form1 aus Form2 schluießen
 
Danke an Chris und jaenicke für die Erklärung

BAMatze 9. Mär 2009 09:53

Re: Form1 aus Form2 schluießen
 
Hallo hier nochmal eine kleine Frage zu meinem Verständnis zu den Windows-Messages und ihrem Gültigkeitsbereich.

Wenn ich in einer Unit eine:
Delphi-Quellcode:
  const M_MACH_WEITER = WM_USER +1;
definiere, ist diese rein für diese Form/Unit und nicht für das gesamte Projekt gültig, so dass ich für eine andere Form/Unit diese WM_User+1-Message nochmal benutzen könnte oder?

jaenicke 9. Mär 2009 09:58

Re: Form1 aus Form2 schluießen
 
Du versendest diese Botschaft als Windowsbotschaft. D.h. es darf nicht passieren, dass zwei verschiedene Nachrichten mit dem selben Wert an die selbe Adresse gehen. Denn für den Empfänger wäre diese ja dann anhand des Wertes nicht mehr zu unterscheiden.

Deshalb ist es keine gute Idee mehrere Botschaften mit dem selben Wert zu benutzen. Am besten gib immer verschiedene Werte, dann kann auch nichts durcheinander gehen.

ChrisE 9. Mär 2009 10:36

Re: Form1 aus Form2 schluießen
 
Hallo,

sehe ich ähnlich wie jaenicke allerdings mit einer Unterscheidung. Da bei jedem Post/SendMessage eine Adresse angegeben werden muss - der Handle des Fensters das diese Botschaft verarbeiten soll - kann man durchaus ein und die selbe Nummer vergeben für unterschiedliches verhalten. Schliesslich sind die Aufgaben oftmals sehr Fensterbezogen, also doch sehr nah an dem Fenster für das die Nachricht ist.

Da man aber eben in der Programmierung nie weiß was noch kommt sollte man vielleicht schon den Weg der Eindeutigkeit gehen :-) Dann sollten diese aber auch global in einer Deklarationsunit liegen. Sonst wird die Suche nach diesen Variablen um die entsprechend nächste Konstante anzulegen doch etwas aufwendig :-)

Gruß, Chris

Dipl Phys Ernst Winter 23. Mai 2009 16:02

Re: Form1 aus Form2 schluießen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Versuchts doch einmal ganz einfach:
Das Hauptformular exportiert eine logische Variable
Delphi-Quellcode:
isAborted: boolean;
Form2 wird geöffnet mit
Delphi-Quellcode:
procedure TForm1.btnForm2ShowClick(Sender: TObject);
begin
  Form2.ShowModal;
  if isAborted then Close
end;
Zum Schließen von Form2 gibt es die Buttons btnClose und btnAbort
Delphi-Quellcode:
procedure TForm2.btnCloseClick(Sender: TObject);    // Form2 schließen
begin
  isAborted:= false; Close
end;

procedure TForm2.btnAbortClick(Sender: TObject);            // Programm beenden
begin
  isAborted:= true; Close
end;
die dem Hauptprogramm mit isAborted übermitteln, ob das Programm beendet werden soll oder nicht.

Mit ModalResult kann man's eleganter ausdrücken, es ist dann aber nicht mehr so einfach zu überblicken.


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:51 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