Application.ProcessMessages

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 470
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Application.ProcessMessages

Beitrag von Jorg3000 »

Hi!
In einem anderen Beitrag ging es kürzlich darum, während einer langen Programmschleife gelegentlich Application.ProcessMessages() aufzurufen, damit das Programmfenster weiterhin reagiert.

Ein Problem ist dann die Ablauf-Reihenfolge, wenn nämlich der User während einer Schleife ungeduldig auf Buttons klickt, und dann ein ProcessMessages() aus einer Schleife anfängt auf die User-Clicks zu reagieren und andere Abläufe einschiebt.
Wenn's blöd läuft, beeinflussen sich die nun ineinander verschachtelten Abläufe gegenseitig - und wenn's ganz schlecht läuft, blockieren sie sich sogar gegenseitig (Deadlock).

Dies betrifft jedoch nur Fensteranwendungen, und genau darin liegt ein weiteres Problem: Das Application-Objekt ist in Konsolenprogrammen gar nicht verfügbar, weil dann LCL/Forms nicht verfügbar ist.
Somit kann man nicht einfach in jede allgemeine Unit beliebig Application.ProcessMessages() einbauen, wenn die Unit auch in Konsolenprogrammen genutzt werden soll.

Deshalb habe ich mir Folgendes ausgedacht:

Code: Alles auswählen

var
    ProcessMessages_Explicit_Counter: Integer = 0;

procedure ProcessMessages_Explicit();
begin
  {$IFDEF LCL}   // Achtung: existiert nur in fpc, nicht in Delphi
   inc(ProcessMessages_Explicit_Counter);
   try
     Application.ProcessMessages();
   finally
     dec(ProcessMessages_Explicit_Counter);
   end;
  {$ENDIF}
end;
Ich rufe in allen meinen Schleifen nur noch dieses ProcessMessages_Explicit() auf. Durch den Compilerschalter stört es nicht, wenn es keine LCL-Anwendung ist.
Was Wort _Explicit soll verdeutlichen, dass es keine Nachrichten-Verarbeitung aus Idle ist, sondern ein expliziter Aufruf aus dem Programmcode.

Außerdem erhöht der Aufruf die Zählvariable ProcessMessages_Explicit_Counter, die man in der Oberfläche auswerten kann, z.B. bei Click oder in Timer-Events, die lieber nichts Neues starten sollen, solange noch eine andere Schleife läuft.

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
begin
  if ProcessMessages_Explicit_Counter > 0 then begin Beep; Exit; end;
  ...
end;
Ich habe es in ein Programm eingebaut und bin zufrieden. Oder gibt es dafür längst eine bestehende Lösung?

Ein Problem habe ich jedoch: Den Compiler-Wert LCL gibt es in Delphi nicht. Die VCL setzt keinen Wert VCL oder ähnlich. Wie könnte man eine Delphi-kompatible Weiche umsetzen?
Grüße, Jörg

Benutzeravatar
theo
Beiträge: 11406
Registriert: Mo 11. Sep 2006, 19:01

Re: Application.ProcessMessages

Beitrag von theo »

Der "Königsweg" ist eigentlich, dass die Klasse Events bereitstellt.
Im Beispiel "TFileSearcher", worauf du dich wahrscheinlich beziehst, gibt es ja OnDirectoryFound, OnFileFound etc.
Die kann man im LCL Code "einhängen" und dort die gewünschte Aktion auslösen (Info Update, Processmesages).
Das gefällt mir persönlich besser.
Das Gemurkse mit TMyCopyDirTree habe ich ja nur gemacht, weil TCopyDirTree aus unerfindlichen Gründen nicht im interface-Teil von FileUtil deklariert ist.

Was mit der laufenden Prozedur geschieht, bzw. ob die in so einem Moment auch abgebrochen werden kann, hängt vom jew. Fall ab.

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 470
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Application.ProcessMessages

Beitrag von Jorg3000 »

Ja, Callbacks/NotifyEvents sind natürlich der Königsweg, das stimmt.
Wenn man in einem solchen Event dann ProcessMessages() aufrufen möchte, steht man jedoch vor dem gleichen Problem wie oben beschrieben: Lauern weitere Fensternachrichten in der Warteschlange, die dazwischenfunken könnten? Und ist die LCL vorhanden?
Auch in einem TNotifyEvent kann man meine Procedure verwenden ...

Code: Alles auswählen

type
    THelperClass = class
     public
      procedure ProcessMessages(Sender: TObject);   // TNotifyEvent = procedure(Sender: TObject) of object;
    end;

procedure THelperClass.ProcessMessages(Sender: TObject);
begin
  ProcessMessages_Explicit();
end;

Benutzeravatar
Zvoni
Beiträge: 750
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz/FPC fixes)
CPU-Target: 64Bit
Wohnort: BW

Re: Application.ProcessMessages

Beitrag von Zvoni »

Mal unabhängig vom "Königsweg":
Application.ProcessMessages() ruft die Message-Queue des WIDGET-Sets auf, um diese abzuarbeiten.
Und im Source-code ist klar erkennbar das eine Critical Section gestartet wird. --> Ergo: Threads
Klar, steht das nicht in einer Konsolen-Anwendung zur Verfügung, aber was hindert dich daran, sowas selbst zu Implementieren für eine Konsolen-Anwendung?

Ich verweise mal auf DaemonApp --> https://www.freepascal.org/docs-html/fc ... index.html
was ja auch keine GUI/LCL hat

Oder in Lazarus einfach mal auf Project - New Project... und dort mal auf "Console Application" gehen, und sich mal den auto-generierten Code anschauen.
Da fällt einem die Unit "CustApp" sofort ins Auge.

Und ganz zum Schluss: Was soll eine Funktionalität wie "ProcessMessages" in einer Konsolen-Anwendung bewirken?
"ProcessMessages" ist in dem Sinne nur ein "Werkzeug", damit ein Fenster eben nicht blockiert.
Wo in einer Konsolen-Anwendung hast du ein Fenster?

Lange rede, gar kein Sinn: Wenn du in einer Konsolen-Anwendung einen lange dauernden Prozess laufen lassen willst, und du willst aber, dass der User weiterhin in der Konsolen-Anwendung weiter arbeiten kann, heisst das Zauberwort THREADS (mit/ohne Callback bzw. Synchronsation)
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 470
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Application.ProcessMessages

Beitrag von Jorg3000 »

Zvoni hat geschrieben: Di 29. Sep 2026, 16:05 Wo in einer Konsolen-Anwendung hast du ein Fenster?
Das hast du missverstanden. Ich will kein ProcessMessages() für eine Konsolenanwendung nachbauen o.ä., sondern ganz im Gegenteil: Durch die Compiler-Weiche IFDEF LCL soll das Application.ProcessMessages() eben nicht mit kompiliert werden. Es dient lediglich dazu, dass man denselben Quellcode in einer Fenster- und in einer Konsolenanwendung verwenden kann, obwohl das Application-Objekt dort nicht zur Verfügung steht.

Benutzeravatar
Zvoni
Beiträge: 750
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz/FPC fixes)
CPU-Target: 64Bit
Wohnort: BW

Re: Application.ProcessMessages

Beitrag von Zvoni »

ACH SO!
Ok, sorry. Gänzlich missverstanden.

Mach dir doch einfach jeweils 2 debug/release-varianten, in denen du ein eigenes Symbol definierst.

Ist ja jetzt keine Raketen Wissenschaft
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

laz_mikel
Beiträge: 4
Registriert: Mo 17. Aug 2026, 16:17

Re: Application.ProcessMessages

Beitrag von laz_mikel »

Das Problem mit dem Dazwischen-Funken-Könnens wegen Application.ProcessMessages versuche ich (in GUI-Anwendungen) mit einer globalen Variable und einer entsprechenden, dazugehörigen Prozedur zu beheben.
Je nach Wert dieser globalen Variable werden im Programm bestimmte Schalter, Menüs usw. mit Hilfe der Prozedur je nach Bedarf gesperrt oder freigegeben.

Diese Prozedur zu pflegen ist zwar mit einigem Aufwand verbunden, aber so gibt es eine zentrale Stelle, wo je nach Variablenwert nur das zugelassen wird, was auch benutzt werden darf.
So kann verhindert werden, dass bei Aufruf von Application.ProcessMessages etwas Unpassendes gestartet/aufgerufen wird.

Benutzeravatar
Zvoni
Beiträge: 750
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz/FPC fixes)
CPU-Target: 64Bit
Wohnort: BW

Re: Application.ProcessMessages

Beitrag von Zvoni »

Zvoni hat geschrieben: Di 29. Sep 2026, 17:41 ACH SO!
Ok, sorry. Gänzlich missverstanden.

Mach dir doch einfach jeweils 2 debug/release-varianten, in denen du ein eigenes Symbol definierst.

Ist ja jetzt keine Raketen Wissenschaft
Proof of Concept
Zwei Beispiel-Modes "DebugGUI" und "DebugConsole" (gleiches dann für Release)
In "DebugGUI" dann eine "Custom Option" gesetzt "MyGUI" und auf aktiv gesetzt (Siehe Screenshots)
2026-09-30 S1.png
2026-09-30 S1.png (47.6 KiB) 23 mal betrachtet
2026-09-30 S2.png
2026-09-30 S2.png (41.34 KiB) 23 mal betrachtet
2026-09-30 S3.png
2026-09-30 S3.png (24.46 KiB) 21 mal betrachtet
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Antworten