/

/

Qt 学习之路 2(68):访问网络(4)

Qt 学习之路 2(68):访问网络(4)

前面几章我们了解了如何使用QNetworkAccessManager 访问网络。在此基础上,我们已经实现了一个简单的查看天气的程序。在这个程序中,我们使用QNetworkAccessManager进行网络的访问,从一个网络 API 获取某个城市的当前天气状况。

如果你仔细观察就会发现,即便我们没有添加任何相关代码,QNetworkAccessManager的网络访问并不会阻塞 GUI 界面。也就是说,即便是在进行网络访问的时候,我们的界面还是可以响应的。相比之下,如果你对 Java 熟悉,就会了解到,在 Java 中,进行 Socket 通讯时,界面默认是阻塞的,当程序进行网络访问操作时,界面不能对我们的操作做出任何响应。由此可以看出,QNetworkAccessManager的网络访问默认就是异步的、非阻塞的。这样的实现固然很好,也符合大多数程序的应用情形:我们当然希望程序界面能够始终对用户操作做出响应。不过,在某些情况下,我们还是希望会有一些同步的网络操作。典型的是登录操作。在登录时,我们必须要等待网络返回结果,才能让界面做出响应:是验证成功进入系统,还是验证失败做出提示?这就是本章的主要内容:如何使用QNetworkAccessManager进行同步网络访问。

当我们重新运行先前编译好的程序,可以看看这样一个操作:由于我们的界面是不阻塞的,那么当我们第一次点击了 Refresh 按钮之后,马上切换城市再点击一次 Refresh 按钮,就会看到第一次的返回结果一闪而过。这是因为第一次网络请求尚未完成时,用户又发送了一次请求,Qt 会将两次请求的返回结果顺序显示。这样处理结果可能会出现与预期不一致的情况(比如第一次请求响应由于某种原因异常缓慢,第二次却很快,此时第二次结果会比第一次先到,那么很明显,当第一次结果返回时,第二次的结果就会被覆盖掉。我们假设认为用户需要第二次的返回,那么就会出现异常)。

要解决这种情况,我们可以在有网络请求时将界面锁死,不允许用户进行更多的操作(更好的方法是仅仅锁住某些按钮,而不是整个界面。不过这里我们以锁住整个界面为例)。我们的解决方案很简单:当QNetworkAccessManager发出请求之后,我们进入一个新的事件循环,将操作进行阻塞。我们的代码示例如下:

 
 
void fetchWeather(const QString &cityName)
{
QEventLoop eventLoop;
connect(netWorker, &NetWorker::finished,
&eventLoop, &QEventLoop::quit);
QNetworkReply *reply = netWorker->get(QString("http://api.openweathermap.org/data/2.5/weather?q=%1&mode=json&units=metric&lang=zh_cn").arg(cityName));
replyMap.insert(reply, FetchWeatherInfo);
eventLoop.exec();
}
1
2
3
4
5
6
7
8
9
void fetchWeather(const QString &cityName)
{
    QEventLoop eventLoop;
    connect(netWorker, &NetWorker::finished,
            &eventLoop, &QEventLoop::quit);
    QNetworkReply *reply = netWorker->get(QString("http://api.openweathermap.org/data/2.5/weather?q=%1&mode=json&units=metric&lang=zh_cn").arg(cityName));
    replyMap.insert(reply, FetchWeatherInfo);
    eventLoop.exec();
}

注意,我们在函数中创建了一个QEventLoop实例,将其quit()NetWorker::finished()信号连接起来。当NetWorker::finished()信号发出时,QEventLoop::quit()就会被调用。在NetWorker::get()执行之后,调用QEventLoop::exec()函数开始事件循环。此时界面就是被阻塞。

现在我们只是提供了一种很简单的思路。当然这并不是最好的思路:程序界面直接被阻塞,用户获得不了任何提示,会误以为程序死掉。更好的做法是做一个恰当的提示,不过这已经超出我们本章的范畴。更重要的是,这种思路并不完美。如果你的程序是控制台程序(没有 GUI 界面),或者是某些特殊的情况下,会造出死锁!控制台程序中发送死锁的原因在于在非 GUI 程序中另外启动事件循环会将主线程阻塞,QNetworkAccessManager的所有信号都不会收到。“某些特殊的情况”,我们会在后面有关线程的章节详细解释。不过,要完美解决这个问题,我们必须使用另外的线程。这里有一个通用的解决方案,感兴趣的童鞋可以详细了解下。

Qt 学习之路 2(68):访问网络(4)的更多相关文章

  1. .Net程序员安卓学习之路2:访问网络API

    做应用型的APP肯定是要和网络交互的,那么本节就来实战一把Android访问网络API,还是使用上节的DEMO: 一.准备API: 一般都采用Json作为数据交换格式,目前各种语言均能输出Json串. ...

  2. Qt 学习之路 2(66):访问网络(2)

    Home / Qt 学习之路 2 / Qt 学习之路 2(66):访问网络(2) Qt 学习之路 2(66):访问网络(2)  豆子  2013年10月31日  Qt 学习之路 2  27条评论 上一 ...

  3. Qt 学习之路 2(67):访问网络(3)

    Qt 学习之路 2(67):访问网络(3) 豆子 2013年11月5日 Qt 学习之路 2 16条评论 上一章我们了解了如何使用我们设计的NetWorker类实现我们所需要的网络操作.本章我们将继续完 ...

  4. Qt 学习之路 2(65):访问网络(1)

    Home / Qt 学习之路 2 / Qt 学习之路 2(65):访问网络(1) Qt 学习之路 2(65):访问网络(1)  豆子  2013年10月11日  Qt 学习之路 2  18条评论 现在 ...

  5. Qt 学习之路 2(72):线程和事件循环

    Qt 学习之路 2(72):线程和事件循环 <理解不清晰,不透彻>  --  有需求的话还需要进行专题学习  豆子  2013年11月24日  Qt 学习之路 2  34条评论 前面一章我 ...

  6. Qt 学习之路 2(71):线程简介

    Qt 学习之路 2(71):线程简介 豆子 2013年11月18日 Qt 学习之路 2 30条评论 前面我们讨论了有关进程以及进程间通讯的相关问题,现在我们开始讨论线程.事实上,现代的程序中,使用线程 ...

  7. Qt 学习之路 2(70):进程间通信

    Qt 学习之路 2(70):进程间通信 豆子 2013年11月12日 Qt 学习之路 2 16条评论 上一章我们了解了有关进程的基本知识.我们将进程理解为相互独立的正在运行的程序.由于二者是相互独立的 ...

  8. Qt 学习之路 2(69):进程

    Qt 学习之路 2(69):进程 豆子 2013年11月9日 Qt 学习之路 2 15条评论 进程是操作系统的基础之一.一个进程可以认为是一个正在执行的程序.我们可以把进程当做计算机运行时的一个基础单 ...

  9. Qt 学习之路 2(35):文件

    Qt 学习之路 2(35):文件 豆子 2013年1月5日 Qt 学习之路 2 12条评论 文件操作是应用程序必不可少的部分.Qt 作为一个通用开发库,提供了跨平台的文件操作能力.从本章开始,我们来了 ...

随机推荐

  1. Android4.0+锁屏程序开发——设置锁屏页面篇

    [如何开发一个锁屏应用] 想要开发一个锁屏应用,似乎很难,其实并没有想象中那么难. 从本质上来说,锁屏界面也只是一个Activity而已,只是这个界面比较特殊,在我们点亮屏幕的时候,这个界面就会出现. ...

  2. resin3.X那些事之resin.conf

    [经验总结]resin那些事之resin.conf ----by johnson 话说与resin打交道很久了,却从未系统了解过.resin一听火了,说:你老兄当真与我打交道很久了?工具.流程如此发达 ...

  3. 【总结整理】原创概念原创idea---摘自《结网》

    假如你有一个原创想法,搜索引擎是否已有现成产品与自己的想法一致,如果有,研究他可以节省很多摸索的时间:若没有,那就是一个货真价实的原创idea: 第一类:受到现有产品的启发,将既有概念进行了转换. 第 ...

  4. axure可用密钥

    axure8.0注册码   激活码:(亲测可用) 用户名:aaa 注册码:2GQrt5XHYY7SBK/4b22Gm4Dh8alaR0/0k3gEN5h7FkVPIn8oG3uphlOeytIajxG ...

  5. 18-printf(*)的输出格式

    #include <bits/stdc++.h> using namespace std; int main(){ for(int i = 0; i < 26; i++){ cout ...

  6. Django框架 之 modelform组件

    Django框架 之 modelform组件 浏览目录 创建mldelform 添加记录 编辑记录 Django框架中的modelform组件 通过名字我们可以看出来,这个组件的功能就是把model和 ...

  7. Android N 新特性

    2016年5月19日,谷歌在美国加州的山景城举办了 Google I/O 开发者大会中发布.2016年6月,Android N正式命名为“牛轧糖” 本届I/O开发者大会上,Google重点介绍了And ...

  8. 开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别(转)

    因CooCox用户数及影响力越来越大,CooCox团队也逐渐提高了对软件及代码协议的重视.在收集整理的过程中,一些归纳好的信息和大家分享一下.首先借用有心人士的一张相当直观清晰的图来划分各种协议:开源 ...

  9. Git代码冲突常见解决方法

    在发布这个配置文件的时候,会发生代码冲突: error: Your local changes to the following files would be overwritten by merge ...

  10. (一)ASP.NET中JavaScript的中英文(多语言)实现方案

    PS: https://github.com/hzlzh/Front-End-Standards/wiki/HTML-CSS-JS-i18n 本文原始思路起源于此网址,请自行查看. 本文只是简单的一个 ...