最近项目有个要求,就是发送文件到服务器上面,然后要在程序里面等待服务器返回的数据,根据返回的信息决定继续发还是断开。本来想用while在那里等待,可是发现不行,界面卡住了。百度下,发现可以用QEventLoop来实现这个功能。
我简单说下QEventLoop的使用,更加具体详细的使用,大家可以参考官方文档或者其他文献。
QEventLoop类为我们提供了一种进入和退出一个事件循环的方法。在任何时候,你都可以创建一个QEventLoop实例,然后调用exec()来启动一个事件循环,在这个循环期间,可以调用exit()来强制使exct()返回。
事件循环是一个无限“循环”,当调用事件的exec()的时候,程序就会在exec()里面无限循环,让在exec()后面的程序得不到运行的机会,除非程序从exec()里面跳出来。
来啦,划重点了。子层事件循环具有父层事件循环的所有功能,所以当在主线程中启动各种exec()(比如QEventLoop::exec())时,虽然会打断main函数中的QApplication::exec(),但是Gui界面还是可以正常响应,不会出现卡住的现象。这与用while来循环是不一样的。
下面介绍下使用的方法,其实使用很简单
(1)实例化
QEventLoop loop;
(2)启动事件循环
//以上省略了部分代码,这是使用HTTP中的post来发送文件到服务器
QNetworkReply *postReply = m_pNetManager->post(request, qbt); //post方式到本地服务器
connect(postReply, SIGNAL(finished()), this, SLOT(postFileReplyFinished())); //成功后会有返回响应
loop->exec(); //设置等待,若文件成功发送,则退出等待
(3)在其他的响应函数中退出循环
void Widget::postFileReplyFinished()
{
QNetworkReply* reply = (QNetworkReply*)sender();
QByteArray replyData = reply->readAll();
//转为JSon格式,便于提取字段数据
QJsonDocument jsonDoc= QJsonDocument::fromJson(replyData);
if(!jsonDoc.isNull())
{
QJsonObject jsonObj = jsonDoc.object(); //转换格式
if(jsonObj.contains("status"))
{
loop->exit(); //loop退出等待
}
}
}
我实现的功能是,发送文件后,就进入事件循环,当接收到返回的json数据后,判断数据是否正确,正确的话就退出事件循环。
其实还有一种方法来实现事件循环的退出。就是使用QT中的信号与槽的机制,在初始化的时候,将 reply的响应与loop的quit连接起来。
QEventLoop loop;
qManager = new QNetworkAccessManager(this);
QNetworkRequest request;
request.setUrl(QUrl("http://localhost/public/index/file/upload"));
QNetworkReply *reply = qManager->get(request);
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
这样的话就更简洁了。可是有个问题就是,一收到reply就退出事件的循环,如果想要判断一下还是用前面的方法比较好。
参考文献:
http://doc.qt.io/archives/qt-4.8/qeventloop.html
http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=29650836&id=4471683
http://blog.chinaunix.net/uid-27685749-id-3847998.html