2013-03-29 14 views
6

Per quanto comprendo e conosco il metodo della TThread Class, se sincronizzi il tuo codice, in realtà viene eseguito nel thread principale dell'applicazione (proprio come un timer/tasto clic/ecc.) Ho giocato in giro e notato che un MessageBox NON blocca l'applicazione principale, tuttavia il sonno fa come previsto. Perché?Perché un MessageBox non blocca l'applicazione su un thread sincronizzato?

+0

Spiegare cosa si intende per "bloccare l'applicazione principale" –

risposta

11

Ci sono due parti per questa risposta.

La parte 1 è spiegata correttamente in If MessageBox()/related are synchronous, why doesn't my message loop freeze?. La funzione MessageBox non sta bloccando, ma crea semplicemente una finestra di dialogo con il proprio loop di messaggi.

La parte 2 è spiegata nello MessageBox documentation.

hWnd: un handle alla finestra del proprietario della finestra di messaggio da creare. Se il parametro è NULL, la finestra del messaggio non ha una finestra del proprietario.

Quando si visualizza una finestra di dialogo modale, Windows disabilita il suo proprietario, ma se si passa 0 per il primo parametro, non c'è nulla di proprietario e disattivare. Pertanto, il tuo programma continuerà ad elaborare i messaggi (e reagire ad essi) mentre viene visualizzata la finestra di messaggio.

Per modificare questo comportamento, passare l'handle del modulo come primo parametro. Per esempio:

procedure TTestThread.SynchThread; 
begin 
    MessageBoxA (Form1.Handle, 'Hello', 'Test', 0); 
end; 
+3

La tua parte 2 non è precisa. Non avere proprietario non cambia il ciclo dei messaggi che rimuove i messaggi. MessageBox è ancora sincrono e fino a quando non ritorna, il suo ciclo di messaggi estrae i messaggi in coda. Quando si passa una finestra del proprietario ad una finestra di dialogo modale, la finestra di dialogo modale disabilita il proprietario, il suo proprietario e così via. –

+2

David, grazie. Corretto. – gabr

4

Synchronize eseguirà il codice nel Mainthread.
Una buona spiegazione può essere trovata qui Synchronization in Delphi TThread class

Devi solo impedire all'utente di interagire con i moduli della tua applicazione, ad es. da

procedure TTestThread.SynchThread; 
begin 
MessageBoxA (0, 'Hello', 'Test', MB_TASKMODAL);  
end; 

utilizzando MessageBoxA come hai fatto tu, non impedirà il Mainthread di reagire a questi eventi triggerd da ueser interazione con i moduli, basta provare

procedure TForm4.Button2Click(Sender: TObject); 
begin 
    MessageBoxA (0, 'Hello', 'Test', 0); 
    // vs 
    // MessageBoxA (0, 'Hello', 'Test', MB_TASKMODAL); 
end; 

MessageBoxA

che la sincronizzazione sarà può essere eseguito nel thread principale può essere mostrato (IMHO) da

type 
    TTestThread = class(TThread) 
    private 
    FSync:Boolean; 
    FCalled:TDateTime; 
    procedure SynchThread; 
    protected 
    procedure Execute; override; 
    public 
    constructor Create(CreateSuspended: Boolean;sync:Boolean); 
    end; 

procedure TTestThread.SynchThread; 
begin 
MessageBox (0,PChar(DateTimeToStr(FCalled)+#13#10+DateTimeToStr(Now)),'Hello' , 0); 
end; 

procedure TTestThread.Execute; 
begin 
sleep(100); // give Caller Time to fell asleep 
if Fsync then Synchronize (SynchThread) else SynchThread; 
end; 

constructor TTestThread.Create(CreateSuspended: Boolean;sync:Boolean); 
begin 
    inherited Create(CreateSuspended); 
    FSync := Sync; 
    FCalled :=Now; 
    FreeOnTerminate := True; 
end; 

procedure StartThread(sync:Boolean); 
var 
TestThread : TTestThread; 
begin 
TestThread := TTestThread.Create (FALSE,sync); 
end; 

procedure TForm4.RunUnsynchronizedClick(Sender: TObject); 
begin 
    StartThread(false);// no sync 
    Sleep(5000);  // Stop messageloop 
end; 

procedure TForm4.RunSynchronizedClick(Sender: TObject); 
begin 
    StartThread(true); // sync 
    Sleep(5000);  // Stop messageloop 
end; 
+0

Allora, perché è questo essere downvoted, mi sembra che il parametro MB_TASKMODAL è un buon suggerimento. @bummi perché non passare la maniglia della finestra di mainform? – Remko

+0

@Remko prima della mia prima modifica ho avuto anche una chiamata con application.handle. Il downvote sarà causato da diversi punti di vista sul "blocco". – bummi

+1

Chiunque là fuori sa come funziona 'MB_TASKMODAL'? Disabilita tutte le finestre di primo livello di proprietà del processo di chiamata? –

10

Ho il sospetto che la questione si riduce a ciò che si intende quando si dice:

scatola Un messaggio non blocca l'applicazione principale.

Quello che prendo questo significa che quando si visualizza la finestra di messaggio, il modulo VCL può ancora essere interagito con. Il problema qui non è correlato ai thread e suggerisco di rimuoverli dall'equazione. La tua comprensione di cosa fa Synchronize è valida.

Il problema è interamente correlato al concetto di window's owner e al comportamento delle finestre di dialogo modali rispetto ai rispettivi proprietari.Si noti che dal proprietario, non intendo la proprietà Delphi TComponent.Owner, ma intendo il significato dell'API di Windows di owner.

Creare un'app VCL e rilasciare due pulsanti sul modulo. Aggiungi i seguenti gestori OnClick.

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    MessageBox(0, 'Not owned', nil, MB_OK); 
end; 

procedure TForm1.Button2Click(Sender: TObject); 
begin 
    MessageBox(Handle, 'Owned by the VCL form', nil, MB_OK); 
end; 

Ora osservare ciò che accade quando si fa clic su Button1. Viene visualizzata la finestra di messaggio, ma è ancora possibile fare clic sul modulo VCL. E confrontare con Button2. Quando mostra la finestra del messaggio, non è possibile interagire con il modulo VCL.

Quando viene visualizzata una finestra di dialogo modale, la finestra di dialogo ne disabilita il proprietario. Nel caso di Button2, il proprietario è il modulo VCL. E una volta disabilitato il modulo, non puoi interagire con esso. Nel caso di Button1, non esiste un proprietario e quindi la finestra di dialogo modale non disabilita altre finestre. Ecco perché è possibile interagire con il modulo VCL.

Raymond Chen ha una lunga serie sulle modalità al suo vecchio blog New Thing:

Problemi correlati