1. HTTP基本概念
• HTTP(超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议。它是万维网(WWW)的数据通信的基础。了解HTTP的基本概念对于理解现代网络通信至关重要。以下是HTTP的一些核心概念:
1.**请求和响应:
HTTP是一个基于请求****-** 响应模式的协议。客户端(通常是Web浏览器)向服务器发送一个HTTP请求,然后服务器返回一个HTTP响应。**请求包含请求的资源(如网页),而响应包含请求的资源的内容。
**2. HTTP方法:
HTTP定义了一系列的方法来表明对资源的不同操作,最常用的包括:
• GET: 用于请求资源。
• POST: 用于提交数据给服务器(例如,表单数据)。
• PUT: 用于上传文件或内容。
• DELETE: 用于请求删除资源。
• HEAD : 用于获取资源的元信息,而不是资源本身。
3.**状态码:
服务器对请求的响应中包含一个状态码**,它表示请求的成功或失败,以及失败的原因。常见的状态码包括:
• 200 OK: 请求成功。
• 404 Not Found: 请求的资源未找到。
• 500 Internal Server Error: 服务器内部错误。
• 301 Moved Permanently: 请求的资源已永久移动到新位置。
4. URL(统一资源定位符):
URL是Web 上资源的地址。它指定了资源的位置以及用于访问资源的协议(例如,http://)。
**5. HTTP**头:
HTTP请求和响应包含头部信息,这些信息包括元数据,如内容类型、内容长度、服务器信息、客户端信息等。例如, Content-Type 头部指示响应中的媒体类型(如text/html,application/json)。
6.**无状态协议:
HTTP是一个无状态协议** ,这意味着服务器不会保留任何请求的数据(状态)。然而,通过使用如
Cookies这样的机制,可以在多个请求之间维持状态。
7.**安全性(HTTPS):
HTTPS是HTTP的安全版本,它在HTTP和TCP层之间增加了一个加密层(通常是SSL/TLS** ) 。这提供了数据传输的加密和更好的安全性。
8. RESTful API:
RESTful是一种使用HTTP协议的Web服务设计风格,它利用HTTP的方法来实现API的不同操作。在 RESTful架构中,**每个URL代表一个资源,并使用HTTP的方法(如GET, POST)来处理这些资源。**
9. Session和Cookies:
由于HTTP本身是无状态的,Cookies和会话(Session)被用来在多个请求之间存储用户数据,从而为用户提供连贯的体验。
2. QT的HTTP编程
• Qt中的HTTP编程主要涉及使用Qt的网络模块来进行HTTP请求和处理HTTP响应。Qt提供了一系列类来处理网络通信,其中最常用的类是 QNetworkAccessManager**、 QNetworkRequest 、** QNetworkReply 以及相关的支持类。
3. 代码
3.1 在widget.cpp
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QMenu>
#include <QDebug>
#include <QMessageBox>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QPainter>
#include <QtNetwork/QNetworkAccessManager>
void Widget::mousePressEvent(QMouseEvent *event){
//关闭窗口
if(event->button() == Qt::RightButton){
qDebug() << "right Mouse click";
menuQuit->exec(QCursor::pos());//启动菜单栏,menu出现在鼠标当前位置
}
//关键是获得当前鼠标位置,当前窗口位置,新的窗口位置
//移动窗口(通过初始鼠标的位置减去初始窗口的位置,得到位移值)
//然后在通过新的鼠标位置 - 位移值 = 新的窗口位置
if(event->button() == Qt::LeftButton){
qDebug() << "left Mouse click";
// qDebug() << "鼠标当前在全局的位置" << event->globalPos();//返回的是鼠标事件的全局坐标
// qDebug() << "返回的是当前对象(窗口或部件)在其父容器中的位置" << this->pos(); // 返回的是当前对象(窗口或部件)在其父容器中的位置
// qDebug() << event->globalPos() - this->pos();//返回的是QPoint类型,这是当前鼠标位置和当前窗口位置的差值
moffset = event->globalPos() - this->pos();
}
}
//鼠标左键按下后的移动,导致这个事件被调用,设置窗口的新位置
void Widget::mouseMoveEvent(QMouseEvent *event){
//这是移动窗口
// 1.当鼠标按下的时候,获得当前鼠标和当前窗口的那段偏移值
// 2.当我鼠标拖动的时候,根据偏移值,算出新的窗口该有的位置
this->move(event->globalPos() - moffset);
}
bool Widget::eventFilter(QObject *object, QEvent *event)
{
//判断监控对象是widget0404,并且触发的事件类型是QEvent::Paint
if(object == ui->widget0404 && event->type() == QEvent::Paint){
drawTempLineHigh();
return true;//表示事件应被处理
}
if(object == ui->widget0405 && event->type() == QEvent::Paint){
drawTempLineLow();
return true;
}
return QWidget::eventFilter(object,event);
}
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//界面初始化
setFixedSize(585,962);
//去除上方"打叉关闭"那一行(设置无状态栏)
setWindowFlag(Qt::FramelessWindowHint);
//使用QMenu创建下拉菜单或上下文菜单(右键菜单),来关闭窗口
menuQuit = new QMenu(this);
//QAction代表用户可以执行的具体操作,创建关闭的动作
QAction* closeAct = new QAction(QIcon(":/res/close.png"),tr("关闭"),this);
//把closeAct操作,添加到menuQuit里面
menuQuit->addAction(closeAct);
//美化QMenu,设置菜单项文字颜色
//closeAct = new QAction(QIcon(":/res/search.png"), tr("打开"), this);
//menuQuit->addAction(closeAct);//通过这个验证QMenu也是个菜单。
menuQuit->setStyleSheet("QMenu::item {color:white}");
//创建信号,当菜单中的某个动作被触发(比如用户点击了菜单项)时,这个信号会被发射。
connect(menuQuit,&QMenu::triggered,this,[=]{
//关闭窗口
this->close();
});
//管理所有的网络请求和连接
//在当前窗口,使用QNetworkAccessManager发起get请求
manager = new QNetworkAccessManager(this);
//指定请求的url地址
urlStr = "http://gfeljm.tianqiapi.com/api?unescape=1&version=v9&appid=47132967&appsecret=u8MRztWQ";
//放入QUrl
//urlStr = "";
QUrl tianqiUrl(urlStr);
//指定请求的url地址(封装HTTP请求的配置信息)
QNetworkRequest res(tianqiUrl);
//进行get请求
//获取服务器返回的数据
//QNetworkReply(网络响应),处理服务器返回的数据
reply = manager->get(res);
//绑定信号与槽
//当通过 QNetworkAccessManager 发起的任何网络请求完成后,都会触发此信号(无论成功还是失败都会触发)。
connect(manager,&QNetworkAccessManager::finished,this,&Widget::readHttpReply);
//把所有天气的图标放进map里面
//根据keys,设置icon的路径
//:/res/type/BaoXue.png
mTypeMap.insert("暴雪",":/res/type/BaoXue.png");
mTypeMap.insert("暴雨",":/res/type/BaoYu. png");
mTypeMap.insert("暴雨到大暴雨",":/res/type/BaoYuDaoDaBaoYu.png");
mTypeMap.insert("大暴雨",":/res/type/DaBaoYu.png");
mTypeMap.insert("大暴雨到特大暴雨",":/res/type/DaBaoYuDaoTeDaBaoYu.png");
mTypeMap.insert("大到暴雪",":/res/type/DaDaoBaoXue.png");
mTypeMap.insert("大雪",":/res/type/DaXue.png");
mTypeMap.insert("大雨",":/res/type/DaYu.png");
mTypeMap.insert("冻雨",":/res/type/DongYu.png");
mTypeMap.insert("多云",":/res/type/DuoYun.png");
mTypeMap.insert("浮沉",":/res/type/FuChen.png");
mTypeMap.insert("雷阵雨",":/res/type/LeiZhenYu.png");
mTypeMap.insert("雷阵雨伴有冰雹",":/res/type/LeiZhenYuBanYouBingBao.png");
mTypeMap.insert("霾",":/res/type/Mai.png");
mTypeMap.insert("强沙尘暴",":/res/type/QiangShaChenBao.png");
mTypeMap.insert("晴",":/res/type/Qing.png");
mTypeMap.insert("沙尘暴",":/res/type/ShaChenBao.png");
mTypeMap.insert("特大暴雨",":/res/type/TeDaBaoYu.png");
mTypeMap.insert("undefined",":/res/type/undefined.png");
mTypeMap.insert("雾",":/res/type/Wu.png");
mTypeMap.insert("小到中雪",":/res/type/XiaoDaoZhongXue.png");
mTypeMap.insert("小到中雨",":/res/type/XiaoDaoZhongYu.png");
mTypeMap.insert("小雪",":/res/type/XiaoXue.png");
mTypeMap.insert("小雨",":/res/type/XiaoYu.png");
mTypeMap.insert("雪",":/res/type/Xue.png");
mTypeMap.insert("扬沙",":/res/type/YangSha.png");
mTypeMap.insert("阴",":/res/type/Yin.png");
mTypeMap.insert("雨",":/res/type/Yu.png");
mTypeMap.insert("雨夹雪",":/res/type/YuJiaXue.png");
mTypeMap.insert("阵雪",":/res/type/ZhenXue.png");
mTypeMap.insert("阵雨",":/res/type/ZhenYu.png");
mTypeMap.insert("中到大雪",":/res/type/ZhongDaoDaXue.png");
mTypeMap.insert("中到大雨",":/res/type/ZhongDaoDaYu.png");
mTypeMap.insert("中雪",":/res/type/ZhongXue.png");
mTypeMap.insert("中雨",":/res/type/ZhongYu.png");
//把UI的控件存在一个数组里面
mDateList << ui->labelday0 << ui->labelday1
<< ui->labelday2 << ui->labelday3
<< ui->labelday4 << ui->labelday5;
mWeekList << ui->labelDate0 << ui->labelDate1
<< ui->labelDate2 << ui->labelDate3
<< ui->labelDate4 << ui->labelDate5;
mIconList << ui->labelWheatherIcon0 << ui->labelWheatherIcon1
<< ui->labelWheatherIcon2 << ui->labelWheatherIcon3
<< ui->labelWheatherIcon4 << ui->labelWheatherIcon5;
mWeaTypeList << ui->lbwheatherTypeDate0 << ui->lbwheatherTypeDate1
<< ui->lbwheatherTypeDate2 << ui->lbwheatherTypeDate3
<< ui->lbwheatherTypeDate4 << ui->lbwheatherTypeDate5;
mAirqList << ui->labelairq0 << ui->labelairq1
<< ui->labelairq2 << ui->labelairq3
<< ui->labelairq4 << ui->labelairq5;
mFxList << ui->labelFX0 << ui->labelFX1
<< ui->labelFX2 << ui->labelFX3
<< ui->labelFX4 << ui->labelFX5;
mFlList << ui->labelFL0 << ui->labelFL1
<< ui->labelFL2 << ui->labelFL3
<< ui->labelFL4 << ui->labelFL5;
//安装事件过滤器
ui->widget0404->installEventFilter(this);
ui->widget0405->installEventFilter(this);
}
void Widget::parseWeatherJsonDataNew(QByteArray rawData){
//将字符数组的数据转变为json格式
//将原始的二进制/文本数据解析为Qt的JSON文档对象,方便后续处理JSON数据
QJsonDocument jsonObj = QJsonDocument::fromJson(rawData);
//处理数据
if(!jsonObj.isNull() && jsonObj.isObject()){//jsonObj必须是对象而且必须不能空
//将jsonObj转换为object对象
QJsonObject jsonRoot = jsonObj.object();
//填充days里面只显示一天的数据
days[0].mCity = jsonRoot["city"].toString();
days[0].mPm25 = jsonObj["aqi"].toObject()["pm25"].toString();
//填充需要七天的数据
if(jsonRoot.contains("data") && jsonRoot["data"].isArray()){
//转换为Array
QJsonArray weaArray = jsonRoot["data"].toArray();
for(int i = 0;i < weaArray.size();i++){
//在转变为Object,因为数组里面的每一项都是对象
QJsonObject obj = weaArray[i].toObject();
days[i].mFl = obj["win_speed"].toString();
days[i].mFx = obj["win"].toArray()[0].toString();
days[i].mHu = obj["humidity"].toString();
days[i].mTip = obj["index"].toArray()[3].toObject()["desc"].toString();
days[i].mAirq = obj["air_level"].toString();
days[i].mDate = obj["date"].toString();
days[i].mTemp = obj["tem"].toString();
days[i].mWeek = obj["week"].toString();
days[i].mTempLow = obj["tem2"].toString();
days[i].mTempHigh = obj["tem1"].toString();
days[i].mWeatherType = obj["wea"].toString();
}
updateUI();//更新UI
}
}
}
void Widget::updateUI(){
QPixmap pixmap;
//解析日期
ui->labelCurrentDate->setText(days[0].mDate + " " + days[0].mWeek);
//解析城市
ui->labelCity->setText(days[0].mCity + "市");
//解析当前温度
ui->labelTmp->setText(days[0].mTemp + "℃");
ui->labelTempRange->setText(days[0].mTempLow + "~" + days[0].mTempHigh + "℃");
//解析天气类型
ui->labelweatherType->setText(days[0].mWeatherType);
//设置天气图标
ui->labelWeatherIcon->setPixmap(mTypeMap[days[0].mWeatherType]);
//感冒指数
ui->labelGanmao->setText(days[0].mTip);
//风向
ui->labelFXType->setText(days[0].mFx);
//风力
ui->labelFXType_2->setText(days[0].mFl);
//PM2.5
ui->labelPM25Data->setText(days[0].mPm25);
//湿度
ui->labelShiduData->setText(days[0].mHu);
//空气质量
ui->labelairData->setText(days[0].mAirq);
//显示六天的数据
for(int i = 0;i < 6;i++){
mWeekList[i]->setText(days[i].mWeek);
//特殊设置这三天
mWeekList[0]->setText("今天");
mWeekList[1]->setText("明天");
mWeekList[2]->setText("后天");
//设置日期
QStringList dayList = days[i].mDate.split("-");
mDateList[i]->setText(dayList[1] + "-" + dayList[2]);
//设置图标
//解决没有图片的问题(防止可能出现,"某某天气"转"某某天气"这种情况,导致没有图标的情况)
//这个函数返回子字符串在原字符串中首次出现的位置索引
int index = days[i].mWeatherType.indexOf("转");
if(index != -1){//出现了"转"的情况,只要左边的天气
//从QMap里面找
pixmap = mTypeMap[days[i].mWeatherType.left(index)];//截取了转之前的天气
}else {
pixmap = mTypeMap[days[i].mWeatherType];
}
//设置图
pixmap = pixmap.scaled(mIconList[i]->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
mIconList[i]->setPixmap(pixmap);
//设置天气类型(这个不需要管"转")
mWeaTypeList[i]->setText(days[i].mWeatherType);
//设置空气质量
QString airQ = days[i].mAirq;
mAirqList[i]->setText(airQ);
//设置styleSheet
if(airQ == "优"){
mAirqList[i]->setStyleSheet("color: rgb(230, 230, 230);\
background-color: rgb(150, 213, 32);\
border-radius: 7px;");
}else if(airQ == "良"){
mAirqList[i]->setStyleSheet("color: rgb(230, 230, 230);\
background-color: rgb(208, 107, 39);\
border-radius: 7px;");
}else if(airQ == "轻度污染"){
mAirqList[i]->setStyleSheet("color: rgb(230, 230, 230);\
background-color: rgb(255, 120, 120);\
border-radius: 7px;");
}else if(airQ == "中度污染"){
mAirqList[i]->setStyleSheet("color: rgb(230, 230, 230);\
background-color: rgb(255, 17, 17);\
border-radius: 7px;");
}else if(airQ == "重度污染"){
mAirqList[i]->setStyleSheet("color: rgb(230, 230, 230);\
background-color: rgb(153, 0, 0);\
border-radius: 7px;");
}
//设置风向和风力
mFxList[i]->setText(days[i].mFx);
//风力
index = days[i].mFl.indexOf("转");
if(index != -1){//出现了"转"的情况,只要左边的天气
mFlList[i]->setText(days[i].mFl.left(index));
}else {
mFlList[i]->setText(days[i].mFl);
}
}
update();
}
void Widget::readHttpReply(QNetworkReply *reply){
//处理服务器返回的数据,数据都在这里QNetworkReply *reply
//这个函数用于获取网络响应中的元数据信息,这些信息不是HTTP响应主体内容,而是关于请求/响应的附加数据。(比如状态码)
int resCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << "resCode:" << resCode;
if(resCode == 200 && reply->error() == QNetworkReply::NoError){//没有错误
//qDebug() << "resCode:" << resCode;
//获取数据(数据的形式是json,需要解析)
QByteArray data = reply->readAll();
parseWeatherJsonDataNew(data);//解析数据
// qDebug() << QString::fromUtf8(data);
}else {
QMessageBox msgBox;
msgBox.setText("网络请求失败");
msgBox.setWindowTitle("错误");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setStyleSheet("QPushButton {color:red}");
int ret = msgBox.exec();
}
}
//需要画图的话需要重写事件过滤器
void Widget::drawTempLineHigh(){
QPainter painter(ui->widget0404);//在ui->widget0404这里画图
//设置属性
painter.setPen(QColor(Qt::yellow));
painter.setBrush(QBrush(QColor(Qt::yellow)));
painter.setRenderHint(QPainter::Antialiasing,true);
//临时变量
int ave;//记录平均气温
int sum = 0;//记录总的气温
int offSet;//偏移量,记录平均气温和最高气温的偏移量
int middle = ui->widget0404->height() / 2;//中间值,基于中间值来画点
//获取sum
for(int i = 0;i < 6;i++){
sum += days[i].mTempHigh.toInt();
}
//获取平均气温
ave = sum / 6;
//定义六个点
QPoint point[6];
for(int i = 0;i < 6;i++){
//设置x坐标
point[i].setX(mAirqList[i]->x() + mAirqList[i]->width() / 2);
//设置y坐标
offSet = (days[i].mTempHigh.toInt() - ave) * 1.5;//获取偏移量
point[i].setY(middle - offSet);//反应到ui->widget0404上面
//画点
painter.drawEllipse(QPoint(point[i]),3,3);
//画出当天温度
painter.drawText(point[i].x() - 15,point[i].y() - 10,days[i].mTempHigh + "°");
}
//画线(将六个点连接起来)
for(int i = 0;i < 5;i++){
painter.drawLine(point[i],point[i + 1]);
}
}
void Widget::drawTempLineLow(){
QPainter painter(ui->widget0405);//在ui->widget0405这里画图
//设置属性QColor(70, 192, 203)
painter.setPen(QColor(70,192,192));
painter.setBrush(QBrush(QColor(70,192,192)));
painter.setRenderHint(QPainter::Antialiasing,true);
//临时变量
int ave;//记录平均气温
int sum = 0;//记录总的气温
int offSet;//偏移量,记录平均气温和最高气温的偏移量
int middle = ui->widget0405->height() / 2;//中间值
//获取sum
for(int i = 0;i < 6;i++){
sum += days[i].mTempLow.toInt();
}
//获取平均气温
ave = sum / 6;
//定义六个点
QPoint point[6];
for(int i = 0;i < 6;i++){
//设置x坐标
point[i].setX(mAirqList[i]->x() + mAirqList[i]->width() / 2);
//设置y坐标
offSet = (days[i].mTempLow.toInt() - ave) * 1.5;//获取偏移量
point[i].setY(middle - offSet);//反应到ui->widget0404上面
//画点
painter.drawEllipse(QPoint(point[i]),3,3);
painter.drawText(point[i].x() - 15,point[i].y() - 10,days[i].mTempLow + "°");
}
//画线(将六个点连接起来)
for(int i = 0;i < 5;i++){
painter.drawLine(point[i],point[i + 1]);
}
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
//获取lineEditCity上面的数据
QString cityNameFromuser = ui->lineEditCity->text();
//从json文件里面找到对应城市ID
QString citycode = c_code.getCityCodeFromName(cityNameFromuser);
qDebug() << citycode;
if(citycode != NULL){
//重新拼接URL
urlStr += "&cityid=" + citycode;
//重新发起get请求
reply = manager->get(QNetworkRequest(QUrl(urlStr)));
}else {
QMessageBox msgBox;
msgBox.setText("请输入正确的城市名");
msgBox.setWindowTitle("错误");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setStyleSheet("QPushButton {color:red}");
int ret = msgBox.exec();
}
}
//回车响应
void Widget::on_lineEditCity_returnPressed()
{
on_pushButton_clicked();
}
3.2 在widget.h
cpp
#ifndef WIDGET_H
#define WIDGET_H
#include "citycodeutil.h"
#include "days.h"
#include <QLabel>
#include <QMenu>
#include <QMouseEvent>
#include <QWidget>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
bool eventFilter(QObject* object,QEvent* event) override;
public slots:
void readHttpReply(QNetworkReply *reply);
private slots:
void on_pushButton_clicked();
void on_lineEditCity_returnPressed();
private:
Ui::Widget *ui;
QMenu* menuQuit;
QPoint moffset;//这是偏移值(也就是那个差值)
days days[7];
QNetworkAccessManager* manager;
QString urlStr;
QNetworkReply* reply;
void parseWeatherJsonDataNew(QByteArray rawData);
void updateUI();
//存放天气的图标
QMap<QString,QString> mTypeMap;
QList<QLabel *> mDateList;
QList<QLabel *> mWeekList;
QList<QLabel *> mIconList;
QList<QLabel *> mWeaTypeList;
QList<QLabel *> mAirqList;
QList<QLabel *> mFxList;
QList<QLabel *> mFlList;
void drawTempLineHigh();//画最高温曲线
void drawTempLineLow();//画最低温曲线
citycodeutil c_code;
};
#endif // WIDGET_H
3.3 在citycodeutils.cpp
cpp
#include "citycodeutil.h"
#include <QFile>
#include <QDebug>
#include <QJsonDocument>
#include <QJsonArray>
citycodeutil::citycodeutil()
{
}
QString citycodeutil::getCityCodeFromName(QString cityName)
{
//先进行判空
if(cityMap.isEmpty()){
//如果为空先进行初始化
initCityMap();
}
//查找,根据传进来的cityName
QMap<QString,QString>::iterator it = cityMap.find(cityName);
if(it == cityMap.end()){//判断是否查找失败
it = cityMap.find(cityName + "市");
if(it == cityMap.end()){//判断是否查找失败
it = cityMap.find(cityName + "县");
}
if(it == cityMap.end()){//判断是否查找失败
it = cityMap.find(cityName + "区");
}
if(it == cityMap.end()){//判断是否查找失败
return "";
}
}
return it.value();//找到了
}
void citycodeutil::initCityMap()
{
//先打开json文件
QFile file(":/citycode.json");
if(!file.open(QIODevice::ReadOnly))return;
//读取文件
QByteArray rawData = file.readAll();
//关闭文件
file.close();
qDebug() << rawData;
//处理读取出来的数据
//转换为json
QJsonDocument jsonObj = QJsonDocument::fromJson(rawData);
if(!jsonObj.isNull() && jsonObj.isArray()){
//转换为Array
QJsonArray citys = jsonObj.array();
//遍历citys
for(QJsonValue val : citys){
//并且只要city_name和city_code
QString cityname = val["city_name"].toString();
QString citycode = val["city_code"].toString();
//存到QMap里面
//这里的键值对的值为cityCode
cityMap.insert(cityname,citycode);
}
}
}
3.4 在citycodeutils.h
cpp
#ifndef CITYCODEUTIL_H
#define CITYCODEUTIL_H
#include <QMap>
#include <QString>
class citycodeutil
{
public:
citycodeutil();
//初始化为空,存放json文件的数据,不用每次都打开,如果每次输入一个城市
QMap<QString,QString> cityMap = {};
QString getCityCodeFromName(QString cityName);
void initCityMap();
};
#endif // CITYCODEUTIL_H
3.5 在days.h(.cpp是空文件)
cpp
#ifndef DAYS_H
#define DAYS_H
#include <QString>
class days
{
public:
days();
QString mDate;
QString mWeek;
QString mCity;
QString mTemp;
QString mWeatherType;
QString mTempLow;
QString mTempHigh;
QString mTip;
QString mFx;
QString mFl;
QString mPm25;
QString mHu;
QString mAirq;
};
#endif // DAYS_H
4. UI

