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/)
-   -   Verrückte Eventreihenfolge, wenn Fenster mit ShowModal geöffnet wurde (https://www.delphipraxis.net/194633-verrueckte-eventreihenfolge-wenn-fenster-mit-showmodal-geoeffnet-wurde.html)

freejay 14. Dez 2017 15:22

Verrückte Eventreihenfolge, wenn Fenster mit ShowModal geöffnet wurde
 
Hallo zusammen,

vielleicht muss ich das ja auch einfach nur so hinnehmen, aber vielleicht kann man es auch verstehen und vielleicht macht das auch für irgendwas Sinn:

Ich habe ein Fenster, in dem eine Prozedur (mittels eines ButtonClicks gestartet) über einen längeren Zeitraum läuft. Diese Prozedur ruft dabei regelmäßig Application.ProcessMessages auf, damit man das Fenster trotzdem schließen und damit den Prozess abbrechen kann. Dazu habe ich das Event OnClose des Formulars gefüllt und setze dort ein Flag, dass die lang laufende Prozedur prüft und gegebenenfalls abbricht.

So weit, so simpel.

ABER:

Das funktioniert nur, wenn man das Fenster mit Show aufgerufen hat!

Wenn man das Fenster mit ShowModal aufruft, dann wird - trotz Application.ProcessMessages - das OnClose-Event erst ausgelöst bzw. verarbeitet, wenn der laufende Prozess (das ButtonClick-Event) vollständig durchgelaufen ist!

Da rollen sich mir glatt die Fußnägel auf!

Kann mir das irgendwer begründen/erklären?

PS: Ich habe das mit einem frischen Projekt getestet, bei dem das vom Hauptformular geöffnete zweite Formular nur einen Button und folgenden Code hat:

Delphi-Quellcode:
procedure TfSubWindow.btDoSomethingClick(Sender: TObject);
var
  OldTime: TDateTime;
begin
  OldTime := now;

  while SecondsBetween(Now,OldTime) < 10 do
    Application.ProcessMessages;
end;

procedure TfSubWindow.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Beep;
end;
Das Beep wird erst nach dem END von btDoSomethingClick ausgeführt, falls das Formular mit ShowModal geöffnet wurde...

himitsu 14. Dez 2017 15:39

AW: Verrückte Eventreihenfolge, wenn Fenster mit ShowModal geöffnet wurde
 
ShowModal wartet, bis dein ButtonClick fertig ist und schließt erst dann das Fenster, weil es erst nach Rückkehr den ModalResult auswerten kann, wenn der Code im ShowModal wieder ausgeführt wird.


Wer mit Application.ProcessMessages die Abarbeitung der Messages verschachtelt, der soll sich nicht wundern, wenn da etwas bissl anders arbeitet.

freejay 14. Dez 2017 15:47

AW: Verrückte Eventreihenfolge, wenn Fenster mit ShowModal geöffnet wurde
 
Ich habe mir schon gedacht, dass irgendwer ProcessMessages ankritteln wird... ;-)

Aber wie könnte man denn das "ich will einen laufenden Prozess über einen Cancel-Button abbrechen lassen können" sonst lösen?

Um die Benutzung eines Cancel-Buttons zu erlauben, muss ich doch ProcessMessage verwenden, oder? Auch wenn ich den Prozess in einen anderen Thread stecke, muss ich doch auf das Ende des Threads mit ProcessMessages warten?

Und sobald ProcessMessages ins Spiel kommt, kann man halt auch den CloseButton drücken. Nur verhält sich der dann recht eigenwillig...

Wosi 14. Dez 2017 16:05

AW: Verrückte Eventreihenfolge, wenn Fenster mit ShowModal geöffnet wurde
 
- Lager die langläufige Routine in einen Thread aus
- Halte eine Referenz auf den Thread (Wichtig ist hierbei, dass FreeOnTerminate nicht gesetzt ist)
- Wenn Abbrechen geklickt wird, rufst du Thread.Terminate auf
- In dem Thread prüfst du regelmäßig ob Terminated gesetzt wurde
- Beim Schließen des Fensters rufst du Thread.Free auf. Damit wartest du automatisch bis der Thread auch wirklich fertig ist

stahli 14. Dez 2017 16:08

AW: Verrückte Eventreihenfolge, wenn Fenster mit ShowModal geöffnet wurde
 
Das ist eine Konstellation, auf die die VCL nicht direkt ausgelegt ist.

Schau mal, ob vielleicht OnCloseQuery vorher getriggert wird. Dann könntest Du dort ein Flag setzen und dies für einen vorzeitigen Abbruch der Schleife prüfen.
Ansonsten gibt es vielleicht eine Message, die man noch abfangen kann.
Aber so etwas kann dann auf späteren Delphi-Versionen oder auf verschiedenen Windows-Versionen und -Rechnern schon wieder ganz anders laufen.

Vielleicht kannst Du Dein SubFormular ja auch durch ein Panel ersetzen, das Du einfach in Dein Hauptformular einsetzt.


Grundsätzlich ist sicher sinnvoll, solche längeren Aufgaben in Threads auszulagern. Dazu muss man dann aber auch die konkreten Zuständigkeiten der einzelnen Formulare klären...
ProcessMessages ist immer mit Vorsicht zu genießen.

freejay 14. Dez 2017 16:15

AW: Verrückte Eventreihenfolge, wenn Fenster mit ShowModal geöffnet wurde
 
[/QUOTE]
Zitat:

Zitat von Wosi (Beitrag 1388868)
- Lager die langläufige Routine in einen Thread aus
- Halte eine Referenz auf den Thread (Wichtig ist hierbei, dass FreeOnTerminate nicht gesetzt ist)
- Wenn Abbrechen geklickt wird, rufst du Thread.Terminate auf
- In dem Thread prüfst du regelmäßig ob Terminated gesetzt wurde
- Beim Schließen des Fensters rufst du Thread.Free auf. Damit wartest du automatisch bis der Thread auch wirklich fertig ist

Ok, und wie prüfe ich jetzt im Formular, ob der Thread fertig ist?
Damit ich z.B. Buttons wieder enablen/disablen kann?
Da fällt mir nur ein TimerEvent (nicht sehr elegant) ein oder eine CallbackProzedur, die der Thread anstößt. Hm...

Wosi 14. Dez 2017 16:19

AW: Verrückte Eventreihenfolge, wenn Fenster mit ShowModal geöffnet wurde
 
http://docwiki.embarcadero.com/Libra...ad.OnTerminate

freejay 14. Dez 2017 16:21

AW: Verrückte Eventreihenfolge, wenn Fenster mit ShowModal geöffnet wurde
 
Zitat:

Zitat von stahli (Beitrag 1388869)
Das ist eine Konstellation, auf die die VCL nicht direkt ausgelegt ist.

Schau mal, ob vielleicht OnCloseQuery vorher getriggert wird. Dann könntest Du dort ein Flag setzen und dies für einen vorzeitigen Abbruch der Schleife prüfen.
Ansonsten gibt es vielleicht eine Message, die man noch abfangen kann.
Aber so etwas kann dann auf späteren Delphi-Versionen oder auf verschiedenen Windows-Versionen und -Rechnern schon wieder ganz anders laufen.

Vielleicht kannst Du Dein SubFormular ja auch durch ein Panel ersetzen, das Du einfach in Dein Hauptformular einsetzt.


Grundsätzlich ist sicher sinnvoll, solche längeren Aufgaben in Threads auszulagern. Dazu muss man dann aber auch die konkreten Zuständigkeiten der einzelnen Formulare klären...
ProcessMessages ist immer mit Vorsicht zu genießen.

Nee, OnCloseQuery verhält sich leider genauso - das hatte ich schon ausprobiert. Ich hab das Problem ja auch nur, weil ich das Fenster modal öffnen muss, sonst geht das mit OnClose und OnCloseQuery alles problemlos.

Natürlich ist ProcessMessages irgendwie etwas Getrickse, aber ich finde, dass man in vielen (einfacheren) Fällen damit sehr gut (und problemlos) arbeiten kann, ohne einen großen Overhead für eine andere Lösung basteln zu müssen. Aber in diesem Fall geht's wohl nicht...

freejay 14. Dez 2017 16:23

AW: Verrückte Eventreihenfolge, wenn Fenster mit ShowModal geöffnet wurde
 
Zitat:

Zitat von Wosi (Beitrag 1388872)

Jaaa, vielleicht sollte ich mir doch angewöhnen, sowas immer rein eventbasiert zu lösen. Und nicht mit lustigen "While ThreadNochLäuft ProcessMessages"-Schleifen... ;-)

himitsu 14. Dez 2017 21:29

AW: Verrückte Eventreihenfolge, wenn Fenster mit ShowModal geöffnet wurde
 
Zitat:

Zitat von freejay (Beitrag 1388866)
Aber wie könnte man denn das "ich will einen laufenden Prozess über einen Cancel-Button abbrechen lassen können" sonst lösen?

Genauso wie bei Threads? (Thread.Terminate und IF-Self.Terminated im Thread)

Deine Schleife muß eben auch auf die Beendigung ragieren.
Delphi-Quellcode:
while (SecondsBetween(Now,OldTime) < 10) and (ModalResult = mrNone) do
  Application.ProcessMessages;
Und das gilt nicht nur für dein modales Fenster, sonden auch für die ganze Anwendung.
Delphi-Quellcode:
while (SecondsBetween(Now,OldTime) < 10) and (ModalResult = mrNone) and not Application.Terminated do
  Application.ProcessMessages;
OnClose und OnCloseQuery werden im DoClose aufgerufen.
Buttons mit ModalResult und TForm.Close setzen eben nur den Status "Liebes Fenster, du darfst dich beenden", aber das wird eben nur/erst im ShowModal ausgewertet, wenn man ihm auch die Möglichkeit dazu gibt.


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