QT项目——天气预报

文章目录

  • 前言
  • 一、项目介绍
  • 二、项目基础知识
    • 1. 软件开发网络通信架构
      • 1.1 CS架构 / BS架构
        • 1.1.1 CS架构(客户端-服务器架构)
        • 1.1.2 BS架构(浏览器-服务器架构)
      • 1.2 HTTP 基本概念
    • 2. QT 下 HTTP 编程
        • 2.1 类的解析
        • 2.2 示例程序
    • 3. JSON概念
    • 4. QT 下解析 JSON 数据
      • 4.1 QJsonDocument
      • 4.2 QJsonObject
      • 4.3 QJsonArray
  • 三、代码框架
    • 1. HTTP请求和判断是否连接
    • 2. 获得天气JSON数据
      • 2.1 刷新当天天气数据
      • 2.2 刷新当天天气图标
    • 3. 刷新七天天气
    • 4. 绘制温度曲线图
      • 4.1 事件过滤器
      • 4.2 绘制最高温度
      • 4.3 绘制最低温度

前言

完整代码:天气预报完整代码

一、项目介绍

本项目主要涉及 Qt 界面设计、HTTP 通信、JSON 数据解析、自定义控件绘制温湿度曲线、Qt 信号与槽等的应用,通过调用天气预报API解析 JSON 数据获取未来七天的温湿度、风力强度、天气状态等信息,最后显示在Qt UI界面。

界面展示:

image.png

二、项目基础知识

1. 软件开发网络通信架构

1.1 CS架构 / BS架构

在计算机网络和软件开发中,CS架构(Client-Server Architecture,客户端-服务器架构)和BS架构(Browser-Server Architecture,浏览器-服务器架构)是两种主要的应用程序架构。

1.1.1 CS架构(客户端-服务器架构)

CS架构是一种典型的两层结构,包括客户端和服务器两个部分。在这种架构中,客户端和服务器通过网络进行通信,每部分都有明确的职责。

  1. 客户端:
    • 用户界面通常在客户端呈现。
    • 可以是桌面应用程序、移动应用或专用软件。
    • 负责向服务器发送请求,接收和处理服务器响应。
  2. 服务器:
    • 管理数据和业务逻辑。
    • 处理来自客户端的请求,并发送回响应。
    • 通常承载在远程系统上,如数据库服务器、应用服务器等。
  3. 特点:
    • 需要为每种操作系统或平台单独开发客户端。
    • 高效的数据处理和响应能力。
    • 在客户端设备上占用资源(如内存和处理能力)。
1.1.2 BS架构(浏览器-服务器架构)

BS架构是一种基于Web的三层或多层架构,主要通过Web浏览器作为客户端访问服务器上的应用程序。

  1. 浏览器(客户端):
    • 使用标准Web浏览器(如Chrome、Firefox等)作为客户端。
    • 无需安装额外的软件,使用HTML、CSS和JavaScript显示内容。
  2. 服务器:
    • 和CS架构中的服务器类似,处理业务逻辑和数据存储。
    • 通过Web服务(如HTTP服务器)提供页面和数据。
  3. 特点:
    • 跨平台兼容性强,可以在任何支持Web浏览器的设备上运行。
    • 客户端无需安装专用软件,容易维护和更新。
    • 可能依赖网络性能,因为所有操作都在服务器上进行。

对比

  • 部署和维护:BS架构易于部署和维护,而CS架构通常需要在每个客户端单独安装和更新。
  • 性能:CS架构可以更有效地利用客户端的计算资源,适合高性能要求的应用。BS架构依赖于服务器的性能和网络延迟。
  • 安全性:CS架构中,数据经常在客户端和服务器之间传输,可能需要更复杂的安全措施。BS架构中,敏感数据主要存储在服务器端。
  • 用户体验:CS架构通常能提供更丰富的用户界面和交互功能。BS架构的用户体验受限于Web技术的能力。
    在实际应用中,选择哪种架构取决于具体的业务需求、目标用户群、性能要求以及开发和维护的成本。

1.2 HTTP 基本概念

基本概念

HTTP(超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议。它是万维网 (WWW)的数据通信的基础。了解HTTP的基本概念对于理解现代网络通信至关重要。以下是HTTP的一 些核心概念:

1. 请求与响应

HTTP是一个基于请求-响应模式的协议。客户端(通常是Web浏览器)向服务器发送一个HTTP请求,然后服务器返回一个HTTP响应。请求包含请求的资源(如网页),而响应包含请求的资源的内容。

2. HTTP方法

HTTP定义了一系列的方法来表明对资源的不同操作,最常用的包括:

  • GET: 用于请求资源。

  • POST: 用于提交数据给服务器(例如,表单数据)。

  • PUT: 用于上传文件或内容。

  • DELETE: 用于请求删除资源。

  • HEAD: 用于获取资源的元信息,而不是资源本身。

3. 状态码

服务器对请求的响应中包含一个状态码,它表示请求的成功或失败,以及失败的原因。常见的状态码包括:

  • 200 OK: 请求成功。
  • 404 Not Found: 请求的资源未找到。
  • 500 Internal Server Error: 服务器内部错误。
  • 301 Moved Permanently: 请求的资源已永久移动到新位置。

4. URL(统一资源定位符)

URL是Web上资源的地址。它指定了资源的位置以及用于访问资源的协议(例如,http://)。

5. HTTP头

HTTP请求和响应包含头部信息,这些信息包括元数据,如内容类型、内容长度、服务器信息、客户端信息等。例如, Content-Type 头部指示响应中的媒体类型(如text/html,application/json)。

6. 无状态协议

HTTP是一个无状态协议,这意味着服务器不会保留任何请求的数据(状态)。然而,通过使用如 Cookies这样的机制,可以在多个请求之间维持状态。

7. 安全性(HTTPS)

HTTPS是HTTP的安全版本,它在HTTP和TCP层之间增加了一个加密层(通常是SSL/TLS)。这提供了数据传输的加密和更好的安全性。

8. RESTful API

RESTful是一种使用HTTP协议的Web服务设计风格,它利用HTTP的方法来实现API的不同操作。在RESTful架构中,每个URL代表一个资源,并使用HTTP的方法(如GET, POST)来处理这些资源。

9. Session和Cookies

由于HTTP本身是无状态的,Cookies和会话(Session)被用来在多个请求之间存储用户数据,从而为用户提供连贯的体验。

2. QT 下 HTTP 编程

Qt 中的 HTTP 编程主要涉及使用 Qt 的网络模块来进行 HTTP 请求和处理 HTTP 响应。Qt 提供了一系列类来处理网络通信,其中最常用的类是 QNetworkAccessManagerQNetworkRequestQNetworkReply 以及相关的支持类。

2.1 类的解析

1. QNetworkAccessManager

QNetworkAccessManager 类允许应用程序发送网络请求并接收回复。

网络访问应用程序编程接口(API)是围绕一个 QNetworkAccessManager 对象构建的,该对象保存着它所发送请求的通用配置和设置。它包含代理和缓存配置,以及与此类问题相关的信号,还有可用于监控网络操作进度的回复信号。对于整个 Qt 应用程序来说,一个 QNetworkAccessManager 实例通常就足够了。由于 QNetworkAccessManager 基于 QObject,所以它只能在其所属的线程中使用。

一旦创建了一个 QNetworkAccessManager 对象,应用程序就可以使用它通过网络发送请求。提供了一组标准函数,这些函数接收一个请求以及可选的数据,并各自返回一个 QNetworkReply 对象。返回的这个对象用于获取针对相应请求所返回的任何数据。

一个简单的从网络下载的操作可以通过以下方式完成:

QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished,this, &MyClass::replyFinished);manager->get(QNetworkRequest(QUrl("http://qt-project.org")));

QNetworkAccessManager 具有异步应用程序编程接口(API)。当上面的 replyFinished 槽函数被调用时,它所接收的参数是包含已下载数据以及元数据(头部信息等)的 QNetworkReply 对象。

注意:在请求完成之后,用户有责任在适当的时候删除 QNetworkReply 对象。不要在连接到 finished() 的槽函数内部直接删除它。你可以使用 deleteLater() 函数。

注意:QNetworkAccessManager 会对它接收到的请求进行排队。并行执行的请求数量取决于协议。目前,对于桌面平台上的 HTTP 协议,针对一个主机 / 端口组合,会并行执行 6 个请求。

2. QNetworkRequest

QNetworkRequest 类保存着一个要通过 QNetworkAccessManager 发送的请求。

QNetworkRequest 是网络访问应用程序编程接口(API)的一部分,它是一个用于保存通过网络发送请求所需信息的类。它包含一个 URL 以及一些可用于修改请求的辅助信息。

3. QNetworkReply

QNetworkReply 类包含了使用 QNetworkAccessManager 发送请求的数据和头部信息。

QNetworkReply 类还包含了与使用 QNetworkAccessManager 发布的请求相关的数据和元数据。与 QNetworkRequest 类似,它包含一个 URL 和 头部信息(既有解析后的形式,也有原始形式)、一些有关回复状态的信息以及回复本身的内容。

QNetworkReply 是一个顺序访问的 QIODevice,这意味着一旦从该对象读取了数据,设备就不会再保留这些数据。因此,如果应用程序需要这些数据,就有责任自行保存。每当从网络接收到更多数据并进行处理时,就会发出 readyRead() 信号。

当接收到数据时,也会发出 downloadProgress() 信号,但如果对内容进行了任何转换(例如,解压并去除协议开销),该信号中包含的字节数可能并不代表实际接收到的字节数。

尽管 QNetworkReply 是一个连接到回复内容的 QIODevice,但它也会发出 uploadProgress() 信号,该信号用于指示具有此类内容的操作的上传进度。

注意:不要在连接到 error()finished() 信号的槽函数中删除该对象。请使用 deleteLater()

2.2 示例程序
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 创建一个QNetworkAccessManager 对象QNetworkAccessManager manager;// 请求的UrlQNetworkRequest request(QUrl("http://example.com"));// 获取请求内容 返回一个QNetworkReply对象QNetworkReply *reply = manager.get(request);QObject::connect(reply, &QNetworkReply::finished, [&]() {if (reply->error()) {qDebug() << "Error:" << reply->errorString();return;}// 从设备中读取所有剩余数据,并将其作为字节数组返回。QString response = reply->readAll();qDebug() << "Response:" << response;});return a.exec();
}

3. JSON概念

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它易于人阅读和编写,同时也易于机器解析和生成。JSON是基于JavaScript的一个子集,尽管它是独立于语言的,且有多种语言支持。 JSON常用于网络应用程序中的数据传输,尤其是在Web应用程序中与后端服务器通信。 使用JSON的原因总结如下:

原因描述
易于阅读和编写JSON的结构简单、清晰,对人类来说易于阅读和编写。
轻量级数据格式相较于XML等标记语言,JSON更轻量,使用更少的符号,数据体积更小。
易于解析和生成大多数编程语言都提供了解析和生成JSON的内置支持或库。
跨语言支持JSON是独立于语言的,被广泛支持和使用在多种编程语言中。
网络友好JSON格式适合Web环境,易于通过网络传输,是Web API的常用格式。
数据互操作性作为一种标准化格式,JSON提高了不同系统间的数据互操作性。

BS/CS开发过程中,会使用不同的编程语言,JSON作为数据传输的标准化格式,方便程序员协议约定和数据处理,以下是不同编程语言处理JSON的方案

语言/平台JSON处理库/接口特点/描述
CJansson提供JSON的编码、解码和处理功能
C++nlohmann/json现代C++(从C++11开始)的JSON库,易于使用
javaJackson强大的JSON处理库,支持JSON的序列化和反序列化
GsonGoogle提供的JSON序列化/反序列化库
PythonjsonPython标准库中的JSON处理模块
QtQJsonDocumentQt框架中用于JSON处理的类
QJsonObject用于表示JSON对象的Qt类
QJsonArray用于表示JSON数组的Qt类
Androidorg.jsonAndroid SDK自带的JSON处理类,提供基础JSON操作功能
iOSJSONSerializationApple提供的用于JSON处理的类,部分Swift和Objective-C标准库中

4. QT 下解析 JSON 数据

在Qt中生成和解析JSON数据涉及使用QJsonDocumentQJsonObjectQJsonArray类。

4.1 QJsonDocument

QJsonDocument类提供了一种读写JSON文档的方法。

QJsonDocument是一个类,它封装了一个完整的JSON文档,并且能够以UTF-8编码的基于文本的表示形式以及Qt自身的二进制格式来读写该文档。

可以使用QJsonDocument::fromJson()将一个基于文本表示的JSON文档转换为QJsonDocumenttoJson()则可将其转换回文本形式。该解析器速度非常快且效率高,它会将JSON转换为Qt所使用的二进制表示形式。

可以通过!isNull()来查询已解析文档的有效性。

可以使用isArray()isObject()来查询一个文档是否包含数组或对象。文档中包含的数组或对象可以通过array()object()获取,然后进行读取或操作。

还可以使用fromBinaryData()fromRawData()从存储的二进制表示形式来创建一个文档。

4.2 QJsonObject

QJsonObject 类封装了一个 JSON 对象。

一个 JSON 对象是一个键值对的列表,其中键是唯一的字符串,而值由 QJsonValue 表示。

一个 QJsonObject 可以与一个 QVariantMap 相互转换。你可以使用 size() 查询(键,值)对的数量,使用 insert()remove() 对其中的条目进行插入和删除操作,并且可以使用标准的 C++ 迭代器模式遍历其内容。

QJsonObject 是一个隐式共享类,只要它未被修改,就会与其创建时所源自的文档共享数据。

你可以通过 QJsonDocument 将该对象与基于文本的 JSON 进行相互转换。

4.3 QJsonArray

QJsonArray 类封装了一个 JSON 数组。

一个 JSON 数组是一个值的列表。可以通过在数组中插入和删除 QJsonValue 来操作该列表。

一个 QJsonArray 可以与一个 QVariantList 相互转换。你可以使用 size() 查询条目的数量,使用 insert()removeAt() 对其中的条目进行插入和删除操作,并且可以使用标准的 C++ 迭代器模式遍历其内容。

QJsonArray 是一个隐式共享类,只要它未被修改,就会与其创建时所源自的文档共享数据。

你可以通过 QJsonDocument 将该数组与基于文本的 JSON 进行相互转换。

三、代码框架

1. HTTP请求和判断是否连接

流程图:

image.png

在这里用的天气API网址是易客云,直接百度搜索即可。

HTTP请求和判断代码示例:

#include <QNetworkReply>
#include <QMessageBox>public slots:void readHttpRply();private:QNetworkReply *reply;Weather::Weather(QWidget *parent) :QWidget(parent),ui(new Ui::Weather)
{ui->setupUi(this);// http 请求QNetworkAccessManager *manager = new QNetworkAccessManager(this);QUrl urlItBoy("http://v1.yiketianqi.com/free/week?unescape=1&appid=18819752&appsecret=Telvfll9");// 获得数据QNetworkRequest res(urlItBoy);reply = manager->get(res);connect(reply, &QNetworkReply::finished, this, &Weather::readHttpRply);
}void Weather::readHttpRply()
{   /* 从reply对象中获取HTTP状态码,并将其转换为整数 */int resCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();if (reply->error() == QNetworkReply::NoError && resCode == 200){QByteArray data = reply->readAll();qDebug() << QString::fromUtf8(data);}else{QMessageBox mes;mes.setWindowTitle("错误");mes.setText("网络请求失败");mes.setStyleSheet("QPushButton {color:red}");mes.setStandardButtons(QMessageBox::Ok);mes.exec();}
}

image.png

编译运行结果:获得当天的天气

image.png

2. 获得天气JSON数据

2.1 刷新当天天气数据

通过解析天气 API 的 JSON 数据,读取到 UI 界面。

代码示例:

#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>private:void parseWeatherJsonData(QByteArray rawData);void Widget::parseWeatherJsonData(QByteArray rawData)
{QJsonDocument jsonObj = QJsonDocument::fromJson(rawData);if (!jsonObj.isNull() && jsonObj.isObject()){QJsonObject objRoot = jsonObj.object();//解析日期1QString date = objRoot["date"].toString();QString week = objRoot["week"].toString();ui->labelCurrentDate->setText(date+"  "+week);//解析城市名称QString cityName = objRoot["city"].toString();ui->labelCity->setText(cityName+"市");//解析当前温度QString currentTemp = objRoot["tem"].toString();ui->labelTmp->setText(currentTemp+"℃");ui->labelTempRange->setText(objRoot["tem2"].toString()+"~"+objRoot["tem1"].toString());//解析天气类型ui->labelweatherType->setText(objRoot["wea"].toString());//感冒指数ui->labelGanmao->setText(objRoot["air_tips"].toString());//风向ui->labelFXType->setText(objRoot["win"].toString());//风力ui->labelFXTypeData->setText(objRoot["win_speed"].toString());//PM2.5ui->labelPM25Data->setText(objRoot["air_pm25"].toString());//湿度ui->labelShiduData->setText(objRoot["humidity"].toString());//空气质量ui->labelairData->setText(objRoot["air_level"].toString());}
}void Widget::readHttpRply()
{int resCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();if (reply->error() == QNetworkReply::NoError && resCode == 200){QByteArray data = reply->readAll();parseWeatherJsonData(data);qDebug() << QString::fromUtf8(data);}else{QMessageBox mes;mes.setWindowTitle("错误");mes.setText("网络请求失败");mes.setStyleSheet("QPushButton {color:red}");mes.setStandardButtons(QMessageBox::Ok);mes.exec();}
}

2.2 刷新当天天气图标

将所有天气图标存放到 QMap 容器中,模板参数为<QString,QString>

代码示例:

private:QMap<QString,QString> mTypeMap;Weather::Weather(QWidget *parent) :QWidget(parent),ui(new Ui::Weather)
{//根据keys,设置icon的路径mTypeMap.insert("暴雪",":/images/type/BaoXue.png");mTypeMap.insert("暴雨",":/images/type/BaoYu. png");mTypeMap.insert("暴雨到大暴雨",":/images/type/BaoYuDaoDaBaoYu.png");mTypeMap.insert("大暴雨",":/images/type/DaBaoYu.png");mTypeMap.insert("大暴雨到特大暴雨",":/images/type/DaBaoYuDaoTeDaBaoYu.png");mTypeMap.insert("大到暴雪",":/images/type/DaDaoBaoXue.png");mTypeMap.insert("大雪",":/images/type/DaXue.png");mTypeMap.insert("大雨",":/images/type/DaYu.png");mTypeMap.insert("冻雨",":/images/type/DongYu.png");mTypeMap.insert("多云",":/images/type/DuoYun.png");mTypeMap.insert("浮沉",":/images/type/FuChen.png");mTypeMap.insert("雷阵雨",":/images/type/LeiZhenYu.png");mTypeMap.insert("雷阵雨伴有冰雹",":/images/type/LeiZhenYuBanYouBingBao.png");mTypeMap.insert("霾",":/images/type/Mai.png");mTypeMap.insert("强沙尘暴",":/images/type/QiangShaChenBao.png");mTypeMap.insert("晴",":/images/type/Qing.png");mTypeMap.insert("沙尘暴",":/images/type/ShaChenBao.png");mTypeMap.insert("特大暴雨",":/images/type/TeDaBaoYu.png");mTypeMap.insert("undefined",":/images/type/undefined.png");mTypeMap.insert("雾",":/images/type/Wu.png");mTypeMap.insert("小到中雪",":/images/type/XiaoDaoZhongXue.png");mTypeMap.insert("小到中雨",":/images/type/XiaoDaoZhongYu.png");mTypeMap.insert("小雪",":/images/type/XiaoXue.png");mTypeMap.insert("小雨",":/images/type/XiaoYu.png");mTypeMap.insert("雪",":/images/type/Xue.png");mTypeMap.insert("扬沙",":/images/type/YangSha.png");mTypeMap.insert("阴",":/images/type/Yin.png");mTypeMap.insert("雨",":/images/type/Yu.png");mTypeMap.insert("雨夹雪",":/images/type/YuJiaXue.png");mTypeMap.insert("阵雪",":/images/type/ZhenXue.png");mTypeMap.insert("阵雨",":/images/type/ZhenYu.png");mTypeMap.insert("中到大雪",":/images/type/ZhongDaoDaXue.png");mTypeMap.insert("中到大雨",":/images/type/ZhongDaoDaYu.png");mTypeMap.insert("中雪",":/images/type/ZhongXue.png");mTypeMap.insert("中雨",":/images/type/ZhongYu.png");
}void Widget::parseWeatherJsonData(QByteArray rawData)
{if (!jsonObj.isNull() && jsonObj.isObject()){//解析天气类型ui->labelWeatherIcon->setPixmap(mTypeMap[objRoot["wea"].toString()]);ui->labelweatherType->setText(objRoot["wea"].toString());}
}

编译运行结果:

image.png

3. 刷新七天天气

定义一个 QList 容器,模板参数为<QLabel *>,用来存放每日的天气情况。

代码示例:day.h

#ifndef DAY_H
#define DAY_H#include <QString>class Day
{
public:Day();QString mDate;QString mWeek;QString mCity;QString mTemp;QString mWeathType;QString mTempLow;QString mTempHigh;QString mTips;QString mFx;QString mFl;QString mPm25;QString mHu;QString mAirq;
};#endif // DAY_H

核心代码:

public:Day days[7];QList<QLabel *> mDateList;QList<QLabel *> mWeekList;QList<QLabel *> mIconList;QList<QLabel *> mWeaTypeList;QList<QLabel *> mAirqList;QList<QLabel *> mFxList;QList<QLabel *> mFlList;private:void parseWeatherJsonDataNew(QByteArray rawData);void updateUI();Weather::Weather(QWidget *parent) :QWidget(parent),ui(new Ui::Weather)
{mWeekList << ui->labelday0 << ui->labelday1<< ui->labelday2 << ui->labelday3<< ui->labelday4 << ui->labelday5;mDateList << ui->labelDate0 << ui->labelDate1<< ui->labelDate2 << ui->labelDate3<< ui->labelDate4 << ui->labelDate5;mIconList << ui->labelWeaterIcon0 << ui->labelWeaterIcon1<< ui->labelWeaterIcon2 << ui->labelWeaterIcon3<< ui->labelWeaterIcon4 << ui->labelWeaterIcon5;mWeaTypeList << ui->lbweatherTypeDate0 << ui->lbweatherTypeDate1<< ui->lbweatherTypeDate2 << ui->lbweatherTypeDate3<< ui->lbweatherTypeDate4 << ui->lbweatherTypeDate5;mAirqList << ui->labelairq0 << ui->labelairq1 << ui->labelairq2<< ui->labelairq3 << ui->labelairq4 << ui->labelairq5;mFxList << ui->labelFX0 << ui->labelFX1 << ui->labelFX2<< ui->labelFX3 << ui->labelFX4 << ui->labelFX5;mFlList << ui->labelFL0 << ui->labelFL1 << ui->labelFL2<< ui->labelFL3 << ui->labelFL4 << ui->labelFL5;
}// 解析json数据 七天数据
void Weather::parseWeatherJsonDataNew(QByteArray rawData)
{// 将JSON作为UTF-8编码的JSON文档进行解析,并基于它创建一个 QJsonDocumentQJsonDocument jsonDoc = QJsonDocument::fromJson(rawData);// 解析对象if(!jsonDoc.isNull() && jsonDoc.isObject()){QJsonObject jsonRoot = jsonDoc.object();days[0].mCity = jsonRoot["city"].toString();days[0].mPm25 = jsonRoot["aqi"].toObject()["pm25"].toString();// 解析数组if(jsonRoot.contains("data") && jsonRoot["data"].isArray()){// 转换类型为QT表示JSON数组的数据类型QJsonArray weaArray = jsonRoot["data"].toArray();for(int i = 0; i < weaArray.size(); i++){// 转换类型为QT表示JSON对象的数据类型QJsonObject obj = weaArray[i].toObject();days[i].mDate = obj["date"].toString();days[i].mWeek = obj["week"].toString();days[i].mWeathType = obj["wea"].toString();days[i].mTemp = obj["tem"].toString();days[i].mTempLow = obj["tem2"].toString();days[i].mTempHigh = obj["tem1"].toString();days[i].mFx = obj["win"].toArray()[0].toString();days[i].mFl = obj["win_speed"].toString();days[i].mAirq = obj["air_level"].toString();days[i].mTips = obj["air_tips"].toString();days[i].mHu = obj["humidity"].toString();}}}// 更新界面updateUI();
}void Weather::updateUI()
{QPixmap pixmap;// 解析当前日期ui->labelCurrentDate->setText(days[0].mDate + " " + days[0].mWeek);// 解析城市名词ui->labelCity->setText(days[0].mCity + "市");// 解析当前温度ui->labelTmp->setText(days[0].mTemp + "℃");ui->labelTempRange->setText(days[0].mTempLow + "℃" + "~"  + days[0].mTempHigh +  "℃");// 解析天气类型ui->labelweatherType->setText(days[0].mWeathType);ui->labelWeatherIcon->setPixmap(mTypeMap[days[0].mWeathType]);// 解析感冒指数ui->labelGanmao->setText(days[0].mTips);// 解析风向ui->labelFXType->setText(days[0].mFx);// 解析风力ui->labelFXTypeData->setText(days[0].mFl);// 解析PM2.5ui->labelPM25Data->setText(days[0].mPm25);// 解析湿度ui->labelShiduData->setText(days[0].mHu);// 解析空气质量ui->labelairData->setText(days[0].mAirq);ui->lbweatherTypeDate3->setText(days[3].mWeathType);ui->lbweatherTypeDate0->setText(days[0].mWeathType);for(int i = 0; i < 6; i++){mWeekList[i]->setText(days[i].mWeek);mWeekList[0]->setText("今天");mWeekList[1]->setText("明天");mWeekList[2]->setText("后天");QStringList dayList = days[i].mDate.split("-");mDateList[i]->setText(dayList.at(1) + "-" + dayList.at(2));// 缩放图片大小和label大小能匹配int index = days[i].mWeathType.indexOf("转");if(index != -1){pixmap = mTypeMap[days[i].mWeathType.left(index)];}else{pixmap = mTypeMap[days[i].mWeathType];}pixmap = pixmap.scaled(mIconList[i]->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);mIconList[i]->setMaximumHeight(50);mIconList[i]->setMaximumWidth(ui->widget02->width()/6.5);mIconList[i]->setPixmap(pixmap);mWeaTypeList[i]->setText(days[i].mWeathType);QString airQ = days[i].mAirq;mAirqList[i]->setText(airQ);if(airQ == "优"){mAirqList[i]->setStyleSheet("background-color:rgb(150, 213, 32);border-radius: 7px;color: rgb(230, 230, 230)");}if(airQ == "良"){mAirqList[i]->setStyleSheet("background-color:rgb(255, 170, 127);border-radius: 7px;color: rgb(230, 230, 230)");}if(airQ == "轻度污染"){mAirqList[i]->setStyleSheet("background-color:rgb(170, 200, 129);border-radius: 7px;color: rgb(230, 230, 230)");}if(airQ == "中度污染"){mAirqList[i]->setStyleSheet("background-color:rgb(255, 17, 17);border-radius: 7px;color: rgb(230, 230, 230)");}if(airQ == "重度污染"){mAirqList[i]->setStyleSheet("background-color:rgb(153, 0, 0);border-radius: 7px;color: rgb(230, 230, 230)");}mFxList[i]->setText(days[i].mFx);index = days[i].mFl.indexOf("转");if(index != -1){mFlList[i]->setText(days[i].mFl.left(index));}else{mFlList[i]->setText(days[i].mFl);}}
}

编译运行结果:

image.png

4. 绘制温度曲线图

4.1 事件过滤器

API原型:

bool QObject::eventFilter(QObject *watched, QEvent *event)

如果此对象已被安装为受监视对象的事件过滤器,则对事件进行筛选。

在重新实现此函数时,如果你想要滤除该事件,即阻止它被进一步处理,返回 “真”;否则返回 “假”。

QObject 对象安装事件过滤器:对象用 installEventFilter() 后,所有达到目标控件的事件都首先到达监视对象的 eventFilter() 函数。如果一个对象有多个事件过滤器,过滤器按顺序激活,先到达最近安装的监视对象,最后到达最先安装的监视对象。

代码示例:

protected:bool eventFilter(QObject *watched,QEvent *event);Weather::Weather(QWidget *parent) :QWidget(parent),ui(new Ui::Weather)
{// 安装事件过滤器ui->widget0404->installEventFilter(this);ui->widget0405->installEventFilter(this);
}// watched 受监控对象 event 过滤的事件
bool Weather::eventFilter(QObject *watched, QEvent *event)
{// 满足条件则执行相应操作if(watched == ui->widget0404 && event->type() == QEvent::Paint){drawTempLineHigh();return true;}if(watched == ui->widget0405 && event->type() == QEvent::Paint){drawTempLineLow();return true;}return QWidget::eventFilter(watched,event);
}

4.2 绘制最高温度

整体思路:

选取一个参照物,算出其 x 轴位置,算出组件的中间位置,温度的平均值,根据获取到的温度减去平均值得到的值乘以 2 获得偏移值,最后结合组件的中间值和偏移值算出 y 轴位置,描点、连线。

代码示例:

void Weather::drawTempLineHigh()
{QPainter painter(ui->widget0404);// 抗锯齿painter.setRenderHint(QPainter::Antialiasing,true); // 设置画刷painter.setBrush(Qt::yellow);// 设置画笔painter.setPen(Qt::yellow);int ave;  // 平均值int sum = 0; // 总数int offSet = 0; // 偏移值int middle = ui->widget0404->height()*0.7; // 中间位置for (int i = 0; i < 6; i++) {sum += days[i].mTempHigh.toInt();}ave = sum / 6;// 定义6个点QPoint points[6];for (int i = 0; i < 6; i++) {// 以mAirqList为参照算出 x 位置points[i].setX(mAirqList[i]->x() + mAirqList[i]->width()/2);// 算出偏移量 (最高温度 - 平均温度) * 2offSet = (days[i].mTempHigh.toInt() - ave)*2;// 算出 Y 位置 中值 - 偏移量points[i].setY(middle - offSet);// 画出6个点painter.drawEllipse(QPoint(points[i]),3,3);// 画出当天温度painter.drawText(points[i].x() - 15,points[i].y()-15,days[i].mTempHigh + "°");}for (int i = 0; i < 5; i++) {// 点与点之间连线painter.drawLine(points[i],points[i+1]);}
}

4.3 绘制最低温度

代码示例:

// 绘制最低温度曲线
// 绘制最低温度曲线
void Weather::drawTempLineLow()
{QPainter painter(ui->widget0405);// 抗锯齿painter.setRenderHint(QPainter::Antialiasing,true);// 设置画刷painter.setBrush(QColor(70,192,203));// 设置画笔painter.setPen(QColor(70,192,203));int ave;int sum = 0;int offSet = 0;int middle = ui->widget0405->height()*0.7;for (int i = 0; i < 6; i++) {sum += days[i].mTempLow.toInt();}ave = sum / 6;// 定义6个点QPoint points[6];for (int i = 0; i < 6; i++) {points[i].setX(mAirqList[i]->x() + mAirqList[i]->width()/2);offSet = (days[i].mTempLow.toInt() - ave)*2;points[i].setY(middle - offSet);// 画出6个点painter.drawEllipse(QPoint(points[i]),3,3);// 画出当天温度painter.drawText(points[i].x() - 15,points[i].y()-15,days[i].mTempLow + "°");}for (int i = 0; i < 5; i++) {// 画出两点之间的线painter.drawLine(points[i],points[i+1]);}
}

编译运行结果:

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/21752.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最优化方法-牛顿法

牛顿法 泰勒级数 泰勒级数展开 $$ \begin{aligned} f(x)&\lim\limits_{n\rightarrow \infin}\sum\limits_{i1}n\frac{1}{n!}f{(n)}(x_0)(x-x_0)^n\ &f(x_0)f’(x_0)(x-x_0)\frac{f’(x_0)}{2!}(x-x_0)2\cdots\frac{1}{n!}fn(x_0)(x-x_0)^n\ &\quad~ O\left[(x-x_…

论文笔记(七十二)Reward Centering(二)

Reward Centering&#xff08;二&#xff09; 文章概括摘要2 简单的奖励中心 文章概括 引用&#xff1a; article{naik2024reward,title{Reward Centering},author{Naik, Abhishek and Wan, Yi and Tomar, Manan and Sutton, Richard S},journal{arXiv preprint arXiv:2405.0…

halcon机器视觉深度学习对象检测,物体检测

目录 效果图操作步骤软件版本halcon参考代码本地函数 get_distinct_colors()本地函数 make_neighboring_colors_distinguishable() 效果图 操作步骤 首先要在Deep Learning Tool工具里面把图片打上标注文本&#xff0c; 然后训练模型&#xff0c;导出模型文件 这个是模型 mod…

MySQL修改JSON格式数据示例

最近发现有个数据是用JSON格式直接存到表格里面的&#xff0c;大概就是下面这样的 然后需要修改里面某个属性的值&#xff0c;一开始我想的是 REPLACE 替换 UPDATE test_1 SET content REPLACE(content, {"age": 15, "name": "w5"}, {"ag…

第4章 信息系统架构(二)

4.2 系统架构 信息系统架构是一种体系结构&#xff0c;它反映了一个组织信息系统的各个组成部分之间的关系&#xff0c;以及信息系统与相关业务、信息系统与相关技术之间的关系。 4.2.1 架构定义 对于大规模的复杂系统来说&#xff0c;对总体的系统结构设计比起对计算算法和…

AI 时代:探索大语言模型与核心技术

引言 在当今科技快速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;正成为推动创新和变革的重要力量。从能够理解和生成自然语言的大语言模型&#xff08;LLM&#xff09;&#xff0c;到具有自我学习能力的生成式预训练转换器&#xff08;GPT&#xff09;&#xf…

Python----数据结构(单链表:节点,是否为空,长度,遍历,添加,删除,查找)

一、链表 链表是一种线性数据结构&#xff0c;由一系列按特定顺序排列的节点组成&#xff0c;这些节点通过指针相互连接。每个节点包含两部分&#xff1a;元素和指向下一个节点的指针。其中&#xff0c;最简单的形式是单向链表&#xff0c;每个节点含有一个信息域和一个指针域&…

10、k8s对外服务之ingress

service和ingress的作用 service的作用 NodePort&#xff1a;会在每个节点开放一个端口&#xff0c;端口号30000-32767。 也是只能用于内网访问&#xff0c;四层转发。实现负载均衡。不能基于域名进行访问。 clusterip&#xff1a;service的默认类型&#xff0c;只能在集群…

Linux-ubuntu系统移植之Uboot启动流程

Linux-ubuntu系统移植之Uboot启动流程 一&#xff0c;Uboot启动流程1.Uboot的两阶段1.1.第一阶段1.11.硬件初始化1.12.复制 U-Boot 到 RAM1.13.跳转到第二阶段 1.2.第二阶段1.21.C 语言环境初始化1.22. 硬件设备初始化1.23. 加载环境变量1.24. 显示启动信息1.25. 等待用户输入&…

H3C交换机路由器防火墙FTP/TFTP服务器搭建。

软件介绍。 3CDaemon 2.0 - Download 3CDaemon 是一款集成了多种网络服务功能的工具软件&#xff0c;主要用于网络管理和文件传输&#xff0c;支持TFTP、FTP、Syslog等多种协议&#xff0c;广泛应用于网络设备的配置和管理。 1. 主要功能 TFTP服务器&#xff1a;支持TFTP协议…

Docker Mysql 数据迁移

查看启动命令目录映射 查看容器名称 docker ps查看容器的启动命令 docker inspect mysql8.0 |grep CreateCommand -A 20如下图所示:我这边是把/var/lib/mysql 目录映射到我宿主机的/mnt/mysql/data目录下,而且我的数量比较大使用方法1的话时间比较久,所以我采用方法2 如果没…

[Windows] WPS 2024冬季更新版(版本号19770)

[Windows] WPS 2024冬季更新版 链接&#xff1a;https://pan.xunlei.com/s/VOJQrS4UCz5639Oan7pu1X84A1?pwdg8ad# WPS灵犀正式上线DeepSeek R1&#xff01;告别服务器超时&#xff0c;办公效率飙升300%&#xff01; 2025年2月14日&#xff0c;WPS官方宣布全面接入DeepSeek …

图解循环神经网络(RNN)

目录 1.循环神经网络介绍 2.网络结构 3.结构分类 4.模型工作原理 5.模型工作示例 6.总结 1.循环神经网络介绍 RNN&#xff08;Recurrent Neural Network&#xff0c;循环神经网络&#xff09;是一种专门用于处理序列数据的神经网络结构。与传统的神经网络不同&#xff0c…

【队列】循环队列(Circular Queue)详解

文章目录 一、循环队列简介二、循环队列的判空和判满三、循环队列的实现leetcode 622. 设计循环队列 一、循环队列简介 在实际开发中&#xff0c;队列是一种常用的数据结构&#xff0c;而循环队列&#xff08;Circular Queue&#xff09;则一般是一种基于数组实现的队列&#x…

vmware虚拟机Ubuntu Desktop系统怎么和我的电脑相互复制文件、内容

1、先安装vmware workstation 17 player&#xff0c;然后再安装Ubuntu Desktop虚拟机&#xff0c;然后再安装vmware tools&#xff0c;具体可以参考如下视频&#xff1a; VMware虚拟机与主机实现文件共享&#xff0c;其实一点也不难_哔哩哔哩_bilibili 2、本人亲自试过了&…

Netty入门详解

引言 Netty 是一个基于 Java 的高性能、异步事件驱动的网络应用框架&#xff0c;用于快速开发可维护的高性能网络服务器和客户端。它提供了一组丰富的 API&#xff0c;使得开发人员能够轻松地处理各种网络协议&#xff0c;如 TCP、UDP 等&#xff0c;并且支持多种编解码方式&a…

DeepSeek 助力 Vue 开发:打造丝滑的点击动画(Click Animations)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

Spring-GPT智谱清言AI项目(附源码)

一、项目介绍 本项目是Spring AI第三方调用整合智谱请言&#xff08;官网是&#xff1a;https://open.bigmodel.cn&#xff09;的案例&#xff0c;回答响应流式输出显示&#xff0c;这里使用的是免费模型&#xff0c;需要其他模型可以去 https://www.bigmodel.cn/pricing 切换…

DeepSeek智能测试知识库助手PRO版:多格式支持+性能优化

前言 测试工程师在管理测试资产时,需要面对多种文档格式、大量文件分类及知识库的构建任务。为了解决这些问题,我们升级了 DeepSeek智能测试知识库助手,不仅支持更多文档格式,还加入了 多线程并发处理 和 可扩展格式支持,大幅提升处理性能和灵活性。 主要功能亮点: 多格…

【Python游戏】双人简单对战游戏

以下是一个使用 Python 的 pygame 库实现的简单对战游戏示例&#xff0c;游戏中玩家可以控制两个角色进行对战&#xff0c;并且支持自定义图片(最好使用无底色的png图片)。完整源码以及实现思路&#xff1a; import pygame import os# 初始化 Pygame pygame.init()# 设置游戏窗…