2010-08-24 12 views
18

lo so, ci sono alcune domande simili alle seguenti là fuori, ma non riuscivo a trovare una risposta concreta che mi aiuta. Quindi, ecco il mio problema:bloccato in attesa di un segnale asincrono Qt

Io lavoro su un'applicazione che fa alcuni gui-Inizializzazioni in fase di start up. Una delle cose che ho da fare, sta chiamando

NetworkConfigurationManager::updateConfigurations() 

Questa è una chiamata asincrona, che emette il segnale updateCompleted(), quando è finito. Il problema è che tutte le altre inizializzazioni della GUI devono attendere fino al termine dello updateConfigurations().

Quindi quello che ho potuto fare sarebbe qualcosa di simile:

MyApp::MyApp(QWidget *parent) : .... 
{ 
    doSomeInits(); 
    //Now connect the signal we have to wait for 
    connect(configManager, SIGNAL(updateCompleted()), this, SLOT(networkConfigurationUpdated())); 
    configManager->updateConfigurations(); //call the async function 
} 

void MyApp::networkConfigurationUpdated() 
{ 
    doSomething(); 
    doRemainingInitsThatHadToWaitForConfigMgr(); 
} 

di dividere l'inizializzazione non sembra un buon modo per me. Penso che renda il codice molto più difficile da leggere - le basi dovrebbero rimanere insieme. L'altra cosa è: Perché updateConfiguration() è asincrono, l'utente sarà in grado di utilizzare l'interfaccia grafica, che non gli è ancora dato alcuna informazione, perché siamo in attesa di updateCompleted().

Quindi c'è un modo per attendere il segnale updateCompleted(), prima che l'applicazione continui?

come:

MyApp::MyApp(QWidget *parent) : .... 
{ 
    doSomeInits(); 
    //Now connect the signal we have to wait for 
    connect(configManager, SIGNAL(updateCompleted()), this, SLOT(doSomething())); 
    ???? //wait until doSomething() is done. 
    doRemainingInitsThatHadToWaitForConfigMgr(); 
} 

In alcune API esistono alternative al blocco funzioni asincrone, ma non in questo caso.

Apprezzo qualsiasi aiuto. Grazie!

risposta

19

Il modo per farlo è quello di utilizzare i cicli di eventi nidificati. È sufficiente creare il proprio QEventLoop, collegare qualsiasi segnale che si desidera attendere allo slot del loop quit(), quindi il ciclo exec(). In questo modo, una volta che il segnale viene chiamato, attiverà lo slot quit() di QEventLoop, uscendo quindi dal ciclo exec().

MyApp::MyApp(QWidget *parent) : .... 
{ 
    doSomeInits(); 
    { 
     QEventLoop loop; 
     loop.connect(configManager, SIGNAL(updateCompleted()), SLOT(quit())); 
     configManager->updateConfigurations(); 
     loop.exec(); 
    } 
    doReaminingInitsThatHadToWaitForConfigMgr(); 
} 
+0

Sì, questo funziona, ed è il modello standard per "il blocco di attesa senza bloccare l'interfaccia utente". Lo eviterei però se possibile. I loop di eventi nidificati possono causare gravi mal di testa, ad es. l'utente che esegue roba non corretta casualmente mentre loop.exec(), chiude l'applicazione ecc., lasciando l'applicazione in uno stato non coerente e incoerente dopo che exec() restituisce. Oppure: un evento (utente) apre un altro ciclo di eventi locale in attesa di un evento che richiede il completamento del primo ciclo, causando una sorta di quasi-deadlock. Ecco perché raccomando di usare uno slot e continuare lì, anche se è più dettagliato. –

+0

Prima di tutto: grazie per il vostro aiuto. La tua risposta è giusta, anche se non funziona nella mia soluzione. Credo di avere uno dei problemi menzionati da Frank, perché il mio ciclo non è in grado di uscire. Tuttavia ho trovato una risposta alla tua risposta nel Nokia Wiki (http://wiki.forum.nokia.com/index.php/TSQ001335_-_Asynchronous_operations_in_S60_and_Qt). Quindi grazie a tutti! – cyphorious

+0

Secondo Qt/Nokia, non si dovrebbe usare un QEventloop come causa della mia ricorsione fuori controllo (vedere http://developer.nokia.com/community/wiki/How_to_wait_synchronously_for_a_Signal_in_Qt). Questo dovrebbe essere solo per i test. O sto leggendo male questo articolo? – TSG

7

Lavorare da chalup s' answer, se avete intenzione di essere in attesa per un tempo user-evidente, si potrebbe desiderare di mostrare un progress bar invece (o un splash screen, forse).

MyApp::MyApp(QWidget *parent) : .... 
{ 
    doSomeInits(); 
    { 
     QSpashScreen splash; 
     splash.connect(configManager, SIGNAL(updateCompleted()), SLOT(close())); 
     configManager->updateConfigurations(); 
     splash.exec(); 
    } 
    doReaminingInitsThatHadToWaitForConfigMgr(); 
} 
0

Un'altra soluzione potrebbe essere quella di utilizzare QSignalSpy::wait(). Questa funzione è stata introdotta in Qt 5 e fa esattamente ciò che desideri.

L'unico problema che vedo con quella classe è che viene fornito nel modulo QtTest. Nel mio caso lo trovo molto utile durante il test del codice, ma potrebbe non essere la soluzione migliore per il codice di produzione.

+0

Sembra essere internamente uguale alla risposta di 'chalup'. –

Problemi correlati