2015-04-04 15 views
7

Mam wątpliwości, w jaki sposób powinienem użyć QEventLoop. Mam 2 kawałki kodu, oba działają dla mnie (pobierz pobrany zasób sieciowy).Właściwe użycie QEventLoop

Pierwszy:

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(); 

drugie jeden:

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(); 

Co chcę wiedzieć, który z nich powinno się używać. Mam na myśli, czy pętla zdarzeń kończy się w drugiej po wyzwoleniu sygnału? Czy muszę zadzwonić pod numer quit() jak w pierwszym? Drugie rozwiązanie znalazłem gdzieś, ale nie wydawało mi się to właściwe, więc zmodyfikowałem go na pierwszy kawałek kodu.

+0

Jak chcesz przerwać pętlę zdarzeń w drugim przypadku? Najpierw jest OK, ale powinieneś też radzić sobie z błędami. –

+0

Tak, właśnie o tym wiedziałem, więc go zmieniłem. Po prostu nie byłam pewna, czy dobrze się zastanawiałam, więc zapytałam: –

+1

Ogólnie nie powinieneś używać - QApplication już tworzy pętlę zdarzeń dla głównego wątku, a QThread ustawia pętlę zdarzeń dla wątków w tle. – MrEricSir

Odpowiedz

1

W Twojej drugiej przykładowej pętli zdarzeń nigdy nie zrezygnujesz, z drugiej strony w pierwszym przykładzie pętla zakończy się, kiedy wyemituje finished(QNetworkReply*). Ale co jeśli sygnał będzie emitowany przed podłączeniem do niego pętli?

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(); 

A także trzeba jakoś sobie sytuację, w której menedżer nie emitują SIGNAL(finished(QNetworkReply*)) w ogóle.

1

Zgadzam się z @ Mher-Didaryan - że pętla zdarzeń uruchomiona przez następujący wiersz kodu loop.exec(); w drugim fragmencie kodu - nigdy się nie zakończy. Dzieje się tak, ponieważ connect() między SIGNAL i SLOT jest wykonywane dla innej pętli zdarzeń niż pętla zdarzeń wskazana przez EventLoop loop;.

W przypadku pierwszego fragmentu kodu, logika zależy od sygnału finished(QNetworkReply*) związanego z jednym takim samym żądaniem GET emitowanym do dwóch różnych pętli zdarzeń. Ale to jest całkiem możliwe, że

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

może dobrze wykonać po manager->get(request) ; został wyemitowany sygnał finished(QNetworkReply*). Być może może się tak stać w przypadku operacji HTTP typu GET z bardzo małym plikiem lub odpowiedzią. W takim scenariuszu pętla zdarzeń rozpoczęta przez loop.exec(); w pierwszym fragmencie kodu również nie zostanie zakończona. Sądzę, że to jest to, co @ Mher-Didaryan również pyta w swojej odpowiedzi.

Być może można użyć poniższego QEventLoop logikę, która będzie obsługiwać następujące scenariusze negatywne wykonanie zbyt

  1. rozrządu z żądania GET (słownie powodu problemów z łącznością sieciowa)
  2. Error odpowiedzi typu z serwera strona sieci

    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; 
    
Powiązane problemy