QT项目—天气预报

QT项目—天气预报

1.项目描述

在右上角输入要查询的城市,然后点击查询按钮,就会发送 Http 请求服务器,请求回来的天气数据为 JSON 格式通过解析 JSON 可以获取城市天气信息,并且更新到UI上
具体功能:
发送HTTP请求(GET请求),从国家气象局提供的API接口中获取到JSON格式的天气数据;
使用QT提供的解析JSON数据的QJson类来解析数据,将数据更新到项目界面上;
可查看昨天、今天以及未来4天的详细天气数据,空气质量、风向风力、湿度、感冒指数;
根据每天高低温度绘制温度曲线,对绘图控件安装事件过滤器,重写控件事件;
实现城市模糊搜索和窗口跟随鼠标移动功能;

效果演示:
在这里插入图片描述

技术点:界面的设置合理,HTTP请求,JSON数据,事件,绘图,资源文件

项目开始从第7步项目 开始,前面6点为运用到的知识的讲解
项目源文件及资源项目


2、JSON

2.1、简介

学习链接:菜鸟JSON教程json基础

问题:客户端和服务端之间通信采用什么数据格式合适,

​ 比如 C++ 写的服务端,创建了一个 Person 对象, 怎么将服务端创建的 Person 对象传递到客户端?

​ 直接传 person 对象肯定是不合适的,因为客户端可能甚至不是 C++ 写的,能是 Java 写的,Java 不认识 C++ 中的对象更有甚者, 客户端是一个单片机的设备,是用 语言写的, 语言是面向过程的,压根就没有类和对象的概念

方法:需要一种通用的数据格式JSON(是网络传输使用效率最高的数据格式)

通常说的 JSON,其实就是 JSON 字符串,本质上是一种特殊格式的字符串

JSON 是一种轻量级的数据交换格式负责不同编程语言中的数据传递和交互,客户端和服务端数据交互,基本都是 JSON 格式的

  • JSON: JavaScript Object Notation(JavaScript 对象表示法)

  • JSON 是存储和交换文本信息的语法,类似 XML。

  • JSON 比 XML 更小、更快,更易解析。

  • JSON 易于人阅读和编写

  • JSON 是轻量级的文本数据交换格式,网络传输的标准数据格式

  • JSON 独立于语言:JSON 使用 Javascript语法来描述数据对象,但是 JSON 仍然独立于语言和平台

    • JSON 解析器和 JSON 库支持许多不同的编程语言。 目前非常多的动态(PHP,JSP,.NET)编程语言都支持JSON,
    • C、Python、C++、Java、PHP、Go等编程语言都支持 JSON。

一些JSON库:

#c
	Jansson、cJSON
#c++
    jsonCpp、JSON for Modern C++
#Java
   json-ib、org-json
#QT
   QJsonxxx    	 
2.2 数据格式:JSON 数组,JSON 对象
  • JSON 数组

    •   [ "Google", "Runoob", "Taobao" ]
      
      
    • 中括号中书写,值之间使用逗号分隔

    • JSON 数组中的元素可以是不同的数据类型,包括: 整形、 浮点、 字符串、布尔类型、JSON数组JSON 对象、空值

  • JSON 对象

    •   { "name":"runoob", "alexa":10000, "site":null }
      
    • 大括号 {…} 中书写,key/value(键/值)对,key 和 value 中使用冒号分割,值之间使用逗号分隔

    • key 必须是字符串,value 是合法的 JSON 数据(字符串, 数字, 对象, 数组, 布尔值或 null),还可以嵌套JSON数组JSON 对象

3、QTJson

QT编译器需要在.pro文件中 QT += Core

操作Json文件所需要用到的类:在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

编写json文件,解析Json文件

#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>

#include <QFile>
#include <QDebug>

//          "name":"china",
//          "info":{
//              "capital":"beijing",
//              "asian": true ,
//              "founded":1949
//          },
//          "provinces":[{
//              "name":"shandong",
//              "capita1":"jinan"
//          },{
//              "name","zhejiang",
//              "capital","hangzhou"
//          }]


//写json字符串
void writeJson()
{
    //1.把数据写入
    //1.创建JSON对象
    QJsonObject rootObj;
    //1.1插入name信息
    rootObj.insert("name","China");

    //1.2插入info信息,value是JSON对象
    QJsonObject infoObj;
    infoObj.insert("capital","Beijing");
    infoObj.insert("asion",true);
    infoObj.insert("founded",1949);

    rootObj.insert("info",infoObj);

    //1.3插入province信息,value为JSON数组
    QJsonArray provinceArray;
    QJsonObject province1;
    QJsonObject province2;
    province1.insert("name","Shandong");
    province1.insert("capital","Jinnan");
    province2.insert("name","zhejiang");
    province2.insert("capital","hangzhou");
    provinceArray.append(province1);
    provinceArray.append(province2);

    rootObj.insert("provinces",provinceArray);

    //2.装换成JSON字符串
    QJsonDocument doc(rootObj);
    QByteArray json = doc.toJson();

    //3.测试
//    qDebug() <<QString(json).toUtf8().data();

    //4.写入到文件里面
    QFile file("C:/Users/hanghang/Desktop/jsontest.txt");
    file.open(QFile::WriteOnly);
    file.write(json);
    file.close();
}


//解析json文件
void findJson()
{
    //1.读取文件
    QFile file("C:/Users/hanghang/Desktop/jsontest.txt");
    file.open(QFile::ReadOnly);
    QByteArray json = file.readAll();
    file.close();

    //2.json转换成字符串,判断打开是否json
    QJsonDocument doc = QJsonDocument::fromJson(json);
    if(!doc.isObject())
    {
        qDebug() <<" error, 不是一个jsonObject! ";
        return;
    }

    //3.解析
    QJsonObject rootObj = doc.object(); //创建接受对象
    QStringList keys = rootObj.keys();
    for(int i = 0 ; i < keys.size() ; i++)
    {
        //获取每个key - value
        QString key = keys[i]; //jsonObject的Key值是String类型
        //根据key来获取对应的value
        QJsonValue value = rootObj.value(key);

        if(value.isBool())
        {
            qDebug() << key << ":" << value.toBool();
        } else if (value.isDouble())
        {
            qDebug() << key << ":" << value.toDouble();
        } else if (value.isString())
        {
            qDebug() << key << ":" << value.toString();
        } else if (value.isObject())
        {
            qDebug() << key << ":" ;

            //value是对象的话,也是先创建一个对象来接收它,再依次获取每个key - value
            //步骤一样,这里就直接默认当是知道key - value,直接写出来就算了
            QJsonObject infoObj = value.toObject();
            QString capital = infoObj.value("capital").toString();
            bool asian = infoObj.value("asian").toBool();
            int founded = infoObj.value("founded").toInt();

            qDebug() << "   " << "capital" << ":" << capital;
            qDebug() << "   " << "asian" << ":" << !asian;
            qDebug() << "   " << "founded" << ":" << founded;

        } else if (value.isArray())
        {
            qDebug() << key << ":" ;

            //先创建一个数组来接收json数组
            QJsonArray provinceArray = value.toArray();

            for(int i = 0; i < provinceArray.size() ; i++)
            {
                QJsonObject provinceObj = provinceArray[i].toObject();

                QString name = provinceObj.value("name").toString();
                QString capital = provinceObj.value("capital").toString();

                qDebug() << "   " << "name" << ":" << name << " , " << "capital" << ":" << capital;
            }
        }
    }
}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

//    writeJson();

    findJson();
    return a.exec();
}

4.HTTP知识

4.1简介

HTTP 协议基于客户端/服务端C/S架构模型,通过一个可靠的链接来交换信息,是一个无状态的请求/响应协议。

HTTP 协议:是客户端发起请求服务器做出响应请求,必是先从客户端发起的,服务器端在没有接收到请求之前不会发送任何响应也就是说,服务端无法主动推送消息给客户端
无状态:服务器不会记住发起请求者的信息
有状态:http协议上带有cookie

4.2两种架构

B/s 架构:Browser /Server, 浏览器/服务器架构
B:浏览器,比如 Firefox、B:Internet Explorer、Goog1e chrome .
S:服务器,比如 Apache、nginx等

C/s架构:Client / server,客户端/服务器架构
B/s架构相对于c/s架构,客户机上无需安装任何软件使用浏览器即可访问服务器

4.3请求报文

在这里插入图片描述

HTTP的请求报文由四部分组成(请求行+请求头部+空行+请求体

  • 请求行:

    • ①是请求方法,GET和POST是最常见的HTTP方法,除此以外还包括DELETE、HEAD、OPTIONS、PUT、TRACE。
    • ②为请求对应的URL地址,它和报文头的Host属性组成完整的请求URL。
    • ③是协议名称及版本号
  • 请求头:

    • 服务端据此获取客户端的额外的信息

    • 包含若干个属性,格式为“属性名:属性值

    •   Client-IP:提供了运行客户端的机器的IP地址
        From:提供了客户端用户的E-mail地址
        Host:给出了接收请求的服务器的主机名和端口号
        Referer:提供了包含当前请求URI的文档的URL
        UA-Color:提供了与客户端显示器的显示颜色有关的信息
        UA-CPU:给出了客户端CPU的类型或制造商
        UA-OS:给出了运行在客户端机器上的操作系统名称及版本
        User-Agent:将发起请求的应用程序名称告知服务器
        Accept:告诉服务器能够发送哪些媒体类型
        Accept-Charset:告诉服务器能够发送哪些字符集
        Accept-Encoding:告诉服务器能够发送哪些编码方式
        Accept-Language:告诉服务器能够发送哪些语言
        TE:告诉服务器可以使用那些扩展传输编码
        Expect:允许客户端列出某请求所要求的服务器行为
        Range:如果服务器支持范围请求,就请求资源的指定范围
        Cookie:客户端用它向服务器传送数据
        Cookie2:用来说明请求端支持的cookie版本
      
  • 空行:

    • 请求头之后是一个空行,通知服务器以下不再有请求头
    • 分割作用
  • 请求体:

    • 就是实际传输的数据信息

    • GET没有请求数据,POST有。

      与请求数据相关的最常使用的请求头是 Content-Type 和 Content-Length

4.4响应报文

HTTP的响应报文也由四部分组成( 响应行+响应头+空行+响应体):

在这里插入图片描述

  • 响应行:

    • ①报文协议及版本
    • ②状态码及状态描述:200表示请求成功
      • 404 Not Found:请求资源不存在。比如,输入了错误的url(客户端错误)
      • 403 Forbidden:服务器收到请求,但是拒绝提供服务
      • 500 Internal Server Error:服务器发生不可预期的错误。(服务端错误)
      • 503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常
    • OK 原因短语
  • 响应头:

    • 传递一些额外的信息,响应时间等

    •   Age:(从最初创建开始)响应持续时间
        Public:服务器为其资源支持的请求方法列表
        Retry-After:如果资源不可用的话,在此日期或时间重试
        Server:服务器应用程序软件的名称和版本
        Title:对HTML文档来说,就是HTML文档的源端给出的标题
        Warning:比原因短语更详细一些的警告报文
        Accept-Ranges:对此资源来说,服务器可接受的范围类型
        Vary:服务器会根据这些首部的内容挑选出最适合的资源版本发送给客户端
        Proxy-Authenticate:来自代理的对客户端的质询列表
        Set-Cookie:在客户端设置数据,以便服务器对客户端进行标识
        Set-Cookie2:与Set-Cookie类似
        WWW-Authenticate:来自服务器的对客户端的质询列表
      
  • 空行:

    • 分割
  • 响应体

    • 实际数据

    • 当Web服务器接收到Web客户端的请求报文后,对HTTP请求报文进行解析,并将Web客户端的请求的对象取出打包,通过HTTP响应报文将数据传回给Web客户端,如果出现错误则返回包含对应错误的错误代码和错误原因的HTTP响应报文

5.Postman

Postman 是一个接口测试工具,用来模拟各种HTTP 请求的 (比如 GET 请求POST 请求等)

在做接口测试的时候,Postman 相当于客户端,它可模拟用户发起的各类HTTP 请求,将请求数据发送至服务端,并获取对应的响应结果

示例:

北京天气:http://t.weather.itboy.net/api/weather/city/101010100
101010100是北京的地址编号
在这里插入图片描述
.


6.QT HTTP

6.1步骤

  • 创建“网络访问管理”对象**
mNetAccessManager = new QNetworkAccessManager(this);
  • 发送HTTP请求之前,先关联信号槽
connect(mNetAccessManager, &0NetworkAccessManager::finished, this , &Mainwindow: :onReplied);

当请求结束,获取到服务器的数据时,mNetAccessManager 会发射一个finished 信号,该信号携带一个 NetworkReply 的参数服务器返回的所有数据就封装在其中,通过QNetworkRep1y 类提供的各种方法,就可以获取响应头,响应体等各种数据

  • 发送HTTP请求
QUrl url("http://t.weather.itboy.net/api/weather/city/101010100");
mNetAccessManager->get(QNetworkRequest(ur1));

根据请求的地址构建出一个 Qurl 对象,然后直接调用 QNetworkAccessManagerget 方法,即可发送一个GET 请求

  • 接收数据,调用我们自定义的槽函数 onReplied

    void onReplied(QNetworkReply* reply)
    {
        // 响应的状态码为200,表示请求成功
        int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    
        qDebug() << "operation: " << reply->operation();    //请求方式
        qDebug() << "status_code: " << status_code;         //状态码
        qDebug() << "url: " << reply->url();                //url
        qDebug() << "raw Header: " << reply->rawHeaderList(); //header
    
        if(reply->error() != QNetworkReply::NoError || status_code != 200)
        {
            QMessageBox::warning(this,"提示","请求数据失败!",QMessageBox::Ok);        
        }else{
            //获取响应信息
            QByteArray reply_data = reply->readAll();
            QByteArray byteArray = QString(reply_data).toUtf8();
            qDebug() << "read All: " << byteArray.data();
        }
        
        reply->deleteLater();
    }
    //QNetworkRep1y 中封装了服务器返回的所有数据,包括响应头、状态码、响应体等
    

7.项目创建 项目

项目成品及图标、城市编码资源文件:https://pan.baidu.com/s/1TiqlngwBKhqlnp557nrRTA?pwd=6666
提取码:6666

1.创建文件weatherForecase
2.固定界面大小,无边框
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //设置界面无边框
    setWindowFlag(Qt::FramelessWindowHint);
    //固定界面大小
    setFixedSize(800,450);
}
3.编写右键退出菜单

MainWindow.h

#include <QContextMenuEvent>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

protected:
    void contextMenuEvent(QContextMenuEvent *event) override; //鼠标右键点击事件

private:
    Ui::MainWindow *ui;

    QMenu* mExitMenu; //右键退出的菜单
    QAction* mExitAction; //退出的行为-菜单项
};

MainWindow.cpp

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
	...

    //构建右键退出菜单
    mExitMenu = new QMenu(this);

    mExitAction = new QAction();
    mExitAction->setText("退出");
    mExitAction->setIcon(QIcon(":/weatherImages/close.png"));

    mExitMenu->addAction(mExitAction);
    //关联退出信号
    connect(mExitAction,&QAction::triggered,this,[=](){
        qApp->exit(0);
    });
}

//重写父类的虚函数,父类中默认的实现 是忽略右键菜单事件,重写之后,就可以处理右键菜单
//鼠标右键点击事件重写
void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
    //右键弹出退出选项,QCursor::pos()在鼠标当前位置显示一个弹出菜单
    mExitMenu->exec(QCursor::pos());
}
4.界面布局
4.1widget (0,0,800*500)

样式表如下:

QWidget#widget
{
	border-image:url(:/weatherImages/background.png);
}

QLabel {
	font: 25 10pt "微软雅黑";
	border-radius: 4px;
	background-color: rgba(60, 60, 60, 100);
	color: rgb(255, 255, 255);
}

效果如图:
在这里插入图片描述

4.2 4个widget

在这里插入图片描述
在这里插入图片描述

4.3给四个wigget设置界面
4.3.1设置顶部界面

最终效果如图:

在这里插入图片描述

  • widget_2 (0,0)800*50
background-color: rgba(0, 170, 255,0);
  • cityLineEdit (15,10)200*28

    font: 14pt "Microsoft YaHei UI";
    background-color: rgb(255, 255, 255);
    border-radius: 4px;
    padding: 1px 5px
    

在这里插入图片描述

  • btnsearch (220,10)35*28
background-color: rgba(157, 133, 255,0);

在这里插入图片描述

  • lblDate (510,10) 270*28
font: 20pt "Arial";
background-color: rgba(255, 255, 255,0);

在这里插入图片描述

  • 然后将widget_2 水平布局,并且添加一个弹簧**

在这里插入图片描述


4.3.2设置天气图标和温度界面

最终效果:
在这里插入图片描述

  • widget_3

    background-color: rgba(157, 133, 255, 0);
    border-radius: 15px
    
  • lblTypeIcon (11,11)110*110

    background-color: rgba(255, 255, 255, 0);
    

    在这里插入图片描述
    .

  • 先把这4个lable准备好,写好对应的文字和简明知意的label名字

在这里插入图片描述

  • 样式表如下

    • lblTemperture

      color: rgb(255, 255, 255);
      font: 50pt "Arial";
      background-color: rgba(0, 255, 255, 0);
      
    • lblCity

      font: 12pt "Microsoft YaHei UI";
      background-color: rgba(255, 255, 255,0);
      
    • lblTypeChange

      background-color: rgba(255, 255, 255,0);
      font: 12pt "微软雅黑";
      
    • lblLowHight

      background-color: rgba(255, 255, 255,0);
      font: 12pt "微软雅黑";
      
  • 把lblCity放入到一个垂直布局QVboxLayout当中

在这里插入图片描述

  • lblTypeChangelblLowHight放到一个水平布局QHboxLayout当中,再增加一个line来分割一下(没有也行),弹簧修饰

在这里插入图片描述

  • lblTemperturelblCity放到一个水平布局当中,加个弹簧

在这里插入图片描述

  • 然后把这两个水平布局拉到一个垂直布局里面,这里要慢慢拉,有点难拉

在这里插入图片描述

在这里插入图片描述


4.3.3具体天气,空气质量等界面

最终效果图:红色部分

在这里插入图片描述

  • lblGanmao (10,18) 320*70

    background-color: rgba(60, 60, 60, 0);
    padding-left: 5px;
    padding-right: 5px;
    
    //感冒指数:儿童、老年人及心脏、呼吸系统疾病患者人群应减少长时间或高强度户外锻炼
    

在这里插入图片描述

在这里插入图片描述

  • 添加一个widget

在这里插入图片描述

QWidget {
    background-color: rgb(157, 133, 255);
	border-radius: 15px;
}

QLabel {
	font: 10pt "微软雅黑";
	background-color: rgba(255, 255, 255, 0);
}
  • lblWindIcon 40*40

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

  • lblWindFx 50*20 text = “西北风”

    在这里插入图片描述

  • lblWindFL 30*20 text =“ 3级”

    在这里插入图片描述

  • lblWindFLlblWindFx 放到一个垂直布局里面

在这里插入图片描述

  • 再放到一个水平布局里面 ,lblWindIcon

在这里插入图片描述

  • 然后复制四份,改一下标签名和对应名字即可

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

  • 最后放到刚才紫色的widget里面,再进行栅格布局就行

在这里插入图片描述


4.3.4未来几天天气情况界面

最终效果图:

在这里插入图片描述

  • 准备好5widget,位置和宽高如下

在这里插入图片描述

//第一个widget样式表
QLabel {
	background-color: rgba(0, 200, 200, 200);
	border-radius: 4px;
}

//第二个widget样式表
QLabel {
	background-color: rgba(60, 60, 60, 100);
	border-radius: 4px;
}
  • 第一个widget添加12个lable,星期几和对应日期,采用栅格布局

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 第二个widget添加12个lable,采用栅格布局,lable把图片引进即可,pixmap

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

  • 第三个widget, 6个lable,水平布局

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

//6个lable从上到下的样式表

background-color: rgb(121, 184, 0);
padding:8px;

background-color: rgb(255, 187, 23);

background-color: rgb(255, 87, 97);

background-color: rgb(235, 17, 27);

background-color: rgb(170, 0, 0);

background-color: rgb(110, 0, 0);
  • 第四个widget,两个lable ,留作温度曲线的展示,垂直布局

    在这里插入图片描述

在这里插入图片描述

  • 第五个widget,12个lable,栅格布局

    在这里插入图片描述

    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


5.窗口随鼠标左键移动

MainWindow.h

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

protected:
    void mousePressEvent(QMouseEvent *event); 
    void mouseMoveEvent(QMouseEvent *event);
private:
	...
    QPoint mOffset;  //窗口移动时,鼠标与窗口左上角的偏移
};

MainWindow.cpp

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    mOffset = event->globalPos() - this->pos();
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
   this->move(event->globalPos() - mOffset);
}

在这里插入图片描述

6.从服务器上获取天气数据
6.1先添加网络模块
QT       += core gui network
6.2MainWindow.h

添加用于http通信的QNetworkAccessManager对象,
用于处理http服务返回的数据onReplied

#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
protected:
    void getWeatherInfo(QString cityCode); //获取对应城市的信息,用城市编码区分
private slots:
    void onReplied(QNetworkReply* reply); //处理http请求
private:
    QNetworkAccessManager * mNetAccessManager; 
};
6.3MainWindow.cpp

关联信号槽,当getWeatherInfo函数中mNetAccessManager get执行后 就会自动调用 槽函数onReplied

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    //关联请求服务器数据,HTTP请求
    mNetAccessManager = new QNetworkAccessManager(this);
    //请求完成即finished之后,就会自动onReplied函数
    connect(mNetAccessManager,&QNetworkAccessManager::finished,this,&MainWindow::onReplied);

    //直接获取北京天气数据信息
    getWeatherInfo("101010100");
}

//根据城市编码返回信息
void MainWindow::getWeatherInfo(QString cityCode)
{
    QUrl url("http://t.weather.itboy.net/api/weather/city/" + cityCode); //这个网址返回的数据时json格式
    mNetAccessManager->get(QNetworkRequest(url)); //get请求完成就会是finished,上面的槽函数onReplied就会被调用
}

//请求服务器数据
void MainWindow::onReplied(QNetworkReply *reply)
{
    qDebug() << "onReplied successfully!" ;

    //响应的信息
    // 响应的状态码为200,表示请求成功
    int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

    qDebug() << "operation: " << reply->operation();    //请求方式
    qDebug() << "status_code: " << status_code;         //状态码
    qDebug() << "url: " << reply->url();                //url
    qDebug() << "raw Header: " << reply->rawHeaderList(); //响应header

    if(reply->error() != QNetworkReply::NoError || status_code != 200)
    {
        //errorString()返回一个QString类型字符串,而toLatin1()将该QString转换为使用Latin-1编码QByteArray类型。
        //最后,data()函数返回QByteArray的数据指针
        qDebug() << reply->errorString().toLatin1().data();
        QMessageBox::warning(this,"提示","请求数据失败!",QMessageBox::Ok);
    }else{
        //获取响应信息
        QByteArray reply_data = reply->readAll();
        QByteArray byteArray = QString(reply_data).toUtf8();
        qDebug() << "read All: " << byteArray.data();
    }

    //不然会造成内存泄漏
    reply->deleteLater();
}

在这里插入图片描述

在这里插入图片描述

7.解析获取到的JSON数据
7.1新建一个c++的头文件 weatherdata.h

由于界面上主要显示的是“今天"的天气,以及"最近六天"的天气,因此我们新建一个c++的头文件 weatherdata.h,并定义两个类

  • Today
    用于显示今天的所有天气参数,也就是屏幕左侧的数据

  • Day
    用于显示六天的天气参数,也就是屏幕右侧的数据这样,可以方便地将解析出的数据保存到类的成员变量

    //根据我们之前设计的UI布局的lable名称来获取设计对应的数据名称
    class Today
    {
    public:
        Today()
        {
            city ="广州";
            date ="2023-7-28";
    
            wendu = 0;
            type ="多云";
            high = 30;
            low = 18;
    
            ganmao ="感冒指数";
    
            shidu = "0%";
            pm25 = 0;
            fx ="南风";
            fl ="2级";
            quality ="无数据";
        }
    
        QString city;
        QString date;
    
        int wendu;
        QString type;
    
        int high;
        int low;
    
        QString ganmao;
    
        QString shidu;
        int pm25;
        QString fx;
        QString fl;
        QString quality;
    };
    
    class Day
    {
    public:
        Day()
        {
            week ="周五";
            date ="2023-7-29";
    
            type ="多云";
    
            aqi = 0; //空气指数,优
    
            high = 0;
            low = 0;
    
            fx ="南风";
            fl ="2级";
        }
    
        QString week;
        QString date;
    
        QString type;
    
        int aqi;
    
        int high;
        int low;
    
        QString fx;
        QString fl;
    };
    
7.2解析json数据

mainwindow.h

#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT
protected:
   void parseJson(QByteArray & byteArray); //解析json
private:
    Today mToday; //json解析到到数据存到这两个类里面
    Day mDay[6]; //6天的数据 
};

onReplied函数中调用

//请求服务器数据
void MainWindow::onReplied(QNetworkReply *reply)
{
    if(reply->error() != QNetworkReply::NoError || status_code != 200)
    {
    }else{
        //获取响应信息
        QByteArray reply_data = reply->readAll();
        QByteArray byteArray = QString(reply_data).toUtf8();
        qDebug() << "read All: " << byteArray.data();

        //获取到json数据后进行解析
        parseJson(byteArray);
    }
}

解析过程根据返回来的json数据编写,用json解析工具解析数据,再一一对应的写

void MainWindow::parseJson(QByteArray &byteArray)
{
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson(byteArray,&error); //如果报错就会把错误信息写到error里
    //报错直接退出
    if(error.error != QJsonParseError::NoError)
    {
        return;
    }

    QJsonObject rootObj = doc.object();
//    qDebug() << rootObj.value("message").toString();

    //1.解析城市跟日期
    mToday.city = rootObj.value("cityInfo").toObject().value("city").toString();
    mToday.date = rootObj.value("date").toString();

    //2.解析昨天yesterday数据
    QJsonObject dataObj = rootObj.value("data").toObject();

    QJsonObject yesterdayObj = dataObj.value("yesterday").toObject();
    mDay[0].week = yesterdayObj.value("week").toString();
    mDay[0].date = yesterdayObj.value("ymd").toString();
    //天气类型
    mDay[0].type = yesterdayObj.value("type").toString();

    //空气指数
    mDay[0].aqi =yesterdayObj.value("aqi").toDouble();

    //温度,要分割取数据,"high":"高温 32℃"
    QString highS;
    highS = yesterdayObj.value("high").toString().split(" ").at(1); //高温 32℃ -> 32°C ,按空格切割,取第二个数据
    mDay[0].high = highS.left(highS.length() - 1).toInt(); //长度减一,从左边开始计算取,32°c -> 32 ,在转换为int
    QString lowS;
    lowS = yesterdayObj.value("low").toString().split(" ").at(1);
    mDay[0].low = lowS.left(lowS.length() - 1).toInt();

    //风向,风力
    mDay[0].fx = yesterdayObj.value("fx").toString();
    mDay[0].fl = yesterdayObj.value("fl").toString();

    //3.解析forecast中5天的数据 ,forecast当中包括15天的数据,数组形式
    QJsonArray forecastArr = dataObj.value("forecast").toArray();
    for(int i=0 ; i<5 ; i++)
    {
        QJsonObject forecastObj = forecastArr[i].toObject();

        mDay[i+1].week = forecastObj.value("week").toString();
        mDay[i+1].date = forecastObj.value("ymd").toString();
        mDay[i+1].type = forecastObj.value("type").toString();
        //空气指数
        mDay[0].aqi =forecastObj.value("aqi").toDouble();

        //温度,要分割取数据,"high":"高温 32℃"
        QString highS;
        highS = forecastObj.value("high").toString().split(" ").at(1); 
        mDay[i+1].high = highS.left(highS.length() - 1).toInt(); 
        QString lowS;
        lowS = forecastObj.value("low").toString().split(" ").at(1);
        mDay[i+1].low = lowS.left(lowS.length() - 1).toInt();

        //风向,风力
        mDay[i+1].fx = forecastObj.value("fx").toString();
        mDay[i+1].fl = forecastObj.value("fl").toString();
    }

    //4.解析今天的数据
    mToday.wendu =dataObj.value("wendu").toInt();

    mToday.ganmao =dataObj.value("ganmao").toString();

    mToday.shidu = dataObj.value("shidu").toString();
    mToday.pm25 =dataObj.value("pm25").toInt();
    mToday.quality =dataObj.value("quality").toString();

    //还有一些今天的天气数据在forecast里面
    mToday.type = mDay[1].type; //上面存好了,直接用
    mToday.high = mDay[1].high;
    mToday.low = mDay[1].low;

    mToday.fx = mDay[1].fx;
    mToday.fl = mDay[1].fl;
}
8.更新UI

mainwindow.h

#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
private:
    //界面右边部分label名称,用数组存起来,用于ui更新
    //星期和日期
    QList<QLabel* > mWeekList;
    QList<QLabel* > mDateList;
    //天气和天气图标
    QList<QLabel* > mTypeList;
    QList<QLabel* > mTypeIconList;
    //天气污染指数,优……
    QList<QLabel* > mAqiList;
    //风向,风力
    QList<QLabel* > mFxList;
    QList<QLabel* > mFlList;

    //图标
    QMap<QString,QString> mTypeIconMap;
};

mainwindow.cpp

将UI上的label写到数组里面

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    // UI初始化
    //将控件放到数组里面,方便使用循环进行处理
    //星期和日期
    mWeekList << ui->lblWeek0 << ui->lblWeek1 << ui->lblWeek2 << ui->lblWeek3 << ui->lblWeek4 << ui->lblWeek5;
    mDateList << ui->lblDate0 << ui->lblDate1 << ui->lblDate2 << ui->lblDate3 << ui->lblDate4 << ui->lblDate5;
    //天气和天气图标
    mTypeList << ui->lblType0 << ui->lblType1 << ui->lblType2 << ui->lblType3 << ui->lblType4 << ui->lblType5;
    mTypeIconList << ui->lblTypeIcon0 << ui->lblTypeIcon1 << ui->lblTypeIcon2 << ui->lblTypeIcon3 << ui->lblTypeIcon4 << ui->lblTypeIcon5;
    //天气污染指数,优……
    mAqiList << ui->lblQuality0 << ui->lblQuality1 << ui->lblQuality2 << ui->lblQuality3 << ui->lblQuality4 << ui->lblQuality5;
    //风向,风力
    mFxList << ui->lblFx0 << ui->lblFx1 << ui->lblFx2 << ui->lblFx3 << ui->lblFx4 << ui->lblFx5;
    mFlList << ui->lblFl0 << ui->lblFl1 << ui->lblFl2 << ui->lblFl3 << ui->lblFl4 << ui->lblFl5;

    //图标
    mTypeIconMap.insert("晴", ":/weatherImages/type/Qing.png");
    mTypeIconMap.insert("多云", ":/weatherImages/type/DuoYun.png");
    mTypeIconMap.insert("阴", ":/weatherImages/type/Yin.png");
    mTypeIconMap.insert("雨", ":/weatherImages/type/Yu.png");
    mTypeIconMap.insert("雪", ":/weatherImages/type/Xue.png");
    mTypeIconMap.insert("沙尘暴", ":/weatherImages/type/ShaChenBao.png");

    mTypeIconMap.insert("雷阵雨", ":/weatherImages/type/LeiZhenYu.png");
    mTypeIconMap.insert("大雨", ":/weatherImages/type/DaYu.png");
    mTypeIconMap.insert("小雨", ":/weatherImages/type/XiaoYu.png");
    mTypeIconMap.insert("中雨", ":/weatherImages/type/ZhongYu.png");
    mTypeIconMap.insert("阵雨", ":/weatherImages/type/ZhenYu.png");
    mTypeIconMap.insert("暴雨", ":/weatherImages/type/BaoYu.png");
    mTypeIconMap.insert("大暴雨", ":/weatherImages/type/DaBaoYu.png");
    mTypeIconMap.insert("大到暴雨",":/weatherImages/type/DaDaoBaoYu.png");
    mTypeIconMap.insert("暴雨到大暴雨",":/weatherImages/type/BaoYuDaoDaBaoYu.png");
    mTypeIconMap.insert("大暴雨到大暴雨",":/weatherImages/type/DaBaoYuDaoDaBaoYu.png");

    mTypeIconMap.insert("暴雪",":/weatherImages/type/BaoXue.png");
    mTypeIconMap.insert("大到暴雪",":/weatherImages/type/DaDaoBaoXue.png");
    mTypeIconMap.insert("大雪", ":/weatherImages/type/DaXue.png");
    mTypeIconMap.insert("小雪", ":/weatherImages/type/XiaoXue.png");
    mTypeIconMap.insert("中雪", ":/weatherImages/type/ZhongXue.png");


    mTypeIconMap.insert("雨夹雪", ":/weatherImages/type/YuJiaXue.png");
    mTypeIconMap.insert("霾", ":/weatherImages/type/Mai.png");
    mTypeIconMap.insert("扬沙", ":/weatherImages/type/YangSha.png");
    mTypeIconMap.insert("沙尘暴", ":/weatherImages/type/ShaChenBao.png");
    mTypeIconMap.insert("特大暴雨", ":/weatherImages/type/TeDaBaoYu.png");
    mTypeIconMap.insert("乌", ":/weatherImages/type/Wu.png");
    mTypeIconMap.insert("小到中雨", ":/weatherImages/type/XiaoDaoZhongYu.png");
    mTypeIconMap.insert("小到中雪", ":/weatherImages/type/XiaoDaoZhongXue.png");
    mTypeIconMap.insert("雨夹雪", ":/weatherImages/type/YuJiaXue.png");
    mTypeIconMap.insert("阵雪", ":/weatherImages/type/ZhenXue.png");
}

更新函数,将获取到的数据更新到UI

void MainWindow::updateUI()
{
    //设置日期 城市
    //注意返回来的值为“20230728”这种格式,要进行转换2023/07/28
    ui->lblDate->setText(QDateTime::fromString(mToday.date,"yyyyMMdd").toString("yyyy/MM/dd") + " " + mDay[1].week);
    ui->lblCity->setText(mToday.city);

    //更新今天
    ui->lblTypeIcon->setPixmap(mTypeIconMap[mToday.type]);
    ui->lblTemperture->setText(QString::number(mToday.wendu));
    ui->lblTypeChange->setText(mToday.type);
    ui->lblLowHight->setText(QString::number(mToday.low) + "°" +"~" + QString::number(mToday.high) + "°");
    ui->lblGanmao->setText("感冒指数:" + mToday.ganmao);
    ui->lblWinFx->setText(mToday.fx);
    ui->lblWinFI->setText(mToday.fl);
    ui->lblPM25->setText(QString::number(mToday.pm25));
    ui->lblShiDu->setText(mToday.shidu);
    ui->lblQuality->setText(mToday.quality);


    //更新6天
    for(int i=0 ; i<6 ; i++)
    {
        //更新星期
        mWeekList[i]->setText("周" + mDay[i].week.right(1)); //数据是”星期六“,取右边第一位
        ui->lblWeek0->setText("昨天");
        ui->lblWeek1->setText("今天");
        ui->lblWeek2->setText("明天");

        //更新日期 ,数据是”2023-07-28“
        QStringList ymdList = mDay[i].date.split("-");
        mDateList[i]->setText(ymdList[1] + "/" + ymdList[2]);

        //更新天气类型
        mTypeList[i]->setText(mDay[i].type);
        mTypeIconList[i]->setPixmap(mTypeIconMap[mDay[i].type]);

        //更新空气质量
        if (mDay[i].aqi >= 0 && mDay[i].aqi <= 50)
        {
            mAqiList[i]->setText("优");
            mAqiList[i]->setStyleSheet("background-color: rgb(121, 184, 0);");
        }
        else if (mDay[i].aqi > 50 && mDay[i].aqi <= 100)
        {
            mAqiList[i]->setText("良");
            mAqiList[i]->setStyleSheet("background-color: rgb(255, 187, 23);");
        }
        else if (mDay[i].aqi > 100 && mDay[i].aqi <= 150)
        {
            mAqiList[i]->setText("轻度");
            mAqiList[i]->setStyleSheet("background-color: rgb(255, 87, 97);");
        }
        else if (mDay[i].aqi > 150 && mDay[i].aqi <= 200)
        {
            mAqiList[i]->setText("中度");
            mAqiList[i]->setStyleSheet("background-color: rgb(235, 17, 27);");
        }
        else if (mDay[i].aqi > 200 && mDay[i].aqi <= 250)
        {
            mAqiList[i]->setText("重度");
            mAqiList[i]->setStyleSheet("background-color: rgb(170, 0, 0);");
        }
        else
        {
            mAqiList[i]->setText("严重");
            mAqiList[i]->setStyleSheet("background-color: rgb(110, 0, 0);");
        }


        //更新风
        mFxList[i]->setText(mDay[i].fx);
        mFlList[i]->setText(mDay[i].fl);
    }
}

在解析完数据之后就可以更新UI

//解析数据
void MainWindow::parseJson(QByteArray &byteArray)
{
    //更新UI
    updateUI();
}
9.城市编码

实现搜索城市,获取到相对应的天气数据,并且更新到UI上

//weatherTool的数据,懒得分开了,注意报错什么多重定义的,不要把头文件 #include "weathertool.h" 的引入放到这里
// 在头文件中定义了静态变量,然后在多个源文件中包含了这个头文件,
// 就会出现同一个变量被多次定义的情况,从而导致链接错误,直接放在头文件就行

mainwindow.h

#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
public:
    void initCityCode(); // 初始化城市数据,读取解析一个json文件,将数据存到map里面
    QString getCityCode(QString cityName); //在map里面根据城市名字找对应编码
private:
    //城市编码
    QMap<QString,QString> mCityMap;
};

mainwindow.cppgetWeatherInfo()函数中调用




void MainWindow::getWeatherInfo(QString cityName) //原来是getWeatherInfo(QString cityCode)
{
    QString cityCode = getCityCode(cityName);

    if(cityCode.isEmpty())
    {
       QMessageBox::warning(this,"错误","请检查是否输入正确的城市",QMessageBox::Ok);
       return;
    }
    QUrl url("http://t.weather.itboy.net/api/weather/city/" + cityCode);
    mNetAccessManager->get(QNetworkRequest(url)); //get请求完成就会是finished,上面的槽函数onReplied就会被调用
}

//
QString MainWindow::getCityCode(QString cityName)
{
    // 初始化map
    if (mCityMap.isEmpty())
    {
        initCityCode();
    }
     // 根据城市名字遍历map,获取城市编码
    QMap<QString, QString>::iterator it = mCityMap.find(cityName);
    // 特殊:输入北京/北京市都可以找到
    if (it == mCityMap.end())
    {
        it = mCityMap.find(cityName + "市");
    }
    if (it == mCityMap.end())
    {
        it = mCityMap.find(cityName + "区");
    }
    if (it == mCityMap.end())
    {
        it = mCityMap.find(cityName + "县");
    }
     // 如果遍历到有这个城市名字,就返回编码
    if (it != mCityMap.end())
    {
        return it.value();
    }
    return ""; // 没有就返回空
}

//初始化
void MainWindow::initCityCode()
{
    // 读取文件
    QFile file(":/citycode.json");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        // 处理文件打开失败的情况
        return;
    }
    QByteArray json = file.readAll();
    file.close();
     // 解析json,并且写入到map,这个文件是json数组
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson(json, &error);
    if (error.error != QJsonParseError::NoError || !doc.isArray())
    {
        // 处理JSON解析失败的情况
        return;
    }
     // 然后获取json数据当中的城市名字和对应的编码
    QJsonArray cityArr = doc.array();
    for (int i = 0; i < cityArr.size(); i++)
    {
        QString city = cityArr[i].toObject().value("city_name").toString();
        QString code = cityArr[i].toObject().value("city_code").toString();
         // 然后写入到map
        // 注意当输入是省份时,是没有城市编码的,不可以查整个省份的天气,只能是具体的城市
        if (!code.isEmpty())
        {
            mCityMap.insert(city, code);
        }
    }
}

mainwindow.cpp中关联搜索点击信号和输入回车信号

//搜索按钮点击
void MainWindow::on_btnSearch_clicked()
{
    QString cityname = ui->Cityline->text();
    getWeatherInfo(cityname);
}

//输入框回车
void MainWindow::on_Cityline_returnPressed()
{
    QString cityname = ui->Cityline->text();
    getWeatherInfo(cityname);
}

10.绘制温度曲线

MainWindow.h

#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
protected:
    bool eventFilter(QObject *watched, QEvent *event) override; //重写绘图事件

    //绘制曲线
    void paintHight();
    void paintLow();
};

mainwindow.cpp 注意这里事件过滤器的步骤

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    //温度曲线
    //步骤1 安装事件过滤器
    ui->lblHightCurve->installEventFilter(this);
    ui->lblLowCurve->installEventFilter(this);
}
//注意这里要在更新UI函数这里调用Upadate函数,不然就会一直显示都是温度曲线0
//因为eventFilter会最先调用,请求服务器那些语句都还没执行,所以不会有数据
//在更新UI函数中,在调用一次eventFilter函数就会有数据,此时请求数据的那些函数已经被执行

//步骤2重写事件
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{

    //处理绘图事件(QEvent::Paint)。
    //在这个事件处理函数中,首先通过检查事件的类型(event->type() == QEvent::Paint)来确定是否是绘图事件
    if(event->type() == QEvent::Paint)
    {
        //"watched" 是否等于 "ui->lblHight",来判断是否是标签控件 "ui->lblHight" 的绘图事件
        if(watched == ui->lblHightCurve)
        {
            paintHight();
        }

        if(watched == ui->lblLowCurve)
        {
            paintLow();
        }
    }

    return QWidget::eventFilter(watched,event);
}


void MainWindow::paintHight()
{

    //在lblHighCurve上绘图
    QPainter painter(ui->lblHightCurve);
    //设置 QPainter::Antialiasing 标志来启用抗锯齿功能,产生更平滑的图形效果
    painter.setRenderHint(QPainter::Antialiasing,true);

    //1.计算温度点的坐标(X,Y)
    //X
    int pointX[6] = {0};
    for(int i = 0; i < 6 ;i++)
    {   //6个点,平均分成5等分
        //ui->lblHight->pos().x()用于获取lblHightCurve相对于其父级或包含的窗口的左边的x坐标,就是label的左边边边的位置
        //为了更好看,设置一个边距DISTANCE 10
        pointX[i] = mWeekList[i]->pos().x()+(mWeekList[i]->width()/2);
    }

    //Y
    int tempertureSum = 0;
    int tempertureAvg = 0;
    int yCenter = ui->lblHightCurve->height() / 2; //中心轴,平均温度绘制在这里
    int moveDistance = ui->lblHightCurve->height() / 20 ; //偏移量,根据实际温度与平均温度的差值*偏移量 来计算距离中心轴的距离
    for(int i = 0; i < 6 ;i++)
    {
        tempertureSum += mDay[i].high;
    }
    tempertureAvg = tempertureSum / 6;

    int pointY[6] = {0};
    for(int i = 0; i < 6 ;i++)
    {
        //y轴方向为向下
        pointY[i] = yCenter - (mDay[i].high - tempertureAvg)*moveDistance;
    }

    //2.设置画笔,字体
    QPen pen = painter.pen();
    pen.setWidth(2);
    pen.setColor(QColor(250,170,0));
    painter.setPen(pen);

    painter.setBrush(QColor(250,170,0));
    painter.setFont(QFont("Microsoft YaHei", 10));


    //3.画温度点,设置文本
    for(int i=0 ; i<6 ; i++)
    {
        painter.drawEllipse(QPoint(pointX[i],pointY[i]),2,2);
        painter.drawText(QPoint(pointX[i] - TEXT_OFFSET_X ,pointY[i] - TEXT_OFFSET_Y),QString::number(mDay[i].high) + "°");
    }

    //4、连线
    for(int i = 0 ; i < 5 ; i++)
    {
        //第一天是虚线
        if(i==0)
        {
            pen.setStyle(Qt::DotLine);
            painter.setPen(pen);
        }
        else
        {
            pen.setStyle(Qt::SolidLine);
            painter.setPen(pen);
        }
        painter.drawLine(QPoint(pointX[i],pointY[i]),QPoint(pointX[i+1],pointY[i+1]));
    }

}

void MainWindow::paintLow()
{
    //在lblHighCurve上绘图
    QPainter painter(ui->lblLowCurve);
    //设置 QPainter::Antialiasing 标志来启用抗锯齿功能,产生更平滑的图形效果
    painter.setRenderHint(QPainter::Antialiasing,true);

    //1.计算温度点的坐标(X,Y)
    //X
    int pointX[6] = {0};
    for(int i = 0; i < 6 ;i++)
    {   //6个点,平均分成5等分
        //ui->lblHight->pos().x()用于获取lblHightCurve相对于其父级或包含的窗口的左边的x坐标,就是label的左边边边的位置
        //为了更好看,设置一个边距DISTANCE 10
        pointX[i] = mWeekList[i]->pos().x()+(mWeekList[i]->width()/2);
    }

    //Y
    int tempertureSum = 0;
    int tempertureAvg = 0;
    int yCenter = ui->lblLowCurve->height() / 2; //中心轴,平均温度绘制在这里
    int moveDistance = ui->lblLowCurve->height() / 20 ; //偏移量,根据实际温度与平均温度的差值*偏移量 来计算距离中心轴的距离
    for(int i = 0; i < 6 ;i++)
    {
        tempertureSum += mDay[i].low;
    }
    tempertureAvg = tempertureSum / 6;

    int pointY[6] = {0};
    for(int i = 0; i < 6 ;i++)
    {
        //y轴方向为向下
        pointY[i] = yCenter - (mDay[i].low - tempertureAvg)*moveDistance;
    }

    //2.设置画笔,字体
    QPen pen = painter.pen();
    pen.setWidth(2);
    pen.setColor(QColor(0,255,255));
    painter.setPen(pen);

    painter.setBrush(QColor(0,255,255));
    painter.setFont(QFont("Microsoft YaHei", 10));


    //3.画温度点,设置文本
    for(int i=0 ; i<6 ; i++)
    {
        painter.drawEllipse(QPoint(pointX[i],pointY[i]),2,2);
        painter.drawText(QPoint(pointX[i] - TEXT_OFFSET_X ,pointY[i] - TEXT_OFFSET_Y),QString::number(mDay[i].low) + "°");
    }

    //4、连线
    for(int i = 0 ; i < 5 ; i++)
    {
        //第一天是虚线
        if(i==0)
        {
            pen.setStyle(Qt::DotLine);
            painter.setPen(pen);
        }
        else
        {
            pen.setStyle(Qt::SolidLine);
            painter.setPen(pen);
        }
        painter.drawLine(QPoint(pointX[i],pointY[i]),QPoint(pointX[i+1],pointY[i+1]));
    }
}
//更新UI
void MainWindow::updateUI()
{
    //更新温度曲线
    ui->lblHightCurve->update();
    ui->lblLowCurve->update();
}

在这里插入图片描述

  • 17
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: c++ qt天气预报项目是一个基于qt框架的气象应用程序,主要功能是提供准确的天气信息查询服务。它具有直观的用户界面,可设置城市、天气、温度、湿度、气压等信息,还可显示未来几天的天气预报,方便用户随时了解天气情况。 在实现中,项目主要分为两个部分:前端和后端。前端主要负责展示数据和用户交互,使用qt的QML语言、JavaScript和CSS等技术进行布局和设计。后端主要负责实现数据的获取和处理,使用qtC++语言、网络通信和解析技术,从网络上获取数据,并进行解析与处理。 在该项目中,通过网络请求获得实时天气信息,如空气质量、温度、湿度、气压等,并根据用户设置的城市信息,显示对应的天气信息。同时,项目还提供城市搜索、切换、添加、删除等功能,并支持开机自启动。 此外,项目还包含了数据缓存和网络异常处理功能,当网络异常时,项目可以显示错误信息,并提示用户检查网络连接,保证用户能够正常使用。 总的来说,C++ qt天气预报项目是一款非常实用的天气应用程序,具有简单易用、界面美观、功能实用等特点,帮助用户时刻掌握天气情况,是一款非常实用和有用的工具。 ### 回答2: C++ Qt 天气预报项目是一个基于 Qt 框架开发的一款天气预报应用程序。该项目主要利用了 Qt 的 QWidget 和 QWebKit 组件来实现应用程序的界面和数据获取功能。在编写程序界面时,采用了 Qt Designer 工具进行设计,通过信号和槽机制实现用户交互和数据实时刷新。 该应用程序能够自动获取用户所在地区的天气信息,并展示当前天气情况、未来几天的天气预报等相关信息。在数据获取方面,通过 WebView 组件实现对天气网站的模拟访问,获取天气数据并进行解析和处理,最终将数据展示在界面上。 除了基本的天气信息展示功能外,该应用程序还具有自定义城市、多城市查询、背景图片更换等一些实用的功能。在多城市查询方面,用户可以添加多个城市进行查询,并支持切换城市信息。在背景图片更换方面,用户可以选择不同的背景主题,从而实现界面个性化定制。 在代码实现方面,该项目重点涉及信号和槽机制、数据处理和展示等方面的学习和应用。整个程序采用模块化架构,具有灵活性和可扩展性,非常适合初学者进行 Qt 编程练习。该项目还具有实际应用价值,能够帮助用户随时获取所在地区及其他城市的天气信息,使用户出行更加方便。 ### 回答3: C++ Qt 天气预报项目是一个使用C++ 编程语言,通过Qt GUI程序库和天气API开发的一款实用工具。它可以实现天气查询,每日天气信息的更新,城市切换、温度切换、语言切换等功能。 该项目的实现分为三个模块:天气API数据获取模块、天气信息处理模块和GUI界面设计与交互模块。天气API数据获取模块负责从API中获取天气数据,天气信息处理模块用于对天气数据进行处理, GUI界面设计与交互模块则主要实现用户界面的设计、功能按钮操作等。 在该项目的实现中,C++编程语言的高效性和良好的性能表现得到了充分的发挥。Qt GUI程序库提供了丰富的GUI组件和封装好的API,为项目开发提供了便利和支持。天气API的获取和处理模块为项目提供了可靠的数据来源和数据处理能力。 总的来说,C++ Qt 天气预报项目是一款实用、高效、易用的工具,为用户提供了便利的天气查询服务和多功能操作,同时也展示了C++编程语言Qt GUI程序库的优异特性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值