惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

U
Unit 42
罗磊的独立博客
T
Tailwind CSS Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Jina AI
Jina AI
V
V2EX
美团技术团队
阮一峰的网络日志
阮一峰的网络日志
酷 壳 – CoolShell
酷 壳 – CoolShell
月光博客
月光博客
量子位
MyScale Blog
MyScale Blog
G
Google Developers Blog
M
MIT News - Artificial intelligence
L
LangChain Blog
Microsoft Azure Blog
Microsoft Azure Blog
Recent Announcements
Recent Announcements
MongoDB | Blog
MongoDB | Blog
N
Netflix TechBlog - Medium
有赞技术团队
有赞技术团队
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
D
DataBreaches.Net
云风的 BLOG
云风的 BLOG
B
Blog

博客园 - 平凡人

std::atomic linux学习-目录 C++设计模式--PIMPL c++的RAII C++技术之---标准容器的值语义 blender学习系列之--CLOG Blender中的DNA QT元对象系统(Meta-Object System) Blender文档翻译:ID Datablocks(ID数据块) Blender内存管理库(bf_intern_guardedalloc) IDA\Windbg调试 - 平凡人 - 博客园 IOCTL(CTL_CODE) 内核开发速查表 Blender中的事件处理器 Blender:SDNA QT信号和槽 Blender文档翻译:Operators tutorial(操作教程) Blender文档翻译:Operators Blender文档翻译:RNA Blender文档翻译-Blender库数据的通用属性
利用QEventLoop实现同步等待信号槽返回结果
平凡人 · 2018-05-06 · via 博客园 - 平凡人

在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函数,则所有过程可简化为一个函数的形式。