项目简介:

1,使用Qt设计一款天气预报的程序,主要包括:

  1. 界面显示:当日天气情况、空气质量等级、温湿度等空气指数、每日祝福语以及未来几日天气预报;根据近几日的温度数据绘制温度曲线;支持搜索指定城市功能以及刷新数据功能。
  2. 数据处理:QJson的读取与解析。
  3. 学习和使用Qt的信号与槽。

2,运行效果图(天气预报数据来源于网络):

部分代码整理:

1,温度曲线的绘制

void PaintCurve()
{QPainter painter(ui->curveLb);//反锯齿 使绘制出的线光滑painter.setRenderHint(QPainter::Antialiasing,true);int iTempTotal=0;int high[6]={};QString strHigh;for(int i=0;i<6;++i){strHigh=m_forecast[i].high;strHigh=strHigh.mid(3);strHigh=strHigh.left(2);high[i]=(int)(strHigh.toDouble());iTempTotal+=high[i];}//高温的平均值int iTempAverage=(int)(iTempTotal/6);//算出温度对应的点坐标int pointX[6]={45,133,221,309,397,485};//x坐标的具体计算要结合所设置的控件宽度以及要显示数据的组数int pointY_h[6]={};for(int i=0;i<6;++i){pointY_h[i]=TEMPERATURE_STARTING_COORDINATE - ((high[i]-iTempAverage)* SPAN_INDEX);}QPen pen=painter.pen();pen.setWidth(1);//设置画笔的宽度//高温曲线绘制painter.save();//昨天到今天的数据pen.setColor(QColor(255,170,0));pen.setStyle(Qt::DotLine);painter.setPen(pen);painter.setBrush(QColor(255,170,0));painter.drawEllipse(QPoint(pointX[0],pointY_h[0]),ORIGIN_SIZE,ORIGIN_SIZE);painter.drawEllipse(QPoint(pointX[1],pointY_h[1]),ORIGIN_SIZE,ORIGIN_SIZE);painter.drawLine(pointX[0],pointY_h[0],pointX[1],pointY_h[1]);//今天到未来四天的数据pen.setStyle(Qt::SolidLine);pen.setWidth(1);painter.setPen(pen);for(int i=1;i<5;++i){painter.drawEllipse(QPoint(pointX[i+1],pointY_h[i+1]),ORIGIN_SIZE,ORIGIN_SIZE);painter.drawLine(pointX[i],pointY_h[i],pointX[i+1],pointY_h[i+1]);}painter.restore();
}

其中m_forecast是封装的类Forecast的对象,主要保存天气的数据(或者说是个结构体可能更直观)。

QPainter的使用要保证save()与restore()成对出现,即开始会之前调用下save(),绘制完成后调用下restore()。

2,搜索与刷新

//刷新按钮
void on_refreshBt_clicked()
{//获取城市天气数据GetWeatherInfo(m_pManager);//得到新数据后调用下绘制曲线的控件的刷新,进行绘制ui->curveLb->update();
}//搜索按钮
void on_searchBt_clicked()
{//保存当前城市,当搜索出现错误时,还可以继续显示当前城市m_strCityTemp=m_strCity;m_strCity=ui->cityLineEdit->text();GetWeatherInfo(m_pManager);
}

其中m_pManager是QNetworkAccessManager的一个指针,是网络编程部分的,与其相关的还有另外两个类,大致关系为

对于一个应用程序来说,一个QNetworkAccessManager已经足够了。
以刷新功能为例,通过自己实现的方法GetWeatherInfo去向服务器发送请求获取数据,通过m_pManager的信号得知服务器应答完成并处理数据,内容如下:

//初始化时绑定的信号槽
connect(m_pManager,&QNetworkAccessManager::finished,this,&MainWindow::replyFinished);//GetWeatherInfo的实现
void GetWeatherInfo(QNetworkAccessManager*& manager)
{//根据城市获取城市邮编QString strCityCode=m_tool[m_strCity];//获取失败 或 输入为省份 或 没有覆盖到该城市if(strCityCode=="000000000"){QMessageBox::warning(this,u8"错误",u8"天气:指定城市不存在!",QMessageBox::Ok);return;}//拼好url:链接+城市邮编QUrl jsonUrl(m_strUrl+strCityCode);//发送网络请求manager->get(QNetworkRequest(jsonUrl));
}//网络请求完成后的响应槽函数
void replyFinished(QNetworkReply* reply)
{//获取响应的消息 状态码200表示正常QVariant status_code=reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);//出错if(reply->error()!=QNetworkReply::NoError || status_code!=200){QMessageBox::warning(this,u8"错误",u8"天气:请求数据错误,检查网络连接!",QMessageBox::Ok);return;}//获取数据成功 读取全部数据QByteArray bytes=reply->readAll();//解析json数据ParseJson(bytes);
}

3,QJson的读取与解析

如果前面从网络获取数据成功的话,QByteArray bytes=reply->readAll();bytes就会那到如下样式的内容:

将这些乱乱的数据处理一下,看起来直观些:

篇幅有限就不截全图了,现在key和value就可以非常直观的看出来了(安利一个json解析的链接:https://www.json.cn/)

然后通过ParseJson(bytes)函数去解析数据:

void ParseJson(QByteArray &bytes)
{//首先将bytes数据转换成一个document对象QJsonParseError err;QJsonDocument jsonDoc = QJsonDocument::fromJson(bytes,&err);//转换出错if(err.error!=QJsonParseError::NoError)return;//QJsonObject jsonObj=jsonDoc.object();QString message=jsonObj.value("message").toString();//返回false说明message中没有包含success 即失败if(message.contains("success")==false){QMessageBox::information(this,tr("The Information Of Json_desc"),u8"天气:城市错误!",QMessageBox::Ok);m_strCity=m_strCityTemp;return;}m_today=jsonObj;//解析data中的yesterdayQJsonObject dataObj=jsonObj.value("data").toObject();m_forecast[0]=dataObj.value("yesterday").toObject();//解析data中的forecastQJsonArray forecastArr=dataObj.value("forecast").toArray();//j=0是因为从网上取到的预报数据中是不存在昨天的 即索引0处就是今天 1是明天...int j=0;for(int i=1;i<6;++i){//索引0处表示的是昨天的信息 所以应继续从索引1处开始取数据m_forecast[i]=forecastArr.at(j).toObject();j++;}//更新UI界面数据SetLabelContent();
}

另外项目中在获取城市天气预报的服务中使用的是城市的邮政编码,所以还存在一个输入城市输出邮政编码的方法:

//构造时会去缓存城市名称-城市邮政编码的map
WeatherTool()
{//获取当前程序的相对路径 继而得到城市邮编文件QString fileName=QCoreApplication::applicationDirPath();fileName+="/citycode-2021-06-23.json";//用文本形式以只读的方式打开文件 将数据读取到json中,关闭文件QFile file(fileName);file.open(QIODevice::ReadOnly|QIODevice::Text);QByteArray json=file.readAll();file.close();//按照文件的内容及json的规定 可以将数据分解成一个由城市组成的数组,然后遍历该数组QJsonParseError err;QJsonDocument jsonDoc=QJsonDocument::fromJson(json,&err);QJsonArray citys=jsonDoc.array();for(int i=0;i<citys.size();++i){//将每个城市先转成一个对象,然后访问每个对象的key值为city_code处,得到value后转成string返回,其他同理QString code=citys.at(i).toObject().value("city_code").toString();QString city=citys.at(i).toObject().value("city_name").toString();if(code.size()>0)m_mapCityToCode[city]=code;}
}//传入城市 传出邮编
QString operator[](const QString& city)
{std::map<QString,QString>::iterator iter=m_mapCityToCode.find(city);if(iter==m_mapCityToCode.end())iter=m_mapCityToCode.find(city+u8"市");if(iter!=m_mapCityToCode.end())return iter->second;return "000000000";
}

配置的json文档大致如下:

4,信号与槽

类似于MFC的消息,但要比MFC的消息灵活很多,绑定的信号槽的语法为:
connect(信号发送者,&发了什么信号,信号接收者,&处理信号的函数)
以button为例,基础的用法为:
connect(pBtn,&QPushButton::clicked,this,&ClassName::OnBtnClicked)
信号与槽都为void类型,参数可有可无,信号只需定义无需实现;
信号可以传递,也可绑定多个槽;
信号的参数≥槽的参数,但相等的部分的参数类型必须一一对应。

5,Qt对象树的概念

Qt中的QObject会用对象树管理自己,它会用一个私有变量QList<QObject*>存储子孙后代,如创建一个QObject对象并指定父指针时,就会保存它们的父子关系(这里的父子关系与类的继承无关)。当父对象析构时,会直接析构掉其下的所有子对象。
但事物都有两面性,有好就有坏,针对于对象树,其好处也恰恰是坏处。
如下代码,运行后必崩溃:


关于崩溃的解释:
在函数内声明的临时变量是存储在栈上的,先入后出,所以当main函数执行结束后,会先释放Widget的对象w,而button在声明时已指定了父对象为w,所以当释放w的时候会直接释放掉button;当w释放完成后,栈会去释放button,就会二次析构,又因为button中有些data是new出来的,所以需要delete,所以这也就是为什么崩溃报错在heap上了。

网络天气预报项目笔记(Qt)相关推荐

  1. 基于QT天气预报项目,推荐初学者练手

    文章目录 前言 本项目基于QT平台开发的一款天气预报,一个适合小白练手的项目.使用到了技术有HTTP编程.定位API.天气预报API.JSON解析,unicode转化为汉字.分享给大家一起讨论学习: ...

  2. 项目笔记:4.引入CDN内容分发网络,实现网站静态元素加速

    项目笔记:4.引入CDN内容分发网络,实现网站静态元素加速 squid 1.在192.168.0.6和192.168.0.7上安装squid 开两台虚拟机ip为0.6,0.7 只需搭建本地系统的yum ...

  3. (*长期更新)软考网络工程师学习笔记——Section 6 网络层上篇

    目录 一.网络层的定义 二.IPv4数据报 三.IPv4 (一)分类依据 (二)IP地址分类 (三)网络.主机号位数 (四)特殊IP地址 四.划分子网 五.子网掩码 (一)默认子网掩码 (二)VLSM ...

  4. Qt文档阅读笔记-Qt跨平台库(Qt基本库)

    Qt基本库是所有Qt平台的基础分.他能在所有支持开发的平台和测试平台上跑.这些库在Qt5中已经保持源代码和二进制的兼容. 基本模块(基本库)被其他特殊模块所附加. 下面是Qt基本模块(基本库)的列表: ...

  5. 计算机软考串行和并行公式,2011年计算机软考网络管理员复习笔记第二章

    2011年计算机软考网络管理员复习笔记第二章 第二章 数据通信 (1) 数据通信:两个实体间的数据传输和交换. 2.1数据通信技术 2.1.1 模拟数据通信和数字数据通信 (2) 模拟数据:在某个区间 ...

  6. 瑞吉外卖项目笔记+踩坑1——基础功能

     导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 1 ...

  7. 应用笔记-Qt 程序中使用 Live 20R 指纹采集器

    应用笔记-Qt 程序中使用 Live 20R 指纹采集器 最近一个项目需要用到指纹认证.就在某东上随便搜了个销量比较大的指纹采集器,就是今天这个笔记的主角(Live 20R 指纹采集器).花了几天时间 ...

  8. 基于Django的商城开发项目笔记(一)

    基于Django的商城开发项目笔记(一) 一.环境搭建 1.安装Python:去Python官网下载最新版本Python进行安装,安装时记得勾选将Python加入系统环境变量 2.在命令行输入pip ...

  9. 初出茅庐的小李第113篇博客项目笔记之机智云智能浇花器实战(2)-基础Demo实现

    初出茅庐的小李第112篇博客项目笔记之机智云智能浇花器实战(1)-基础Demo实现 接(1) 继电器实现 继电器原理图 继电器采用的是5V继电器,控制端是RELAY-1 继电器代码实现 #includ ...

最新文章

  1. 阅读Book: MultiObjective using Evolutionary Algorithms (4) --- 3 种方法find Non-dominated set
  2. R Learnilng 十八讲1-6
  3. 鸿蒙股票深度分析,本月华为鸿蒙概念股市回顾分析(3月31日)
  4. [css] 当页面采用rem布局时,如何解决用户设置字体大小造成的页面布局错位?
  5. 讲述一个自学七年Python编程的码农人生
  6. Java无所不能的反射在Android中需要熟练的知识
  7. 高斯双边模糊_OpenCV 学习:9 双边滤波bilateralFilter
  8. java中console_Java:如何从System.Console()获取输入
  9. 详解如何实现一个简单的 vuex
  10. 数据库基础入门知识总结
  11. java实战我爱自学网,白银java教程我要自学网
  12. 【常用方法】ContactsUtil-联系人工具类
  13. TypeScript 之 More on Functions
  14. 设计院总工毕生总结的200条经验
  15. matlab三角形外接圆
  16. 分布式session会话Sticky Sessions
  17. vlc插件详细使用说明
  18. Windows Server 2012 R2 离线安装 .Net Framework3.5
  19. TextCNN文本分类实现(主要是CNN模型的使用)
  20. 计算平均值和标准方差。

热门文章

  1. python和按键精灵自动化测试_自动化测试程序和按键精灵
  2. 维特比算法在隐马尔可夫模型中的应用
  3. 搜索引擎的爬虫技术研究
  4. 视频如何加水印文字?一分钟学会
  5. Android选择/拍照 剪裁 base64/16进制/byte上传图片+PHP接收图片
  6. org.hibernate.TransientObjectException:The given object has a null identifier
  7. vscode使用ssh连接远程Ubuntu服务器(记录)
  8. ubuntu wifi变成问号 网速很慢
  9. elementUI 表格合并单元格-多层级-合并行
  10. 射频百科 | 限幅器的使用指南