QEventLoop正确用法

时间:2015-04-04 17:47:31

标签: qt qtnetwork qeventloop

我怀疑应该如何使用QEventLoop。我有两段代码,它们都适用于我(获取Web资源下载)。

第一个:

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

第二个:

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

我想知道的是我应该使用哪一个。我的意思是,在信号被激活后,事件循环是否在第二个中退出?或者我必须像第一个一样打电话给quit()吗?我在某个地方找到了第二个解决方案,但它对我来说似乎不合适所以我将其修改为第一段代码。

2 个答案:

答案 0 :(得分:2)

我同意@ Mher-Didaryan - 事件循环由第二个代码片段中的以下代码行loop.exec();启动 - 永远不会退出。这是因为SIGNAL和SLOT之间的 connect()正在完成与通过EventLoop loop;指示的事件循环不同的事件循环。

在第一个代码片段的情况下,逻辑取决于与{1}相关联的finished(QNetworkReply*)信号。将相同的GET请求发送到两个不同的事件循环。但很有可能

    connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit()));
manager->get( request ) ;发出finished(QNetworkReply*)信号后,

可能会执行。对于涉及非常小的文件或响应的GET类型HTTP操作,可能会发生这种情况。在这种情况下,第一个代码段中loop.exec();开始的事件循环也不会退出。我想这就是@Mher-Didaryan也在回答他的问题。

也许你可以使用下面的QEventLoop逻辑来处理以下负面执行场景

  1. 提示退出GET请求(例如由于网络连接问题)
  2. 来自网络服务器端的错误类型响应

    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;
    

答案 1 :(得分:1)

在你的第二个例子中,事件循环永远不会退出,另一方面,在你的第一个例子中,循环将在finished(QNetworkReply*)发出时退出。但是,如果在连接循环之前manager->get( request );导致finished(QNetworkReply*)信号被激活,该怎么办呢?

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

而且你还需要以某种方式处理经理根本不会发出SIGNAL(finished(QNetworkReply*))的情况。