De donkere kant van de toepassing. Procesberichten in Delphi-toepassingen

Artikel ingediend door Marcus Junglas

Bij het programmeren van een gebeurtenishandler in Delphi (zoals de Bij klikken gebeurtenis van een TButton), komt er het moment dat uw toepassing een tijdje bezig moet zijn, b.v. de code moet een groot bestand schrijven of sommige gegevens comprimeren.

Als je dat doet, zul je dat merken uw toepassing lijkt te zijn vergrendeld. Uw formulier kan niet meer worden verplaatst en de knoppen vertonen geen teken van leven. Het lijkt te zijn gecrasht.

De reden is dat een Delpi-toepassing een enkele thread heeft. De code die u schrijft, vertegenwoordigt slechts een aantal procedures die door de hoofdthread van Delphi worden opgeroepen telkens wanneer zich een gebeurtenis voordoet. De rest van de tijd is de hoofdthread systeemmeldingen en andere dingen zoals vorm- en componentafhandelingsfuncties.

Dus als u de afhandeling van uw evenement niet afmaakt door wat lang werk te doen, voorkomt u dat de toepassing die berichten afhandelt.

Een gebruikelijke oplossing voor dit soort problemen is om "Application.ProcessMessages" te noemen. "Toepassing" is een wereldwijd object van de klasse TApplication.

De Application.Processmessages verwerkt alle wachtende berichten zoals vensterbewegingen, klikken op knoppen, enzovoort. Het wordt vaak gebruikt als een eenvoudige oplossing om uw applicatie "werkend" te houden.

Helaas heeft het mechanisme achter "ProcessMessages" zijn eigen kenmerken, die grote verwarring kunnen veroorzaken!

Wat doet ProcessMessages?

PprocessMessages verwerkt alle wachtende systeemberichten in de berichtenwachtrij van de applicatie. Windows gebruikt berichten om met alle actieve toepassingen te "praten". Gebruikersinteractie wordt via berichten naar het formulier gebracht en "ProcessMessages" verwerkt ze.

Als de muis bijvoorbeeld op een TButton uitkomt, doet ProgressMessages alles wat er bij deze gebeurtenis zou moeten gebeuren, zoals het opnieuw schilderen van de knop naar een "ingedrukte" status en, natuurlijk, een aanroep van de OnClick () -behandelingsprocedure als u toegewezen.

Dat is het probleem: elke aanroep naar ProcessMessages kan opnieuw een recursieve aanroep naar een gebeurtenishandler bevatten. Hier is een voorbeeld:

Gebruik de volgende code voor de OnClick even-handler van een knop ("werk"). De for-statement simuleert een lange verwerkingstaak met zo nu en dan enkele oproepen aan ProcessMessages.

Dit is vereenvoudigd voor een betere leesbaarheid:

 in MyForm:
  WorkLevel: geheel getal;
OnCreate:
  Werkniveau: = 0;
procedure TForm1.WorkBtnClick (Sender: TObject);
var
  cyclus: geheel getal;
beginnen
  inc (WorkLevel);
  voor cyclus: = 1 naar 5 Doen
  beginnen
    Memo1.Lines.Add ('- Work' + IntToStr (WorkLevel) + ', Cycle' + IntToStr (cycle);
    Application.ProcessMessages;
    slaap (1000); // of ander werk
  einde;
  Memo1.Lines.Add ('Work' + IntToStr (WorkLevel) + 'beëindigd.');
  dec (WorkLevel);
einde;

ZONDER "ProcessMessages" worden de volgende regels naar het memo geschreven, als de knop in een korte tijd tweemaal werd ingedrukt:

 - Werk 1, cyclus 1
- Werk 1, cyclus 2
- Werk 1, cyclus 3
- Werk 1, cyclus 4
- Werk 1, cyclus 5
Werk 1 is beëindigd.
- Werk 1, cyclus 1
- Werk 1, cyclus 2
- Werk 1, cyclus 3
- Werk 1, cyclus 4
- Werk 1, cyclus 5
Werk 1 is beëindigd.