Il lato oscuro di Application.ProcessMessages nelle applicazioni Delphi

Articolo presentato da Marcus Junglas

Quando si programma un gestore di eventi in Delphi (come il Al clic evento di un pulsante TB), arriva il momento in cui l'applicazione deve essere occupata per un po ', ad es. il codice deve scrivere un file di grandi dimensioni o comprimere alcuni dati.

Se lo fai, lo noterai la tua applicazione sembra essere bloccata. Non è più possibile spostare il modulo e i pulsanti non mostrano alcun segno di vita. Sembra essere andato in crash.

Il motivo è che un'applicazione Delpi è a thread singolo. Il codice che stai scrivendo rappresenta solo un mucchio di procedure che vengono chiamate dal thread principale di Delphi ogni volta che si verifica un evento. Il resto del tempo il thread principale gestisce i messaggi di sistema e altre cose come le funzioni di gestione di moduli e componenti.

Quindi, se non completi la gestione degli eventi facendo un lungo lavoro, impedirai all'applicazione di gestire quei messaggi.

Una soluzione comune per questo tipo di problemi è quella di chiamare "Application.ProcessMessages". "Applicazione" è un oggetto globale della classe TApplication.

Application.Processmessages gestisce tutti i messaggi in attesa come movimenti di finestre, clic di pulsanti e così via. È comunemente usata come soluzione semplice per mantenere "funzionante" l'applicazione.

Sfortunatamente il meccanismo alla base di "ProcessMessages" ha le sue caratteristiche, che potrebbero causare grande confusione!

Cosa significa ProcessMessages?

PprocessMessages gestisce tutti i messaggi di sistema in attesa nella coda dei messaggi delle applicazioni. Windows utilizza i messaggi per "parlare" con tutte le applicazioni in esecuzione. L'interazione dell'utente viene portata al modulo tramite messaggi e "ProcessMessages" li gestisce.

Se il mouse si abbassa su un pulsante TB, ad esempio, ProgressMessages fa tutto ciò che dovrebbe accadere in questo evento come la riverniciatura del pulsante su uno stato "premuto" e, naturalmente, una chiamata alla procedura di gestione di OnClick () se si assegnato uno.

Questo è il problema: qualsiasi chiamata a ProcessMessages potrebbe contenere nuovamente una chiamata ricorsiva a qualsiasi gestore di eventi. Ecco un esempio:

Utilizzare il seguente codice per l'handler di OnClick di un pulsante ("lavoro"). L'istruzione for simula un lungo processo di elaborazione con alcune chiamate a ProcessMessages di tanto in tanto.

Questo è semplificato per una migliore leggibilità:

 in MyForm:
  WorkLevel: intero;
OnCreate:
  WorkLevel: = 0;
procedura TForm1.WorkBtnClick (Mittente: TObject);
var
  ciclo: intero;
inizio
  inc (WorkLevel);
  per ciclo: = 1 per 5 fare
  inizio
    Memo1.Lines.Add ('- Work' + IntToStr (WorkLevel) + ', Cycle' + IntToStr (ciclo);
    Application.ProcessMessages;
    sonno (1000); // o qualche altro lavoro
  fine;
  Memo1.Lines.Add ('Work' + IntToStr (WorkLevel) + 'finito.');
  dec (WorkLevel);
fine;

SENZA "ProcessMessages" le seguenti righe vengono scritte nel memo, se il pulsante è stato premuto DUE VOLTE in breve tempo:

 - Lavoro 1, ciclo 1
- Lavoro 1, ciclo 2
- Lavoro 1, ciclo 3
- Lavoro 1, ciclo 4
- Lavoro 1, ciclo 5
Il lavoro 1 è terminato.
- Lavoro 1, ciclo 1
- Lavoro 1, ciclo 2
- Lavoro 1, ciclo 3
- Lavoro 1, ciclo 4
- Lavoro 1, ciclo 5
Il lavoro 1 è terminato.