2015-04-04 11 views
7

Ho dei dubbi su come dovrei usare QEventLoop. Ho 2 pezzi di codice, entrambi funzionano per me (scarica la risorsa web).QEventLoop uso corretto

Primo uno:

QNetworkAccessManager *manager = new QNetworkAccessManager(this); 
QNetworkRequest request; 
request.setUrl(QUrl(url)); 
request.setRawHeader("User-Agent", "Mozilla Firefox"); 
connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*))); 
manager->get(request) ; 

QEventLoop loop; 
connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit())); 
loop.exec(); 

secondo:

QNetworkAccessManager *manager = new QNetworkAccessManager(this); 
QNetworkRequest request; 
request.setUrl(QUrl(url)); 
request.setRawHeader("User-Agent", "Mozilla Firefox"); 
manager->get(request) ; 

QEventLoop loop; 
connect(manager, SIGNAL(finished(QNetworkReply*)),this, SLOT(replyFinished(QNetworkReply*))); 
loop.exec(); 

Quello che voglio sapere è quale dovrei usare. Voglio dire, il ciclo degli eventi si chiude nella seconda dopo che il segnale è emmitato? O devo chiamare quit() come nel primo? Ho trovato la seconda soluzione da qualche parte ma non mi sembrava adatta quindi l'ho modificata nel primo pezzo di codice.

+0

Come si desidera interrompere ciclo di eventi nel secondo caso? Prima è OK, ma dovresti anche gestire gli errori. –

+0

Sì, questo è quello che mi preoccupava, quindi l'ho cambiato. Non ero sicuro che stavo pensando in modo corretto, quindi ho chiesto a –

+1

In generale, non dovresti usare nessuno - QApplication imposta già un loop di eventi per il thread principale e QThread imposta un loop di eventi per i thread in background. – MrEricSir

risposta

1

Nel secondo caso, il ciclo di eventi non si chiuderà mai, d'altra parte nel primo esempio il ciclo si chiuderà quando emette finished(QNetworkReply*). Ma cosa succede se manager->get(request); causa il segnale finished(QNetworkReply*) da emettere prima di collegare il ciclo di uscita da esso?

QNetworkAccessManager *manager = new QNetworkAccessManager(this); 
QNetworkRequest request; 
QEventLoop loop; 
request.setUrl(QUrl(url)); 
request.setRawHeader("User-Agent", "Mozilla Firefox"); 
connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*))); 
connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit())); 
manager->get(request) ; 

loop.exec(); 

E inoltre è necessario gestire in qualche modo situazione in cui manager non emette SIGNAL(finished(QNetworkReply*)) affatto.

1

Sono d'accordo con @ Mher-Didaryan - che il ciclo di eventi iniziato seguendo la riga del codice loop.exec(); nel secondo snippet di codice - non verrà mai chiuso. Questo perché il connect() tra SIGNAL e SLOT viene eseguito per un ciclo di eventi diverso rispetto al ciclo di eventi indicato tramite EventLoop loop;.

Nel caso del 1o snippet di codice, la logica dipende dal segnale finished(QNetworkReply*) associato a una richiesta di GET uguale a & emessa da due diversi loop di eventi. Ma è del tutto possibile che

connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit())); 

può ben eseguito dopo la manager->get(request) ; ha emesso il segnale finished(QNetworkReply*). Forse può succedere per un'operazione HTTP tipo GET che coinvolge un file o una risposta molto piccoli. In tale scenario, il ciclo di eventi avviato dallo loop.exec(); nel primo frammento di codice non verrà chiuso. Immagino che questo sia ciò che @ Mher-Didaryan sta anche chiedendo nella sua risposta.

Forse è possibile utilizzare il sottostante QEventLoop logica che avrebbe gestito i seguenti scenari di esecuzione negativi troppo

  1. Timing fuori dalla richiesta GET (per esempio a causa di problemi di connettività di rete) di tipo
  2. Errore risposta dal server lato della rete

    QNetworkAccessManager *manager = new QNetworkAccessManager(this); 
    QNetworkRequest request; 
    QEventLoop loop; 
    QTimer getTimer; // let's use a 10 second period for timing out the GET opn 
    request.setUrl(QUrl(url)); 
    request.setRawHeader("User-Agent", "Mozilla Firefox"); 
    // connect the timeout() signal of getTimer object to quit() slot of event loop 
    QTimer::connect(&getTimer,SIGNAL(timeout()),&loop, SLOT(quit())); 
    QObject::connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit())); 
    QNetworkReply *resp = manager->get(request);   
    getTimer.start(10000); // 10000 milliSeconds wait period for get() method to work properly 
    loop.exec(); 
    
    if(NULL == resp) 
    { 
        // Error. we probably timed out i.e SIGNAL(finished()) did not happen 
        // this handles above indicated case (1) 
        return -1; // or return some timeout related error value 
    } 
    else if(QNetworkReply::NoError != resp->error()) 
    { 
        // Error - SIGNAL(finished()) was raised but get() opn failed & returned with error 
        // Refer http://doc.qt.io/qt-4.8/qnetworkreply.html#NetworkError-enum 
        // This section of code handles above indicated case (2) 
    } 
    else 
    { 
        // get() operation was Successful !. 
        // read the response available in the 'resp' variable as a QString & parse it. 
        // Obtain the necessary result and etc. 
    } 
    
    delete resp; 
    delete manager;