• Qt之天气预报——功能实现篇(含源码+注释)


    一、功能概述

    天气预报包含实时天气模式和预报天气模式。

    1.基本功能

    添加右键菜单;
    可切换天气模式;
    显示天气报告时间;
    刷新功能(右键菜单);
    城市选择模式:包括下拉框选择和文本框输入(右键菜单);
    切换城市更新天气预报信息,显示报告时间、城市、温度等常用信息。

    2.实时天气模式

    实时天气模式功能比较单一,仅显示当天的天气基本信息。

    3.预报天气模式

    预报天气包含四天的天气信息(包括当天天气),默认显示当天天气信息;可通过自定义按钮对象切换天气信息,且预报天气下方为预报日期日、夜间温度的折线图

    二、天气预报功能示例图

    1.城市选择(下拉框)

    下图通过下拉列表框切换城市从而自动查询天气,其中包括实时天气和预报天气。
    在这里插入图片描述

    2.城市选择(文本框)

    下图演示文本框的联想功能,以及通过城市编码获取天气操作。
    在这里插入图片描述

    3. 预报天气日期切换

    下图通过预报天气中的星期模块切换对应日期的信息。
    在这里插入图片描述

    4.刷新操作

    下图通过右键菜单刷新按钮重新获取天气信息,肉眼可见图表的刷新。
    在这里插入图片描述
    提示:不会使用Qt设计师设计界面的小伙伴点击这里

    三、使用类的简述

    3.1 涉及的Qt类

    QFile:读取配置文件。
    QDateTime:转换时间串。
    QCompleter:文本框联想类。
    QMessageBox:提示对话框。
    QDomDocument、QDomElement:解析XML配置文件;须在pro文件添加“QT += xml”。
    QJsonDocument、QJsonObject、QJsonArray:解析天气预报返回的Json串。
    QChartView、QChart、QLineSeries、QDateTimeAxis、QValueAxis:绘制折线图;须在pro文件添加“QT += charts”,并在图表使用类中添加“QT_CHARTS_USE_NAMESPACE”使用命名空间。
    QNetworkAccessManager、QNetworkReply、QNetworkRequest:天气预报信息申请和获取返回的Json串。
    注:简述仅代表类在本文中的作用。

    3.2 自定义类

    3.2.1 自定义结构体

    stApiInfo:存储API链接信息结构体;可以生成链接、设置链接和判断链接信息释放包含空。
    stLiveInfo:存储实时信息结构体;可设置实时信息和判断实时信息是否包含空。
    stForecastsInfo:存储预报信息结构体;可设置单个预报天气信息内容。
    stWeatherInfo:存储天气信息结构体;包含基础信息、实时信息结构体和预报信息结构体链表。

    3.2.2 自定义类

    CWeatherForecast:天气预报类;其中包含API信息结构体、天气信息结构体、城市信息等。
    CForecastWidget:预报天气信息显示类;主要显示预报天气信息和切换预报天气。
    CForecastBtn:预报天气天气切换按钮类;响应鼠标点击发送索引值,从而切换天气,原型为QWidget,但是主要响应点击信号,所以在此称之为按钮。

    四、配置文件

    1.API链接配置文件——WeatherApi.xml

    配置文件内容可自定义,API_KEY的申请详情可查看Qt之天气预报实现(一)预备篇

    
    <Root Type = "ApiInfo">
    	<Link Link = "http://restapi.amap.com/v3/weather/weatherInfo?"/>
    	<ApiKey ApiKey = "自己申请的API KEy"/>
    	<CityCode CityCode = "110000"/>
    	<Extensions Extensions = "base"/>
    Root>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    1.城市编码配置文件——CityCodeInfo.xml

    城市编码可通过Web服务 API 相关下载下载。
    注:因城市编码信息过多,在此仅展示部分。

    
    <Root  Type = "CityInfo">
    	<CityInfo Name = "北京市" Code = "110000" />
    	<CityInfo Name = "北京市市辖区" Code = "110100" />
    	<CityInfo Name = "东城区" Code = "110101" />
    	<CityInfo Name = "西城区" Code = "110102" />
    	......
    	<CityInfo Name = "风顺堂区" Code = "820005" />
    	<CityInfo Name = "嘉模堂区" Code = "820006" />
    	<CityInfo Name = "路凼填海区" Code = "820007" />
    	<CityInfo Name = "圣方济各堂区" Code = "820008" />
    Root>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    五、遇到的问题

    1.图表坐标轴不显示

    通过序列对象的attachAxis()函数将序列对象与X/Y坐标轴对象关联起来即可。

    2.时间轴数据索引位置对应

    时间轴起始值为1970/01/01,当我设置时间轴范围时,需要将获取日期时间值的毫秒值,然后将毫秒值和温度值添加到序列中即可(详情请见源码)。

    六、源码

    6.1 结构体头文件

    StWeatherForecast.h

    #ifndef STWEATHERFROECAST_H
    #define STWEATHERFROECAST_H
    
    #include 
    #include 
    #include 
    
    // 定义api信息结构体
    typedef struct stApiInfo
    {
        QString link;   // 链接
        QString apiKey; // API Key
        QString cityCode;   // 城市编码
        QString extensions; // 天气查看类型
    
        // api信息结构体初始化
        stApiInfo()
        {
            link = "http://restapi.amap.com/v3/weather/weatherInfo?";   // 链接
            apiKey = "自己的APIKEY";    // apiKey
            cityCode = "110000";    // 城市码
            extensions = "base";    // 天气查看类型(实时、预报)
        }
    
        /**
         * @brief joinApiLink 拼接API链接
         * @return 返回拼接好的API链接
         */
        QString joinApiLink()
        {
            QString ret = "";
            // 拼接API_KEY
            ret = link + "key=" + apiKey;
            ret += "&city=" + cityCode;
            ret += "&extensions=" + extensions;
            return ret;
        }
    
        /**
         * @brief fieldIsEmpty 判断是否有字段值为空
         * @return 是否为空
         */
        bool fieldIsEmpty()
        {
            return link.isEmpty() || apiKey.isEmpty() || cityCode.isEmpty() || extensions.isEmpty();
        }
    }stApiInfo;
    
    // 实时天气信息结构体
    typedef struct stLiveInfo
    {
        QString weather;        // 天气
        QString temperature;    // 温度
        QString winddirection;  // 风向
        QString windpower;      // 风力等级
        QString humidity;       // 湿度
    
        // 无参构造
        stLiveInfo()
        {
        }
    
        // 使用构造函数使其将数据传入,通过初始化列表赋值
        stLiveInfo(const QString &weather, const QString &temperature
                   , const QString &winddirection, const QString &windpower, const QString &humidity)
            : weather(weather)
            , temperature(temperature)
            , winddirection(winddirection)
            , windpower(windpower)
            , humidity(humidity)
        {
        }
    
        /**
         * @brief setWeatherInfo 设置天气信息
         * @param weather 天气
         * @param temperature 温度
         * @param winddirection 风向
         * @param windpower 风力等级
         * @param humidity 湿度
         */
        void setWeatherInfo(const QString &weather, const QString &temperature
                       , const QString &winddirection, const QString &windpower, const QString &humidity)
        {
            this->weather = weather;
            this->temperature = temperature;
            this->winddirection = winddirection;
            this->windpower = windpower;
            this->humidity = humidity;
        }
    
        /**
         * @brief fieldIsEmpty 判断是否有字段值为空
         * @return 是否为空
         */
        bool fieldIsEmpty()
        {
            return weather.isEmpty() || temperature.isEmpty()
                     || winddirection.isEmpty() || windpower.isEmpty() || humidity.isEmpty();
        }
    }stLiveInfo;
    
    // 预报天气信息结构体
    typedef struct stForecastsInfo
    {
    private:
        QHash<int, QString> weekHash;
    
    public:
        QString date;           // 日期
        QString week;           // 星期
        QString dayweather;     // 日间天气
        QString nightweather;   // 夜间天气
        QString daytemp;        // 日间温度
        QString nighttemp;      // 夜间温度
        QString daywind;        // 日间风向
        QString nightwind;      // 夜间风向
        QString daypower;       // 日间风力等级
        QString nightpower;     // 夜间风力等级
    
        // 创建无参构造
        stForecastsInfo()
        {
            //! 初始化Hash的值,为方便获取周数据
            //! 此次可通过配置文件读取,不过我在这里就偷一下懒了,hhh
            weekHash[1] = "周一";
            weekHash[2] = "周二";
            weekHash[3] = "周三";
            weekHash[4] = "周四";
            weekHash[5] = "周五";
            weekHash[6] = "周六";
            weekHash[7] = "周日";
        }
    
        /**
         * @brief setDate 设置日期(自动设置星期)
         * @param dateStr 日期字符串
         */
        void setDate(const QString &dateStr)
        {
            // 结构体日期变量赋值
            this->date = dateStr;
            // 将日期字符串转为QDate对象(必须设置字符串的日期格式哦,否则识别不到日期)
            QDate date = QDate::fromString(dateStr, "yyyy-MM-dd");
            // 结构体星期变量赋值
            this->week = weekHash[date.dayOfWeek()];
        }
    
        /**
         * @brief setWeather 设置日/夜间天气
         * @param dayweather 日间天气
         * @param nightweather 夜间天气
         */
        void setWeather(const QString &dayweather, const QString &nightweather)
        {
            this->dayweather = dayweather;
            this->nightweather = nightweather;
        }
    
        /**
         * @brief setTemperature 设置日/夜间温度
         * @param daytemp 日间温度
         * @param nighttemp 夜间温度
         */
        void setTemperature(const QString &daytemp, const QString &nighttemp)
        {
            this->daytemp = daytemp;
            this->nighttemp = nighttemp;
        }
    
        /**
         * @brief setWindDirection 设置日/夜间风向
         * @param daywind 日间风向
         * @param nightwind 夜间风向
         */
        void setWindDirection(const QString &daywind, const QString &nightwind)
        {
            this->daywind = daywind;
            this->nightwind = nightwind;
        }
    
        /**
         * @brief setWindPower 设置日/夜间风力等级
         * @param daypower 日间风力等级
         * @param nightpower 夜间风力等级
         */
        void setWindPower(const QString &daypower, const QString &nightpower)
        {
            this->daypower = daypower;
            this->nightpower = nightpower;
        }
    }stForecastsInfo;
    
    // 天气信息结构体
    typedef struct stWeatherInfo
    {
        // 基本信息(实时、预报天气都有以下属性)
        QString province;           // 省份
        QString city;               // 城市
        QString adcode;             // 区域编码
        QString reporttime;         // 报告时间
    
        // 因为实时信息和预报信息内容不同,需分开存储
        stLiveInfo              stliveInfo;         // 实时天气信息
        // 实时信息包含多天天气,需用容器存储
        QList<stForecastsInfo>  stForecastInfoList; // 预报天气信息
    
        /**
         * @brief setBaseInfo 设置基础信息函数
         * @param province  省份
         * @param city 成都
         * @param adcode 区域编码
         * @param reportTime 报告时间
         */
        void setBaseInfo(const QString &province, const QString &city
                         , const QString &adcode, const QString &reportTime)
        {
            this->province = province;
            this->city = city;
            this->adcode = adcode;
            this->reporttime = reportTime;
        }
    
    }stWeatherInfo;
    
    #endif // STWEATHERFROECAST_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227

    6.2 预报天气按钮类

    注:因其功能主要为点击,所以称为按钮类。
    CForecastBtn.h

    #ifndef CFORECASTBTN_H
    #define CFORECASTBTN_H
    
    #include 
    
    namespace Ui {
    class CForecastBtn;
    }
    
    class CForecastBtn : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit CForecastBtn(QWidget *parent = nullptr);
        ~CForecastBtn();
    
        /**
         * @brief setBtnInfo 设置按钮显示信息
         * @param week 周几
         * @param weather 天气
         * @param dayTemp 日间温度
         * @param nightTemp 夜间温度
         */
        void setBtnInfo(QString week, QString weather, QString dayTemp, QString nightTemp);
    signals:
        /**
         * @brief clicked 点击信号
         */
        void clicked();
    
    private:
        Ui::CForecastBtn *ui;
    
        // QWidget interface
    protected:
        /**
         * @brief mouseReleaseEvent 鼠标释放时间
         * @param event 事件对象
         */
        void mouseReleaseEvent(QMouseEvent *event);
    };
    
    #endif // CFORECASTBTN_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    CForecastBtn.cpp

    #include "CForecastBtn.h"
    #include "ui_CForecastBtn.h"
    
    #include 
    
    CForecastBtn::CForecastBtn(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::CForecastBtn)
    {
        ui->setupUi(this);
    }
    
    CForecastBtn::~CForecastBtn()
    {
        delete ui;
    }
    
    void CForecastBtn::setBtnInfo(QString week, QString weather, QString dayTemp, QString nightTemp)
    {
        // 设置周标签
        ui->weekLab->setText(week);
        // 设置天气
        ui->weatherLab->setText(weather);
        // 设置温度标签
        ui->tempLab->setText(nightTemp + "°~" + dayTemp + "°");
    }
    
    void CForecastBtn::mouseReleaseEvent(QMouseEvent *event)
    {
        // 当前为左键按钮时进入
        if(Qt::LeftButton == event->button())
        {
            // 发出点击信号
            emit clicked();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    CForecastBtn.ui

    
    <ui version="4.0">
     <class>CForecastBtnclass>
     <widget class="QWidget" name="CForecastBtn">
      <property name="geometry">
       <rect>
        <x>0x>
        <y>0y>
        <width>72width>
        <height>66height>
       rect>
      property>
      <property name="windowTitle">
       <string>Formstring>
      property>
      <layout class="QVBoxLayout" name="verticalLayout">
       <item alignment="Qt::AlignHCenter">
        <widget class="QLabel" name="weekLab">
         <property name="text">
          <string>星期string>
         property>
        widget>
       item>
       <item alignment="Qt::AlignHCenter">
        <widget class="QLabel" name="weatherLab">
         <property name="text">
          <string>天气string>
         property>
        widget>
       item>
       <item alignment="Qt::AlignHCenter">
        <widget class="QLabel" name="tempLab">
         <property name="text">
          <string>0°C~0°Cstring>
         property>
        widget>
       item>
      layout>
     widget>
     <resources/>
     <connections/>
    ui>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    6.3 预报天气模块类

    CForecastWidget.h

    #ifndef CFORECASTWIDGET_H
    #define CFORECASTWIDGET_H
    
    #include "StWeatherForecast.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    
    QT_CHARTS_USE_NAMESPACE // 使用chart的命名空间
    
    namespace Ui {
    class CForecastWidget;
    }
    
    
    class CForecastWidget : public QWidget
    {
        Q_OBJECT
    public:
        explicit CForecastWidget(QWidget *parent = nullptr);
        ~CForecastWidget();
    
        /**
         * @brief initialize 初始化类(使构造函数不做过多的操作)
         * @return 初始化标志值(通过该值区分是否初始化成功或初始化到哪一步)
         */
        int initialize();
    
        /**
         * @brief unInitialize 初始化类(使析构函数不做过多的操作)
         * @return 反初始化标志值(通过该值区分是否释放成功或释放到哪一步)
         */
        int unInitialize();
    
        /**
         * @brief updateWeatherInfo 更新按钮和图表信息
         * @param infoList 预报天气结构体联邦
         */
        void updateWeatherInfo(const QList<stForecastsInfo> &infoList);
    
        /**
         * @brief releaseBtn 释放自定义按钮对象
         */
        void releaseBtn();
    
    signals:
        /**
         * @brief forecastBtnClickedSig 转发按钮点击信号
         * @param index 点击按钮索引
         */
        void forecastBtnClickedSig(int index);
    
    public slots:
    
    private:
        Ui::CForecastWidget     *ui;
    
        QChart                  *m_lineChart;   // 折线图的chart
    
        QLineSeries             *m_daySeries;   // 日间温度序列
    
        QLineSeries             *m_nightSeries; // 夜间温度序列
    
        QDateTimeAxis           *m_dateXAxis;   // 折线图的X轴
    
        QValueAxis              *m_valueYAxis;  // Y轴对象
    
    };
    
    #endif // CFORECASTWIDGET_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    CForecastWidget.cpp

    #include "CForecastWidget.h"
    #include "ui_CForecastWidget.h"
    #include "CForecastBtn.h"
    
    #include 
    
    CForecastWidget::CForecastWidget(QWidget *parent)
        : QWidget(parent)
        , ui(nullptr)
        , m_lineChart(nullptr)
        , m_daySeries(nullptr)
        , m_nightSeries(nullptr)
        , m_dateXAxis(nullptr)
        , m_valueYAxis(nullptr)
    {
    
    }
    
    CForecastWidget::~CForecastWidget()
    {
    
    }
    
    int CForecastWidget::initialize()
    {
        // 返回值对象
        int ret = 0;
    
        if(nullptr == ui)
        {
            ui = new Ui::CForecastWidget;
            ui->setupUi(this);
            ret |= 0x1;
        }
    
        // 创建qchart对象
        if(nullptr == m_lineChart)
        {
            // 创建图表对象
            m_lineChart = new QChart;
            // 将图例对象放到图表的左边
            m_lineChart->legend()->setAlignment(Qt::AlignLeft);
            // 创建默认坐标轴
            m_lineChart->createDefaultAxes();
            ret |= 0x10;
        }
    
        // 创建日间序列对象
        if(nullptr == m_daySeries)
        {
            m_daySeries = new QLineSeries;
            // 设置序列名
            m_daySeries->setName("日间温度");
            ret |= 0x100;
        }
    
        // 创建夜间序列对象
        if(nullptr == m_nightSeries)
        {
            m_nightSeries = new QLineSeries;
            // 设置序列名
            m_nightSeries->setName("夜间温度");
            ret |= 0x1000;
        }
    
        // 创建时间(X)轴对象
        if(nullptr == m_dateXAxis)
        {
            m_dateXAxis = new QDateTimeAxis;
            // 设置坐标轴标签显示格式
            m_dateXAxis->setFormat("yyyy/MM/dd");
            ret |= 0x10000;
        }
    
        // 创建Y轴对象
        if(nullptr == m_valueYAxis)
        {
            m_valueYAxis = new QValueAxis;
            ret |= 0x100000;
        }
    
        // 通过返回值对象判断所有对象是否初始化完成,然后做关联设置操作
        if(0x111111 == ret)
        {
            // 将序列对象添加到chart对象中并将chart对象添加到ui中的GraphiView对象中
            m_lineChart->addSeries(m_daySeries);
            m_lineChart->addSeries(m_nightSeries);
            // 添加X、Y轴对象到图表中
            m_lineChart->addAxis(m_dateXAxis, Qt::AlignBottom);
            m_lineChart->addAxis(m_valueYAxis, Qt::AlignLeft);
    
            //! 序列对象关联X、Y坐标轴
            // 关联X轴
            m_daySeries->attachAxis(m_dateXAxis);
            m_nightSeries->attachAxis(m_dateXAxis);
            // 关联Y轴
            m_daySeries->attachAxis(m_valueYAxis);
            m_nightSeries->attachAxis(m_valueYAxis);
    
            // 将图表对象添加到ui中
            ui->weatherChartView->setChart(m_lineChart);
        }
        return ret;
    }
    
    int CForecastWidget::unInitialize()
    {
        // 返回值对象
        int ret = 0;
    
        // 释放自定义按钮对象
        releaseBtn();
    
        // 释放Y轴
        if(nullptr != m_valueYAxis)
        {
            delete m_valueYAxis;
            m_valueYAxis = nullptr;
            ret |= 0x1;
        }
    
        // 释放X轴
        if(nullptr != m_dateXAxis)
        {
            delete m_dateXAxis;
            m_dateXAxis = nullptr;
            ret |= 0x10;
        }
    
        // 释放夜间序列对象
        if(nullptr != m_nightSeries)
        {
            delete m_nightSeries;
            m_nightSeries = nullptr;
            ret |= 0x100;
        }
    
        // 释放日间序列对象
        if(nullptr != m_daySeries)
        {
            delete m_daySeries;
            m_daySeries = nullptr;
            ret |= 0x1000;
        }
    
        // 释放qchart对象
        if(nullptr != m_lineChart)
        {
            delete m_lineChart;
            m_lineChart = nullptr;
            ret |= 0x10000;
        }
    
        // 释放Ui对象
        if(nullptr != ui)
        {
            delete  ui;
            ui = nullptr;
            ret |= 0x100000;
        }
    
        return ret;
    }
    
    void CForecastWidget::updateWeatherInfo(const QList<stForecastsInfo> &infoList)
    {
        // 释放前一次设置的按钮对象
        releaseBtn();
        // 清空日间、夜间序列内容
        m_daySeries->clear();
        m_nightSeries->clear();
    
        // 获取温度最值,方便设置图表Y轴的最值
        int maxTemp = infoList.first().daytemp.toInt(); // 从日间温度取最大值
        int minTemp = infoList.first().nighttemp.toInt(); //从夜间温度取最小值
    
        // 设置时间坐标轴日期范围
        m_dateXAxis->setRange(QDateTime::fromString(infoList.first().date, "yyyy-MM-d")
                              , QDateTime::fromString(infoList.last().date, "yyyy-MM-dd"));
    
        // 遍历预报天气结构体信息容器
        for(int index = 0; index != infoList.size(); ++index)
        {
            // 获取当前日期信息对象
            const stForecastsInfo &info = infoList.at(index);
            // 创建按钮对象
            CForecastBtn *btn = new CForecastBtn;
            // 将按钮添加到布局器中
            ui->forecastBtnLayout->addWidget(btn);
            // 设置按钮对按钮对象的显示信息
            btn->setBtnInfo(info.week, info.dayweather, info.daytemp, info.nighttemp);
            // 连接按钮信号信号槽
            connect(btn, &CForecastBtn::clicked, [=]()
            {
                // 转发点击信号
                emit forecastBtnClickedSig(index);
            });
            // 获取日/夜间温度
            int dayTemp = info.daytemp.toInt();
            int nightTemp = info.nighttemp.toInt();
            //! 时间轴对象需要将时间转换为毫秒来定位索引
            qint64 timeIndex = QDateTime::fromString(infoList[index].date, "yyyy-MM-d").toMSecsSinceEpoch();
            // 将日/夜间温度追加到对应的序列对象中
            m_daySeries->append(timeIndex, dayTemp);
            m_nightSeries->append(timeIndex, nightTemp);
    
            // 通过三目运算符比较当前日/夜间温度,并取出较大/小值
            maxTemp = dayTemp > maxTemp ? dayTemp : maxTemp;
            minTemp = nightTemp < minTemp ? nightTemp : minTemp;
        }
    
        // 设置Y轴的值范围, 并在最大/小值加/减2使图像不那么靠近边界
        m_valueYAxis->setRange(minTemp - 2, maxTemp + 2);
    }
    
    void CForecastWidget::releaseBtn()
    {
        // 定义布局器item对象
        QLayoutItem *child;
        // 循环获取布局器item对象,并判其不为空
        while(nullptr != (child = ui->forecastBtnLayout->takeAt(0)))
        {
            // 获取item对象中的widget
            QWidget *wgt = child->widget();
            // 判断widget是否为空
            if(nullptr != wgt)
            {
                // 释放widget空间
                delete wgt;
            }
            // 释放widget空间
            delete child;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235

    CForecastWidget.ui

    
    <ui version="4.0">
     <class>CForecastWidgetclass>
     <widget class="QWidget" name="CForecastWidget">
      <property name="geometry">
       <rect>
        <x>0x>
        <y>0y>
        <width>400width>
        <height>300height>
       rect>
      property>
      <property name="windowTitle">
       <string>Formstring>
      property>
      <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
       <property name="spacing">
        <number>0number>
       property>
       <property name="leftMargin">
        <number>0number>
       property>
       <property name="topMargin">
        <number>0number>
       property>
       <property name="rightMargin">
        <number>0number>
       property>
       <property name="bottomMargin">
        <number>0number>
       property>
       <item>
        <layout class="QHBoxLayout" name="forecastBtnLayout"/>
       item>
       <item>
        <widget class="QChartView" name="weatherChartView"/>
       item>
      layout>
     widget>
     <customwidgets>
      <customwidget>
       <class>QChartViewclass>
       <extends>QGraphicsViewextends>
       <header location="global">qchartview.hheader>
      customwidget>
     customwidgets>
     <resources/>
     <connections/>
    ui>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    6.4 天气预报主类

    CWeatherForecast.h

    #ifndef CWEATHERFORECAST_H
    #define CWEATHERFORECAST_H
    
    #include "StWeatherForecast.h"
    #include "CForecastWidget.h"
    
    #include 
    #include 
    #include     // 导入请求/接受天气查询API的类
    #include 
    
    namespace Ui {
    class CWeatherForecast;
    }
    
    class CWeatherForecast : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit CWeatherForecast(QWidget *parent = nullptr);
        ~CWeatherForecast();
    
        /**
         * @brief initialize 初始化类(使构造函数不做过多的操作)
         * @return 初始化标志值(通过该值区分是否初始化成功或初始化到哪一步)
         */
        int initialize();
    
        /**
         * @brief unInitialize 初始化类(使析构函数不做过多的操作)
         * @return 反初始化标志值(通过该值区分是否释放成功或释放到哪一步)
         */
        int unInitialize();
    
        /**
         * @brief loadConfig 加载配置文件
         * @param path 指定文件路径
         * @return 是否加载成功
         */
        bool loadConfig(QString path);
    
        /**
         * @brief loadWeatherForecastCfg 加载天气预报配置文件
         * @param path 文件路径
         * @return 是否加载成功
         */
        bool loadWeatherForecastCfg(QString path);
    
        /**
         * @brief readCityInfo 读取城市信息
         * @param root root节点
         * @return 是否读取成功
         */
        bool readCityInfo(const QDomElement &root);
    
        /**
         * @brief readAPiInfo 读取API信息
         * @param root root节点
         * @return 是否读取成功
         */
        bool readAPiInfo(const QDomElement &root);
    
    private:
        /**
         * @brief parseJson json语句转换槽函数
         * @param jsonArray json语句容器
         */
        int parseJson(QByteArray jsonData);
    
        /**
         * @brief parseLiveJson 解析实时天气信息
         * @param weatherInfo 实时天气信息对象
         */
        void parseLiveJson(QJsonObject weatherInfo);
    
        /**
         * @brief parseForecastJson 解析预报天气信息
         * @param weatherInfo 预报天气信息对象
         */
        void parseForecastJson(QJsonObject weatherInfo);
    
        /**
         * @brief loadUiInfo 根据标记值加载ui
         * @param isChecked 标记值
         */
        void loadUiInfo(bool isChecked);
    
        /**
         * @brief loadForeCastInfo 加载指定预报信息结构体的内容
         * @param info 信息结构体
         */
        void loadForeCastInfo(const stForecastsInfo &info);
    
        /**
         * @brief judgeCityEditText 判断城市编辑栏的文本信息
         * @param text 存放文本框信息对应的城市编码
         * @return 文本是否正确, 若是更新文本框信息不正确则不修改编码存储容器传入时的值
         */
        bool judgeCityEditText(QString &text);
    
        /**
         * @brief sendWeatherRequest 发送天气信息请求函数
         */
        void sendWeatherInfoRequest();
    
        /**
         * @brief responseMenuAction 响应右键菜单
         * @param action 右键菜单点击对象
         */
        void responseMenuAction(QAction *action);
    
    private slots:
        /**
         * @brief on_recvNetworkReply 接收API返回数据对象槽函数
         * @param reply 包含API数据的对象
         */
        void on_recvNetworkReply(QNetworkReply *reply);
    
    
        /**
         * @brief on_switchModeBtn_clicked 模式切换按钮槽函数
         * @param checked 当前按钮选中状态
         */
        void on_switchModeBtn_clicked(bool checked);
    
        /**
         * @brief on_forecastBtnClicked 预报天气界面按钮点击槽函数
         * @param index 点击按钮的索引
         */
        void on_forecastBtnClicked(int index);
    
        /**
         * @brief on_provinceComboBox_currentIndexChanged 省份下拉列表框改变槽函数
         * @param arg1 改变的文本
         */
        void on_provinceComboBox_currentIndexChanged(const QString &arg1);
    
        /**
         * @brief on_cityComboBox_currentIndexChanged 城市下拉列表框改变槽函数
         * @param arg1 改变的文本
         */
        void on_cityComboBox_currentIndexChanged(const QString &arg1);
    
        /**
         * @brief on_countyComboBox_currentIndexChanged 区县下拉列表框改变槽函数
         * @param arg1 改变的文本
         */
        void on_countyComboBox_currentIndexChanged(const QString &arg1);
    
        /**
         * @brief on_customContextMenuRequested 定制菜单信号槽函数
         */
        void on_customContextMenuRequested();
    
        /**
         * @brief on_cityEdit_textChanged 城市编辑框文本改变槽函数
         * @param arg1 改变的文本
         */
        void on_cityEdit_textChanged(const QString &arg1);
    
    private:
        Ui::CWeatherForecast                        *ui;
    
        QNetworkAccessManager                       *m_networkAccMgr;       // 访问天气查询API的网络对象
    
        stApiInfo                                   m_stApiInfo;            // api信息结构体对象
    
        stWeatherInfo                               m_stWeatherInfo;        // 天气信息结构体
    
        CForecastWidget                             *m_forecastWgt;         // 预报天气信息图表显示板块
    
        QMap<QString, QMap<QString, QStringList>>   m_cityInfoMap;          // 城市信息容器 <省份,<城市,区县>>
    
        QMap<QString, QString>                      m_codeInfoMap;          // 编码信息容器 <城市,编码>
    
        QCompleter                                  *m_completer;           // 过滤器对象
    
    };
    
    #endif // CWEATHERFORECAST_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182

    CWeatherForecast.cpp

    #include "CWeatherForecast.h"
    #include "ui_CWeatherForecast.h"
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    CWeatherForecast::CWeatherForecast(QWidget *parent)
        : QMainWindow(parent)
        , ui(nullptr)
        , m_networkAccMgr(nullptr)
        , m_forecastWgt(nullptr)
        , m_completer(nullptr)
    {
    }
    
    CWeatherForecast::~CWeatherForecast()
    {
    }
    
    int CWeatherForecast::initialize()
    {
        // 定义返回对象
        int ret = 0;
    
        // 初始化ui
        if(nullptr == ui)
        {
            ui = new Ui::CWeatherForecast;
            ui->setupUi(this);
    
            // 设置右键菜单信号发送
            this->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
            connect(this, &CWeatherForecast::customContextMenuRequested
                    , this, &CWeatherForecast::on_customContextMenuRequested);
            ret |= 0x1;
        }
    
        // 初始化网络访问对象
        if(nullptr == m_networkAccMgr)
        {
            // 创建网络访问对象空间
            m_networkAccMgr = new QNetworkAccessManager(this);
            // 连接接受网络返回的信号槽
            connect(m_networkAccMgr, SIGNAL(finished(QNetworkReply *))
                    , this, SLOT(on_recvNetworkReply(QNetworkReply *)));
            ret |= 0x10;
        }
    
        // 初始化预报信息图表模块
        if(nullptr == m_forecastWgt)
        {
            m_forecastWgt = new CForecastWidget;
            m_forecastWgt->initialize();
    
            // 链接信号槽
            connect(m_forecastWgt, &CForecastWidget::forecastBtnClickedSig, [=](int index)
            {
               loadForeCastInfo(m_stWeatherInfo.stForecastInfoList.at(index));
            });
            ret |= 0x100;
    
        }
    
        // 创建过滤器对象
        if(nullptr == m_completer)
        {
            m_completer = new QCompleter;
            ret |= 0x1000;
        }
    
        // 加载城市信息配置文件
        QString fileName = "./Config/CityCodeInfo.xml";
        if(!loadConfig(fileName))
        {
            QMessageBox::information(this, "提示", fileName + ":文件加载失败");
        }
    
        // 加载天气预报配置文件
        fileName = "./Config/WeatherApi.xml";
        if(!loadConfig(fileName))
        {
            QMessageBox::information(this, "提示", fileName + ":文件加载失败");
        }
    
        // 通过返回值对象判断所有对象是否初始化完成,然后做关联设置操作
        if(0x1111 == ret)
        {
            // 隐藏城市编辑框
            ui->cityEdit->hide();
            // 将预报天气信息控件添加到ui中
            ui->forecastLayout->addWidget(m_forecastWgt);
            ui->forecastLayout->setStretch(0, 3);
            ui->forecastLayout->setStretch(1, 5);
    
            // 创建提示信息列表容器,并添加城市名称信息
            QStringList listTemp = m_codeInfoMap.keys();
            // 追加城市编码信息
            listTemp.append(m_codeInfoMap.values());
            // 创建提示信息存储的数据模板,并指定父对象
            QStringListModel *model = new QStringListModel(m_completer);
            // 将提示信息设置到模板中
            model->setStringList(listTemp);
            // 将模板设置到过滤器对象中
            m_completer->setModel(model);
            // 将过滤器对象设置到城市编辑栏中
            ui->cityEdit->setCompleter(m_completer);
    
            // 设置省份下拉框
            ui->provinceComboBox->addItems(m_cityInfoMap.keys());
        }
    
        return ret;
    }
    
    int CWeatherForecast::unInitialize()
    {
        // 定义返回对象
        int ret = 0;
        // 释放过滤器对象
        if(nullptr != m_completer)
        {
            delete m_completer;
            m_completer = nullptr;
            ret |= 0x1;
        }
    
        // 释放预报信息对象
        if(nullptr != m_forecastWgt)
        {
            m_forecastWgt->unInitialize();
            delete m_forecastWgt;
            m_forecastWgt = nullptr;  
            ret |= 0x10;
        }
    
        // 释放API访问对象
        if(nullptr != m_networkAccMgr)
        {
            delete m_networkAccMgr;
            m_networkAccMgr = nullptr;
            ret |= 0x100;
        }
    
        // 释放ui
        if(nullptr != ui)
        {
            delete ui;
            ui = nullptr;
            ret |= 0x1000;
        }
        return ret;
    }
    
    bool CWeatherForecast::loadWeatherForecastCfg(QString path)
    {
        bool ret = false;
        do
        {
            // 指定文件并打开
            QFile file(path);
            if(!file.open(QIODevice::ReadOnly))
            {
                QMessageBox::information(this, "提示", path + ":文件打开失败");
                ret = false;
                break;
            }
    
            // 创建QDomDocument对象并设置文档类型名
            QDomDocument domDoc;
            // 设置domDoc的上下文
            if(!domDoc.setContent(&file))
            {
                // 上下文设置失败,关闭QFile对象打开的文件
                file.close();
                QMessageBox::information(this, "提示", path + ":QDomDocument对象上下文设置失败");
                ret = false;
                break;
            }
            // 上下文设置成功不再使用QFile对象打开的文件,将其关闭
            file.close();
    
            // 从QDomDocument对象中取到对应的顶级节点元素对象
            QDomElement apiInfo = domDoc.firstChildElement("Root");
            // 判断顶级节点元素对象是否为空
            if(apiInfo.isNull())
            {
                QMessageBox::information(this, "提示", path + ":ApiInfo节点元素对象获取失败");
                ret = false;
                break;
            }
    
            // 一次获取指定的apiInfo子节点,并且获取其值
            m_stApiInfo.link = apiInfo.firstChildElement("Link").attribute("Link");
            m_stApiInfo.apiKey = apiInfo.firstChildElement("ApiKey").attribute("ApiKey");
            m_stApiInfo.cityCode = apiInfo.firstChildElement("CityCode").attribute("CityCode");
            m_stApiInfo.extensions = apiInfo.firstChildElement("Extensions").attribute("Extensions");
            // 返回值变为true
            ret = true;
        }while(false);
        return ret;
    }
    
    bool CWeatherForecast::readCityInfo(const QDomElement &root)
    {
        // 创建省份名对象
        QString province;
        // 创建城市名对象
        QString city;
        // 获取首个城市信息节点
        QDomElement element = root.firstChildElement("CityInfo");
        // 遍历root节点中的城市信息子节点
        while(!element.isNull())
        {
            // 获取城市名和城市编码
            QString name = element.attribute("Name");
            QString code = element.attribute("Code");
            // 判断城市名和城市编码不为空
            if(code.endsWith("0000"))
            {
                // 省份对象赋值
                province = name;
                // 将省份编码信息填入容器
                m_codeInfoMap[province] = code;
            }
            else if(code.endsWith("00"))
            {
                // 城市对象赋值
                city = name;
            }
            else if(!name.contains("市辖区"))  // 不包含“市辖区”的名才添加
            {
                // 区县值添加
                m_cityInfoMap[province][city].append(name);
                // 添加区县编码信息
                m_codeInfoMap[name] = code;
            }
    
            // 获取下一个信息子节点
            element = element.nextSiblingElement();
        }
    
        // 判断容器是否为空并返回
        return !m_cityInfoMap.isEmpty() && !m_codeInfoMap.isEmpty();
    }
    
    bool CWeatherForecast::loadConfig(QString path)
    {
        bool ret = false;
        do
        {
            // 指定文件并打开
            QFile file(path);
            if(!file.open(QIODevice::ReadOnly))
            {
                QMessageBox::information(this, "提示", path + ":文件打开失败");
                ret = false;
                break;
            }
    
            // 创建QDomDocument对象并设置文档类型名
            QDomDocument domDoc;
            // 设置domDoc的上下文
            if(!domDoc.setContent(&file))
            {
                // 上下文设置失败,关闭QFile对象打开的文件
                file.close();
                QMessageBox::information(this, "提示", path + ":QDomDocument对象上下文设置失败");
                ret = false;
                break;
            }
            // 上下文设置成功不再使用QFile对象打开的文件,将其关闭
            file.close();
    
            // 从QDomDocument对象中取到对应的顶级节点元素对象
            QDomElement root = domDoc.firstChildElement("Root");
            // 判断顶级节点元素对象是否为空
            if(root.isNull())
            {
                QMessageBox::information(this, "提示", path + ":root节点元素对象获取失败");
                ret = false;
                break;
            }
    
            QString type = root.attribute("Type");
    
            if(0 == type.compare("CityInfo"))
            {
                // 获取返回值
                ret = readCityInfo(root);
    
            }
            else if(0 == type.compare("ApiInfo"))
            {
                // 获取返回值
                ret = readAPiInfo(root);
            }
        }while(false);
        return ret;
    }
    
    bool CWeatherForecast::readAPiInfo(const QDomElement &root)
    {
        // 一次获取指定的apiInfo子节点,并且获取其值
        m_stApiInfo.link = root.firstChildElement("Link").attribute("Link");
        m_stApiInfo.apiKey = root.firstChildElement("ApiKey").attribute("ApiKey");
        m_stApiInfo.cityCode = root.firstChildElement("CityCode").attribute("CityCode");
        m_stApiInfo.extensions = root.firstChildElement("Extensions").attribute("Extensions");
        // 判断节点值是否存在空值
        return !m_stApiInfo.fieldIsEmpty();
    }
    
    int CWeatherForecast::parseJson(QByteArray jsonData)
    {
        // 创建返回值对象
        int ret = 0;
    
        //! 创建QJsonParseError对象,用于判断Json是否正确
        //! 尽管从API中返回的Json基本正确,但是流程还是要走,养成好习惯
        QJsonParseError jsonError;
        // 将json数据和jsonError对象传入fromJson函数中
        QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &jsonError);
        // 判断错误码是否不等于QJsonParseError::NoError,不等于则返回
        if(jsonError.error != QJsonParseError::NoError)
        {
            return ret;
        }
    
        // 创建QJsonObject对象接收object的返回值
        QJsonObject jsonObj = jsonDoc.object();
    
        //! 判断接收的Json串是否正确
        //! status为1那么状态为成功,infocode为10000则返回状态为正确
        if("1" != jsonObj.value("status").toString() || "10000" != jsonObj.value("infocode").toString())
        {
            QMessageBox::warning(nullptr, "警告", "数据返回失败/错误");
            return ret;
        }
    
        // 获取当前模式按钮的选中状态
        bool isChecked = ui->switchModeBtn->isChecked();
        // 通过模式切换按钮判断获取当前模式
        QString infoType = isChecked ? "forecasts" : "lives";
        //! 通过infoType获取对应的内容
        //! 因为infoType下的标识符为‘[’所以先转换为数组
        //! 然后取数组下第一个元素并将其转为QJsonObject对象
        QJsonObject weatherInfo = jsonObj.value(infoType).toArray().at(0).toObject();
        // 读取基础信息(省份、城市、区域编码、报告时间)
        m_stWeatherInfo.setBaseInfo(weatherInfo.value("province").toString()
                                    , weatherInfo.value("city").toString()
                                    , weatherInfo.value("adcode").toString()
                                    , weatherInfo.value("reporttime").toString());
    
        // 通过按钮选中状态使用不同模式的转换函数
        if(isChecked)
        {
            // 预报天气转换
            parseForecastJson(weatherInfo);
        }
        else
        {
            // 实时天气转换
            parseLiveJson(weatherInfo);
        }
    
        return ret;
    }
    
    void CWeatherForecast::parseLiveJson(QJsonObject weatherInfo)
    {
        // 获取天气
        QString weather = weatherInfo.value("weather").toString();
        // 获取温度
        QString temperature = weatherInfo.value("temperature").toString();
        // 获取风向
        QString winddirection = weatherInfo.value("winddirection").toString();
        // 获取风力
        QString windpower = weatherInfo.value("windpower").toString();
        // 获取湿度
        QString humidity = weatherInfo.value("humidity").toString();
        // 设置信息
        m_stWeatherInfo.stliveInfo.setWeatherInfo(weather, temperature
                                                  , winddirection, windpower, humidity);
        if(m_stWeatherInfo.stliveInfo.fieldIsEmpty())
        {
            QMessageBox::information(this, "提示", "没有新的天气信息");
            return;
        }
        loadUiInfo(false);
    }
    
    void CWeatherForecast::parseForecastJson(QJsonObject weatherInfo)
    {
        // 每次添加将上次的预报天气信息清空
        m_stWeatherInfo.stForecastInfoList.clear();
    
        // 获取cast的内容,并将其转为数组
        QJsonArray forecastArray = weatherInfo.value("casts").toArray();
        // 获取json数组对象的迭代器
        QJsonArray::const_iterator iterator = forecastArray.begin();
    
        // 判断获取的起始迭代器不等于结束迭代器
        if(forecastArray.end() == iterator)
        {
            QMessageBox::information(this, "提示", "没有新的天气信息");
            return;
        }
    
        // 遍历天气信息
        for(; iterator != forecastArray.end(); ++iterator)
        {
            // 先追加一个预报结构体
            m_stWeatherInfo.stForecastInfoList.append(stForecastsInfo());
            // 获取最新追加结构体的引用对象
            stForecastsInfo &forecastsInfo = m_stWeatherInfo.stForecastInfoList.last();
    
            // 获取当前内容的QJsonObject对象
            QJsonObject forecastsInfoObj = (*iterator).toObject();
            // 设置日期
            forecastsInfo.setDate(forecastsInfoObj.value("date").toString());
            // 设置天气
            forecastsInfo.setWeather(forecastsInfoObj.value("dayweather").toString()
                                     , forecastsInfoObj.value("nightweather").toString());
            // 设置温度
            forecastsInfo.setTemperature(forecastsInfoObj.value("daytemp").toString()
                                     , forecastsInfoObj.value("nighttemp").toString());
            // 设置风向
            forecastsInfo.setWindDirection(forecastsInfoObj.value("daywind").toString()
                                     , forecastsInfoObj.value("nightwind").toString());
            // 设置风力
            forecastsInfo.setWindPower(forecastsInfoObj.value("daypower").toString()
                                     , forecastsInfoObj.value("nightpower").toString());
        }
    
        //加载ui信息
        loadUiInfo(true);
    }
    
    void CWeatherForecast::loadUiInfo(bool isChecked)
    {
        // 设置通用属性
        ui->reportTimeLab->setText(m_stWeatherInfo.reporttime);
        // 城市字符串 省份+城市
        QString cityStr = m_stWeatherInfo.province + "-" +m_stWeatherInfo.city;
        // 设置预报天气信息
        if(isChecked)
        {
            // 设置预报天气城市
            ui->forecastWeatherCityLab->setText(cityStr);
            // 更新预报图表模块信息
            m_forecastWgt->updateWeatherInfo(m_stWeatherInfo.stForecastInfoList);
            // 加载当前显示的天气信息
            loadForeCastInfo(m_stWeatherInfo.stForecastInfoList.first());
        }
        // 设置实时天气信息
        else
        {
            // 设置实时天气城市
            ui->liveWeatherCityLab->setText(cityStr);
            // 获取实时信息的引用
            const stLiveInfo &info = m_stWeatherInfo.stliveInfo;
            // 设置实时信息
            ui->liveTempLab->setText(info.temperature + "°C");
            ui->liveWeatherLab->setText(info.weather);
            ui->liveHumidityLab->setText(info.humidity);
            ui->liveLindPowerLab->setText(info.windpower);
            ui->liveWindDirectionLab->setText(info.winddirection);
        }
    }
    
    void CWeatherForecast::loadForeCastInfo(const stForecastsInfo &info)
    {
        // 将ui上对应的信息设置
        ui->forecastWeatherLab->setText(info.dayweather);
        ui->forecastHighTempLab->setText(info.daytemp + "°C");
        ui->forecastLowTempLab->setText(info.nighttemp + "°C");
        ui->forecastWindPowerLab->setText(info.daypower);
        ui->forecastWindDirectionLab->setText(info.daywind);
        ui->forecastDateLab->setText(info.date + " " +info.week);
    }
    
    bool CWeatherForecast::judgeCityEditText(QString &text)
    {
        // 创建返回值对象
        bool ret = false;
        // 获取城市文本
        QString cityCode = ui->cityEdit->isHidden() ? ui->countyComboBox->currentText() : ui->cityEdit->text();
    
        // 判断文本是否为空
        if(cityCode.isEmpty())
        {
            QMessageBox::information(this, "提示", "请输入城市名称或城市编码");
        }
        else
        {
            // 判断城市名称中是否包含文本
            if(m_codeInfoMap.keys().contains(cityCode))
            {
                // 获取对应城市名的城市编码并赋值
                text = m_codeInfoMap[cityCode];
                ret = true;
            }
            // 获取城市编码是否包含文本框文本
            else if(m_codeInfoMap.values().contains(cityCode))
            {
                // 城市编码正确并赋值
                text = cityCode;
                ret = true;
            }
            else
            {
                QMessageBox::information(this, "提示", "请输入正确的城市名称或城市编码");
            }
        }
    
        return ret;
    }
    
    void CWeatherForecast::on_recvNetworkReply(QNetworkReply *reply)
    {
        // 判断错误码是否为QNetworkReply::NoError(若判断条件成立,则reply对象数据错误)
        if(reply->error() != QNetworkReply::NoError)
        {
            // 弹出警告
            QMessageBox::warning(nullptr, "警告", "数据返回错误");
        }
        else
        {
            // 创建array容器接收数据
            QByteArray data;
            // 读取所有json串
            data = reply->readAll();
            // 解析json串
            parseJson(data);
    
        }
        // 释放内存,防止内存泄漏
        delete reply;
        reply = nullptr;
    }
    
    void CWeatherForecast::sendWeatherInfoRequest()
    {
        if(judgeCityEditText(m_stApiInfo.cityCode))
        {
            // 调用组合API链接函数申请API
            QUrl url(m_stApiInfo.joinApiLink());
            // 获取天气预报回执;此处返回的QNetworkReply对象将在on_recvNetworkReply槽函数中体现,可不在此接收释放。       
            m_networkAccMgr->get(QNetworkRequest(url));
        }
    }
    
    void CWeatherForecast::responseMenuAction(QAction *action)
    {
        // 当参数值为空时返回
        if(nullptr == action)
        {
            return;
        }
    
        QString text = action->text();
        if("刷新" == text)
        {
            // 发送天气信息请求
            sendWeatherInfoRequest();
        }
        else
        {
            // 获取城市编辑栏当前显示状态
            bool isHidden = ui->cityEdit->isHidden();
            // 将城市编辑栏显示状态取反设置
            ui->cityEdit->setHidden(!isHidden);
            // 设置城市选择模式显隐状态
            ui->selectModeWgt->setHidden(isHidden);
            if(isHidden)
            {
                // 获取选择模式下当前城市名
                QString text = ui->countyComboBox->currentText();
                // 将当前城市名设置到编辑栏中
                ui->cityEdit->setText(text);
            }
            else
            {
                // 获取当前区县编码值
                QString countyCode = m_stApiInfo.cityCode;
                // 通过当前区县编码值获取当前区县名
                QString countyName = m_codeInfoMap.key(m_stApiInfo.cityCode);
                bool contain = m_codeInfoMap.values().contains(countyCode);
    
                // 通过当前区县编码值获取当前城市编码值
                QString cityCode = countyCode.replace(countyCode.size() - 2, 2, "00");
                contain = m_codeInfoMap.values().contains(cityCode);
    
                // 通过省份编码值获取省份名
                QString cityName = m_codeInfoMap.key(cityCode);
                // 包含市辖区时移除市辖区文本
                cityName = cityName.replace("市辖区", "");
    
                // 通过当前区县编码值获取当前省份编码值
                QString provinceCode = countyCode.replace(countyCode.size() - 4, 4, "0000");
                contain = m_codeInfoMap.values().contains(provinceCode);
                // 通过省份编码值获取省份名
                QString provinceName = m_codeInfoMap.key(provinceCode);
    
                // 然后将获取到的三个值更新到下拉框中
                // 设置省份
                ui->provinceComboBox->setCurrentText(provinceName);
                // 设置城市
                ui->cityComboBox->setCurrentText(cityName);
                // 设置区县
                ui->countyComboBox->setCurrentText(countyName);
            }
        }
    }
    
    void CWeatherForecast::on_switchModeBtn_clicked(bool checked)
    {
        // 判断选中状态,获取将要设置对应的文本
        QString text = checked ? "预报天气" : "实时天气";
        // 设置当前显示的文本
        ui->switchModeBtn->setText(text);
    
        // 设置API扩展参数变量的新值
        m_stApiInfo.extensions = checked ? "all" : "base";
    
        // 设置当前栈模式对应的窗口
        ui->stackedWidget->setCurrentIndex(checked ? 1 : 0);
    
        // 发送天气信息请求
        sendWeatherInfoRequest();
    }
    
    void CWeatherForecast::on_forecastBtnClicked(int index)
    {
        if(index < m_stWeatherInfo.stForecastInfoList.size())
        {
            loadForeCastInfo(m_stWeatherInfo.stForecastInfoList.at(index));
        }
    }
    
    void CWeatherForecast::on_provinceComboBox_currentIndexChanged(const QString &arg1)
    {
        //! 当省份变化时,城市下拉列表框将要清空
        ui->cityComboBox->clear();
        //! 然后添加对应的城市列表
        ui->cityComboBox->addItems(m_cityInfoMap[arg1].keys());
    }
    
    void CWeatherForecast::on_cityComboBox_currentIndexChanged(const QString &arg1)
    {
        // 当当前文本内容为空时返回
        if(arg1.isEmpty())
        {
            return;
        }
        //! 当城市变化时,区/县下拉列表框将要清空
        ui->countyComboBox->clear();
        //! 然后添加对应的区县列表
        ui->countyComboBox->addItems(m_cityInfoMap[ui->provinceComboBox->currentText()][arg1]);
    }
    
    void CWeatherForecast::on_countyComboBox_currentIndexChanged(const QString &arg1)
    {
        // 当当前文本内容为空时返回
        if(arg1.isEmpty())
        {
            return;
        }
        // 区县改变时将要
        m_stApiInfo.cityCode = m_codeInfoMap[arg1];
        // 发送天气信息请求
        sendWeatherInfoRequest();
    }
    
    void CWeatherForecast::on_customContextMenuRequested()
    {
        // 创建菜单变量
        QMenu menu;
        // 添加菜单选项
        menu.addAction(new QAction("刷新", &menu));
        menu.addAction(new QAction("切换城市选择模式", &menu));
        // 显示菜单,并且显示位置为鼠标位置,并接收返回的对象
        QAction *action = menu.exec(QCursor::pos());
        responseMenuAction(action);
    }
    
    void CWeatherForecast::on_cityEdit_textChanged(const QString &arg1)
    {
        // 当城市编码容器包含当前文本Key值则进入
        if(m_codeInfoMap.contains(arg1) || m_codeInfoMap.values().contains(arg1))
        {
            // 发送天气信息请求
            sendWeatherInfoRequest();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628
    • 629
    • 630
    • 631
    • 632
    • 633
    • 634
    • 635
    • 636
    • 637
    • 638
    • 639
    • 640
    • 641
    • 642
    • 643
    • 644
    • 645
    • 646
    • 647
    • 648
    • 649
    • 650
    • 651
    • 652
    • 653
    • 654
    • 655
    • 656
    • 657
    • 658
    • 659
    • 660
    • 661
    • 662
    • 663
    • 664
    • 665
    • 666
    • 667
    • 668
    • 669
    • 670
    • 671
    • 672
    • 673
    • 674
    • 675
    • 676
    • 677
    • 678
    • 679
    • 680
    • 681
    • 682
    • 683
    • 684
    • 685
    • 686
    • 687
    • 688
    • 689
    • 690
    • 691
    • 692
    • 693
    • 694
    • 695
    • 696
    • 697
    • 698
    • 699
    • 700
    • 701
    • 702
    • 703
    • 704

    CWeatherForecast.ui

    
    <ui version="4.0">
     <class>CWeatherForecastclass>
     <widget class="QMainWindow" name="CWeatherForecast">
      <property name="geometry">
       <rect>
        <x>0x>
        <y>0y>
        <width>649width>
        <height>450height>
       rect>
      property>
      <property name="windowTitle">
       <string>CWeatherForecaststring>
      property>
      <widget class="QWidget" name="centralWidget">
       <layout class="QVBoxLayout" name="verticalLayout">
        <item>
         <layout class="QHBoxLayout" name="horizontalLayout_7">
          <item>
           <widget class="QPushButton" name="switchModeBtn">
            <property name="text">
             <string>实时天气string>
            property>
            <property name="checkable">
             <bool>truebool>
            property>
           widget>
          item>
          <item>
           <widget class="QLineEdit" name="cityEdit">
            <property name="placeholderText">
             <string>请输入城市/城市编码string>
            property>
           widget>
          item>
          <item>
           <widget class="QWidget" name="selectModeWgt" native="true">
            <layout class="QHBoxLayout" name="horizontalLayout_6">
             <property name="leftMargin">
              <number>0number>
             property>
             <property name="topMargin">
              <number>0number>
             property>
             <property name="rightMargin">
              <number>0number>
             property>
             <property name="bottomMargin">
              <number>0number>
             property>
             <item>
              <widget class="QComboBox" name="provinceComboBox"/>
             item>
             <item>
              <widget class="QComboBox" name="cityComboBox"/>
             item>
             <item>
              <widget class="QComboBox" name="countyComboBox"/>
             item>
            layout>
           widget>
          item>
          <item>
           <spacer name="horizontalSpacer_2">
            <property name="orientation">
             <enum>Qt::Horizontalenum>
            property>
            <property name="sizeHint" stdset="0">
             <size>
              <width>40width>
              <height>20height>
             size>
            property>
           spacer>
          item>
          <item>
           <widget class="QLabel" name="label_4">
            <property name="text">
             <string>报告时间:string>
            property>
           widget>
          item>
          <item>
           <widget class="QLabel" name="reportTimeLab">
            <property name="text">
             <string>报告时间string>
            property>
           widget>
          item>
         layout>
        item>
        <item>
         <widget class="QStackedWidget" name="stackedWidget">
          <property name="currentIndex">
           <number>0number>
          property>
          <widget class="QWidget" name="page">
           <layout class="QVBoxLayout" name="verticalLayout_2" stretch="3,1">
            <property name="spacing">
             <number>0number>
            property>
            <property name="leftMargin">
             <number>0number>
            property>
            <property name="topMargin">
             <number>0number>
            property>
            <property name="rightMargin">
             <number>0number>
            property>
            <property name="bottomMargin">
             <number>0number>
            property>
            <item>
             <layout class="QGridLayout" name="gridLayout_2" rowstretch="0,0" columnstretch="1,1,3">
              <property name="spacing">
               <number>0number>
              property>
              <item row="0" column="0">
               <widget class="QLabel" name="liveWeatherCityLab">
                <property name="text">
                 <string>城市标签string>
                property>
               widget>
              item>
              <item row="0" column="1">
               <widget class="QLabel" name="liveTempLab">
                <property name="text">
                 <string>°Cstring>
                property>
               widget>
              item>
              <item row="0" column="2" rowspan="2">
               <spacer name="horizontalSpacer">
                <property name="orientation">
                 <enum>Qt::Horizontalenum>
                property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>40width>
                  <height>20height>
                 size>
                property>
               spacer>
              item>
              <item row="1" column="0">
               <widget class="QLabel" name="liveWeatherImgLab">
                <property name="text">
                 <string>天气图标string>
                property>
               widget>
              item>
              <item row="1" column="1">
               <widget class="QLabel" name="liveWeatherLab">
                <property name="text">
                 <string>天气string>
                property>
               widget>
              item>
             layout>
            item>
            <item>
             <layout class="QHBoxLayout" name="horizontalLayout_2">
              <item>
               <layout class="QHBoxLayout" name="horizontalLayout">
                <property name="spacing">
                 <number>0number>
                property>
                <item>
                 <widget class="QLabel" name="lab">
                  <property name="text">
                   <string>风速:string>
                  property>
                 widget>
                item>
                <item>
                 <widget class="QLabel" name="liveLindPowerLab">
                  <property name="text">
                   <string>风速string>
                  property>
                 widget>
                item>
               layout>
              item>
              <item>
               <layout class="QHBoxLayout" name="horizontalLayout_4">
                <property name="spacing">
                 <number>0number>
                property>
                <item>
                 <widget class="QLabel" name="label_11">
                  <property name="text">
                   <string>风向:string>
                  property>
                 widget>
                item>
                <item>
                 <widget class="QLabel" name="liveWindDirectionLab">
                  <property name="text">
                   <string>风向string>
                  property>
                 widget>
                item>
               layout>
              item>
              <item>
               <layout class="QHBoxLayout" name="horizontalLayout_5">
                <property name="spacing">
                 <number>0number>
                property>
                <item>
                 <widget class="QLabel" name="label_12">
                  <property name="text">
                   <string>湿度:string>
                  property>
                 widget>
                item>
                <item>
                 <widget class="QLabel" name="liveHumidityLab">
                  <property name="text">
                   <string>湿度string>
                  property>
                 widget>
                item>
               layout>
              item>
             layout>
            item>
           layout>
          widget>
          <widget class="QWidget" name="page_2">
           <layout class="QVBoxLayout" name="forecastLayout">
            <property name="spacing">
             <number>0number>
            property>
            <property name="leftMargin">
             <number>0number>
            property>
            <property name="topMargin">
             <number>0number>
            property>
            <property name="rightMargin">
             <number>0number>
            property>
            <property name="bottomMargin">
             <number>0number>
            property>
            <item>
             <layout class="QGridLayout" name="gridLayout">
              <property name="rightMargin">
               <number>80number>
              property>
              <item row="1" column="0">
               <widget class="QLabel" name="forecastWeatherImgLab">
                <property name="text">
                 <string>天气图标string>
                property>
               widget>
              item>
              <item row="1" column="1">
               <widget class="QLabel" name="forecastHighTempLab">
                <property name="text">
                 <string>°Cstring>
                property>
               widget>
              item>
              <item row="1" column="2">
               <layout class="QHBoxLayout" name="horizontalLayout_8">
                <property name="spacing">
                 <number>0number>
                property>
                <item>
                 <widget class="QLabel" name="lab_2">
                  <property name="text">
                   <string>风速:string>
                  property>
                 widget>
                item>
                <item>
                 <widget class="QLabel" name="forecastWindPowerLab">
                  <property name="text">
                   <string>风速string>
                  property>
                 widget>
                item>
               layout>
              item>
              <item row="2" column="1">
               <widget class="QLabel" name="forecastLowTempLab">
                <property name="text">
                 <string>°Cstring>
                property>
               widget>
              item>
              <item row="2" column="2">
               <layout class="QHBoxLayout" name="horizontalLayout_9">
                <property name="spacing">
                 <number>0number>
                property>
                <item>
                 <widget class="QLabel" name="label_14">
                  <property name="text">
                   <string>风向:string>
                  property>
                 widget>
                item>
                <item>
                 <widget class="QLabel" name="forecastWindDirectionLab">
                  <property name="text">
                   <string>风向string>
                  property>
                 widget>
                item>
               layout>
              item>
              <item row="0" column="1">
               <widget class="QLabel" name="forecastDateLab">
                <property name="text">
                 <string>星期 日期string>
                property>
               widget>
              item>
              <item row="0" column="0">
               <widget class="QLabel" name="forecastWeatherCityLab">
                <property name="text">
                 <string>城市标签string>
                property>
               widget>
              item>
              <item row="2" column="0">
               <widget class="QLabel" name="forecastWeatherLab">
                <property name="text">
                 <string>天气string>
                property>
               widget>
              item>
             layout>
            item>
           layout>
          widget>
         widget>
        item>
       layout>
      widget>
      <widget class="QMenuBar" name="menuBar">
       <property name="geometry">
        <rect>
         <x>0x>
         <y>0y>
         <width>649width>
         <height>23height>
        rect>
       property>
      widget>
     widget>
     <layoutdefault spacing="6" margin="11"/>
     <resources/>
     <connections/>
    ui>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361

    总结

    本文通过高德开放平台的天气预报模块获取天气预报信息,然后通过Qt各个类实现天气预报的基本功能。因为各个平台的差异,如返回的天数、天气Json格式、信息等各不相同,所以文本也就固定了仅支持高德开放平台提供的天气预报接口。总的来说,功能不算复杂,比较适合新手练习使用.
    然后是汇报一下近况,为什么更新变慢了,其一是近期公司项目进入收尾,加班增多;其次则是生活和天气原因,再加上每日私人编程时间有限等情况的影响。但我还是会持续更新,下一章为"天气预报-界面优化篇",敬请期待叭。

    相关文章

    天气预报系列

    Qt之天气预报实现(一)预备篇
    Qt之天气预报——界面优化篇(含源码+注释)

    相关类的基本使用

    Qt读取Json文件(含源码+注释)
    Qt读写XML文件(含源码+注释)
    Qt之QChart各个图表的简单使用(含源码+注释)
    Qt创建右键菜单的两种通用方法(QTableView实现右键菜单,含源码+注释)
    Qt之QCompleter的简单使用(自动补全、文本框提示、下拉框提示含源码+注释)

    友情提示——哪里看不懂可私哦,让我们一起互相进步吧
    (创作不易,请留下一个免费的赞叭 谢谢 ^o^/)

    注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
    注:如有侵权,请联系作者删除

  • 相关阅读:
    关于Unity Inspector上的一些常用技巧,一般用于编辑器扩展或者其他
    PHP旅游管理系统Dreamweaver开发mysql数据库web结构php编程计算机网页
    微信小程序——标签wxml、样式wxss、js、json
    vos3000源码(各个版本机器人部署)
    day23-数据接口和selenium基础
    关于三维布尔运算的几点思考
    只是巧合?苹果iOS16的神秘技术竟然与中国企业5年前产品一致!
    线段树维护势能类 / 均摊类问题:CF403E
    CSDN竞赛六期
    考公顺序步骤
  • 原文地址:https://blog.csdn.net/wj584652425/article/details/128046864