利用QEventLoop实现同步等待信号槽返回结果

在QT中想要实现一个简单的函数:给定一个网页地址(http://www.hao123.com),等待返回网页的html内容。

当然我想到可利用QNetWork相关的类:QNetworkAccessManager、QNetworkRequest、QNetworkReply三个类;进一步深入发现,网络访问一般是异步的,因此Qt中reply的结果是利用信号/槽机制来进行通知和处理的,这仍然是异步的,也就是说不能立即取得reply结果,而只能在槽函数中来处理reply结果。我也想到用lambda函数实现槽函数,似乎能立即取得结果,但可惜的是lambda函数仍然是异步调用的。

我用一个类来实现该功能。

头文件:webspider.h

 1 #include "QtNetwork\QNetworkAccessManager"
 2 class WebSpider:public QObject
 3 {
 4     Q_OBJECT    
 5 public:
 6     WebSpider();
 7     ~WebSpider();
 8 
 9     QString getHtml(QString urlStr);
10 
11 public slots:
12     void requestFinished(QNetworkReply *reply);
13 private:
14     QNetworkAccessManager* _netManager;
15     QNetworkRequest* _netRequest;
16     
17     QByteArray _replyResult;
18 };

实现文件:webspider.cpp

 1 #include "WebSpider.h"
 2 #include "QEventLoop"
 3 #include "QtNetwork\QNetworkAccessManager"
 4 #include "QtNetwork\QNetworkReply"
 5 #include "QObject"
 6 
 7 
 8 
 9 WebSpider::WebSpider()
10     :QObject()
11 {
12     _netManager = new QNetworkAccessManager();
13     
14 }
15 
16 
17 WebSpider::~WebSpider()
18 {
19     delete _netManager;
20 }
21 
22 QString WebSpider::getHtml(QString urlStr)
23 {
24     _netRequest = new QNetworkRequest(QUrl(urlStr));
25     _netManager->get(*_netRequest);
26     
27     QEventLoop* el = new QEventLoop();
28 
29     connect(_netManager, &QNetworkAccessManager::finished, el, &QEventLoop::quit);    //网络访问结束时,结束事件循环
30     connect(_netManager, &QNetworkAccessManager::finished, this, &WebSpider::requestFinished); //网络访问结束时,处理返回结果
31     el->exec();    //开始事件循环,等待网络访问结束
32     //事件循环结束后,requestFinished槽中已获取网络访问结果,保存于_replyResult中
33     return QString(_replyResult);    //返回结果
34 }
35 
36 void WebSpider::requestFinished(QNetworkReply *reply)
37 {
38     _replyResult=reply->readAll();
39 }

在程序中只需要简单二行代码就可取得结果

1 WebSpider ws;
2 QString htmlStr=ws.getHtml("http://www.hao123.com");

就象一个函数一样,结果立即就获得了,没有异步访问的感觉了,呵呵。任务达成。
WebSpider中实际上是异步的,但利用QEventLoop等待异步调用后,再返回结果的,也就是说,有一个等待的过程。这里我们没有考虑网络异常的可能,具体应用中可进一步完善。

在QT中异步无处不在,这个小例子有助于我们实现一些简单的小功能,将异步的代码集中包装,在主程序中代码将显示出简单直接。

进一步,如果槽函数可直接写成lambda函数,则所有过程可简化为一个函数的形式。

 

posted @ 2018-05-06 12:26  平凡人  阅读(2456)  评论(0编辑  收藏  举报