天气预报程序

花了大概两天写完

  • 课程来源:B站课程
  • 类型:个人笔记
  • 声明:我不是做UI的,所以有些地方我懒得改。我还是比较关注各个模块功能的实现
  • 实时数据来源:天气API,本项目用到的所有数据均来自此网站

绘制UI与实现鼠标点击事件

懒得写过程了,跟着视频做就行,没啥技术含量。本小节从视频P147开始,P154结束

Http编程

知识点

  • 计算机网络和软件开发中常用的网络通信架构有C/S和B(Browse)/S架构
  • 基本流程:客户端(通常是浏览器)向服务器发送一HTTP请求,服务器返回一HTTP响应。请求包含申请的资源如网页,响应则返回申请需要的资源
  • HTTP方法:GET(请求资源)POST(提交数据至服务器)PUTDELETEHEAD。常用前俩种
  • 状态码:200OK;404 Not Found;500 Internet Server Error;301 Move Permanently
  • HTTP是无状态协议。但是可以通过Cookie等机制维持状态
  • HTTPS:加密过的HTTP,更安全

QtHttp编程

最重要的事情:在Qt中用到网络就必须在pro文件内进行配置

QT       += core gui network

包含这俩头文件

#include<QNetworkAccessManager>
#include<QNetworkReply>
#include<QMessageBox>

Widget类内添加俩成员

class Widget : public QWidget
{
public slots:
	void readHttpReply();//等会要用的槽函数
private:
	QNetworkReply *reply;
}

Widget的构造函数内

 QNetworkAccessManager *manager=new QNetworkAccessManager(this);
    connect(manager,&QNetworkAccessManager::finished,[](){
        qDebug()<<"manager finished============";
    });
    QUrl itboyErr("http://t.weather.itboy.net");//用于测试请求失败情况
    QUrl TianqiApi("http://gfeljm.tianqiapi.com/api?unescape=1&version=v61&appid=31696132&appsecret=NlHppb7U");
    QNetworkRequest request(TianqiApi);//构造函数参数为Url
    reply=manager->get(request);//get()参数为QNetworkRequest,即需要指定访问的地址
    //发起Http请求后读取数据
    connect(reply,&QNetworkReply::finished,this,&Widget::readHttpReply);

QNetworkAccessManager::finished:当一待处理的网络请求完成后QNetworkAccessManager就会发出此信号;对于下边的QNetworkReply::finished同理
槽函数实现

void Widget::readHttpReply()
{
    int resultCode=reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();//返回状态码
    qDebug()<<resultCode;
    if(reply->error()==QNetworkReply::NoError&&resultCode==200){
        auto data=reply->readAll();
        parseWeatherJson(data);
        qDebug()<<QString::fromUtf8(data);//转为utf-8的字符串
    }
    else{
        //qDebug()<<"请求失败:"<<reply->errorString();
        QMessageBox msg;
        msg.setWindowTitle("错误");
        msg.setText("网络请求失败");
        msg.setStyleSheet("QPushButton {color:red}");
        msg.setStandardButtons(QMessageBox::Ok);
        msg.exec();
    }
}

Json

***Json(JavaScript Object Notation)***是一种轻量级的数据交换格式,独立于语言且支持多种语言。它常在网络数据传输中使用,尤其是Web与后端服务器通信时。太出名了,没啥好说的
本文主要专注于在Qt中使用Json
涉及到QJsonDocumentQJsonObjectQJsonArray

简单案例

以下是一个简单的实例

#include<QJsonObject>
#include<QFile>
#include<QJsonArray>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QJsonObject rootObj;
    //QJsonObject重载了=和[]
    rootObj["cityID"]="1010100";
    rootObj["date"]="2025-09-18";
    rootObj["weather"]="雨夹雪";
    rootObj["temprature"]=3;

    QJsonArray array;
    array.append("data1");
    array.append("data2");
    array.append("data3");
    array.append(100);

    rootObj["testArray"]=array;

    QJsonDocument jsonDoc(rootObj);
    QByteArray jsonArr=jsonDoc.toJson();

    QFile file("C:\\Users\\frang\\Desktop\\TEMP\\Qt Temp\\JsonTest\\test.json");
    file.open(QIODevice::WriteOnly);
    file.write(jsonArr);//参数为QByteArray
    file.close();
}

可成功输出,用记事本打开

{
    "cityID": "1010100",
    "date": "2025-09-18",
    "temprature": 3,
    "testArray": [
        "data1",
        "data2",
        "data3",
        100
    ],
    "weather": "雨夹雪"
}

接下来展示在QJsonObject中嵌套QJsonObject

QJsonObject alarm;
    alarm["alarmType"]="雪灾";
    alarm["alarmLevel"]="红色";
    alarm["alarmTip"]="福州市警告:雪灾将在8小时内发生,范围可覆盖至全市即周边地区";

    rootObj["alarm"]=alarm;

很简单
当然我们也可以定义一个数组,数组内包含多个QJsonObject

	QJsonObject day0;
    day0["day"]="星期一";
    day0["wea"]="晴";
    day0["tem"]="19.2";

    QJsonObject day1;
    day1["day"]="星期二";
    day1["wea"]="晴";
    day1["tem"]="23.2";

    QJsonObject day2;
    day2["day"]="星期二";
    day2["wea"]="小雨";
    day2["tem"]="16.2";

    QJsonArray dayArr;
    dayArr.append(day0);
    dayArr.append(day1);
    dayArr.append(day2);

    rootObj["days"]=dayArr;

也没啥难的

{
    "alarm": {
        "alarmLevel": "红色",
        "alarmTip": "福州市警告:雪灾将在8小时内发生,范围可覆盖至全市即周边地区",
        "alarmType": "雪灾"
    },
    "cityID": "1010100",
    "date": "2025-09-18",
    "days": [
        {
            "day": "星期一",
            "tem": "19.2",
            "wea": "晴"
        },
        {
            "day": "星期二",
            "tem": "23.2",
            "wea": "晴"
        },
        {
            "day": "星期二",
            "tem": "16.2",
            "wea": "小雨"
        }
    ],
    "temprature": 3,
    "testArray": [
        "data1",
        "data2",
        "data3",
        100
    ],
    "weather": "雨夹雪"
}

数据解析

接下来对上边的test.json进行解析
这是一个解析Json数据的简单案例(分了几种情况)
拆解键值对

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

    QFile file("C:\\Users\\frang\\Desktop\\TEMP\\Qt Temp\\JsonTest\\test.json");
    file.open(QIODevice::ReadOnly);
    auto rawData=file.readAll();//读取Json文件并保存至QByteArray中
    file.close();
    
    QJsonDocument jsonDoc=QJsonDocument::fromJson(rawData);
    if(!jsonDoc.isNull()&&jsonDoc.isObject()){
        auto objRoot=jsonDoc.object();
        auto strW=objRoot["weather"].toString();
        auto Tmp=objRoot["temprature"].toInt();
        qDebug()<<strW;
        qDebug()<<strCID;
        qDebug()<<QString::number(Tmp);
    }

}

彳亍,没问题。话说我为什么要在构造函数里写?
430d39f1ef0.png)
解析数组

if(objRoot.contains("testArray")&&objRoot["testArray"].isArray())
{
auto testArray=objRoot["testArray"].toArray();
       for(QJsonValue val:testArray)
       {
           switch (val.type()) 
           {
               case QJsonValue::Double:
                   qDebug()<<val.toDouble()<<Qt::endl;
                   break;
               case QJsonValue::String:
                   qDebug()<<val.toString()<<Qt::endl;
                   break;
               case QJsonValue::Object:
                   break;
               default:
                   break;
           }
       }
    }

没问题
在这里插入图片描述
判断某个键对应的值是否是对象QJsonObject的情况

 if(objRoot.contains("alarm")&&objRoot["alarm"].isObject()){
        auto alarmObj=objRoot["alarm"].toObject();
        qDebug()<<alarmObj["alarmLevel"].toString()<<Qt::endl;
        qDebug()<<alarmObj["alarmTip"].toString()<<Qt::endl;
        qDebug()<<alarmObj["alarmType"].toString()<<Qt::endl;
    }

在这里插入图片描述
也很简单
数组内含有对象

 if(objRoot.contains("days")&&objRoot["days"].isArray()){
        auto dayArr=objRoot["days"].toArray();
        for(auto item:dayArr){
            if(item.isObject()){
                QJsonObject obj=item.toObject();
                qDebug()<<obj["day"].toString()<<";"
                        <<obj["tem"].toString()<<";"
                        <<obj["wea"].toString();
            }
        }
    }

在这里插入图片描述
也没问题

刷新当天天气数据

这节也挺无聊的,对着天气API的数据一个个解析就行了
提供一个接口parseWeatherJson

void Widget::parseWeatherJson(QByteArray rawData)
{
    QJsonDocument jsonObj=QJsonDocument::fromJson(rawData);
    if(!jsonObj.isNull()&&jsonObj.isObject())
    {
        QJsonObject objRoot=jsonObj.object();
        //解析Json
        //日期
        auto date=objRoot["date"].toString();
        auto week=objRoot["week"].toString();
        ui->labelDate->setText(date+" "+week);
        //城市
        auto city=objRoot["city"].toString();
        ui->labelCity->setText(city+"市");
        //当前温度
        auto curTemp=objRoot["tem"].toString();
        ui->labelTMP->setText(curTemp+"℃");
        ui->labelTMPRange->setText(objRoot["tem2"].toString()+"~"+
        objRoot["tem1"].toString());
        //天气类型
        ui->labelWeatherT->setText(objRoot["wea"].toString());
        //感冒指数
        ui->ganmao->setText(objRoot["air_tip"].toString());
        //风向与风力
        ui->labelFXT->setText(objRoot["win"].toString());
        ui->labelFXD->setText(objRoot["win_speed"].toString());
        //PM2.5
        ui->labelPM25D->setText(objRoot["air_pm25"].toString());
        //湿度
        ui->labelHumidD->setText(objRoot["humidity"].toString());
        //空气质量
        ui->labelAirQD->setText(objRoot["air_level"].toString());
    }
}

别忘了在readHttpReply中调用此接口
样式全乱了啊,字全跑到左边去了,等会看看怎么设置居中
这是几天后发现的:因为我没有在QLabel内设置水平中心对齐。只是在改变文本格式里设置了居中

支持城市检索

还需要城市id表,这玩意我上哪整
等一下,好像还有救,可以不用cityid改用city,而且更方便啊
好吧,打开弹幕时发现id表可以在github上找到城市ID表,那还是用id表来实现吧
为搜索功能添加槽函数。可以用eventFilter来实现, 这里简单粗暴一点,直接把它换成按钮
一些改动
构造函数内:改为由manager来管理此connect并将其改为类内成员

//发起Http请求后读取数据
connect(manager,&QNetworkAccessManager::finished,this,&Widget::readHttpReply);

readHttpReply改为有参数:

void readHttpReply(QNetworkReply*reply);

url改为类内成员

class Widget:public QWidget
{
private:
	QString strUrl;//注意是QString类型的
};
//网址改为由strUrl接收
strUrl="http://gfeljm.tianqiapi.com/api?unescape=1&version=v61&appid=31696132&appsecret=NlHppb7U";

为搜索按钮添加槽函数

QString GetCityCodeFromJson(QString name)
{
    QFile file("C:/Users/frang/Desktop/TEMP/Qt Temp/WeatherReport/citycode.json");
    file.open(QIODevice::ReadOnly);
    QByteArray rawData=file.readAll();
    file.close();
    QJsonDocument jsonDoc=QJsonDocument::fromJson(rawData);
    if(jsonDoc.isArray()){
        auto cities=jsonDoc.array();
        for(QJsonValue val:cities){
            if(val.isObject()){
                QString cityName=val["city_name"].toString();
                if(cityName==name)
                    return val["city_code"].toString();
            }
        }
    }
    return "";
}

void Widget::on_pushButton_clicked()
{
    QString cityNameFromUser=ui->lineEditCity->text();
    auto cityCode=GetCityCodeFromJson(cityNameFromUser);
    if(cityCode!=""){
        strUrl+="&cityid="+cityCode;
        manager->get(QNetworkRequest(QUrl(strUrl)));
    }
    else{
        QMessageBox msg;
        msg.setWindowTitle("错误");
        msg.setText("请输入正确的城市");
        msg.setStyleSheet("QPushButton {color:red}");
        msg.setStandardButtons(QMessageBox::Ok);
        msg.exec();
    }
}

改进城市检索

把Json数据存储在数据结构内,就不用每次都打开文件了
map来存储很合适
添加一个新的类CityCodeUtility
包含这些头文件并添加以下成员

#include<QString>
#include<QMap>
#include<QFile>
#include<QJsonDocument>
#include<QByteArray>
#include<QJsonArray>
class CityCodeUtility
{
public:
    CityCodeUtility();
    QMap<QString,QString>cityMap={};
    QString GetCityCodeFromJson(QString cityName);
    void initCityMap();
};

将上边的GetCityCodeFromJson逻辑移植过来,原来的删掉

void CityCodeUtility::initCityMap()
{
    QFile file("C:/Users/frang/Desktop/TEMP/Qt Temp/WeatherReport/citycode.json");
    file.open(QIODevice::ReadOnly);
    QByteArray rawData=file.readAll();
    file.close();
    QJsonDocument jsonDoc=QJsonDocument::fromJson(rawData);
    if(jsonDoc.isArray()){
        QJsonArray cities=jsonDoc.array();
        for(QJsonValue val:cities){
            if(val.isObject()){
                QString cityName=val["city_name"].toString();
                QString cityCode=val["city_code"].toString();
                cityMap.insert(cityName,cityCode);
            }
        }
    }
}

对外暴露此接口

QString CityCodeUtility::GetCityCodeFromJson(QString cityName)
{
    if(cityMap.isEmpty())//仅在第一次打开文件
        initCityMap();
    QMap<QString,QString>::iterator it=cityMap.find(cityName);
    if(it==cityMap.end())
        return "";
    return it.value();
}

更新天气Icon

实时更新左上角的天气图标
最没含金量的一集。因为我没文档只能自己从阿里巴巴矢量图标库里一个个下载然后再一个个导入进Qt里
Widget类内创建一个QMap管理天气Icon与天气类型

QMap<QString,QString>weatherTypeMap;

然后一个个插入,哈哈这也是我手打的。并且现实中的天气比这多很多。如果你熟悉数据库的话,我强烈建议你接入数据库来处理,且天气API提供的也是SQL源文件

weatherTypeMap.insert("暴雨",":/res/BaoYu.png");
    weatherTypeMap.insert("暴雪",":/res/BaoXue.png");
    weatherTypeMap.insert("暴雨到大暴雨",":/res/BaoYuDaoDaBaoYu.png");
    weatherTypeMap.insert("大暴雨",":/res/DaBaoYu.png");
    weatherTypeMap.insert("大暴雨到特大暴雨",":/res/DaBaoYuDaoTeDaBaoYu.png");
    weatherTypeMap.insert("大到暴雪",":/res/DaDaoBaoXue.png");
    weatherTypeMap.insert("大雨",":/res/DaYu.png");
    weatherTypeMap.insert("大雪",":/res/DaXue.png");
    weatherTypeMap.insert("冻雨",":/res/DongYu.png");
    weatherTypeMap.insert("多云",":/res/cloudy_W.png");
    weatherTypeMap.insert("浮沉",":/res/FuChen.png");
    weatherTypeMap.insert("雷阵雨",":/res/LeiZhenYu.png");
    weatherTypeMap.insert("雷阵雨伴有冰雹",":/res/LeiZhenYuBanBingBao.png");
    weatherTypeMap.insert("霾",":/res/Mai.png");
    weatherTypeMap.insert("晴",":/res/Clear.png");
    weatherTypeMap.insert("沙尘暴",":/res/ShaChenBao.png");
    weatherTypeMap.insert("强沙尘暴",":/res/QiangShaChenBao.png");
    weatherTypeMap.insert("特大暴雨",":/res/TeDaBaoYu.png");
    weatherTypeMap.insert("雾",":/res/Wu.png");
    weatherTypeMap.insert("小到中雪",":/res/XiaoDaoZhongXue.png");
    weatherTypeMap.insert("小到中雨",":/res/XiaoDaoZhongYu.png");
    weatherTypeMap.insert("小雪",":/res/XiaoXue.png");
    weatherTypeMap.insert("小雨",":/res/XiaoYu.png");
    weatherTypeMap.insert("雪",":/res/Xue.png");
    weatherTypeMap.insert("扬沙",":/res/YangSha.png");
    weatherTypeMap.insert("阴",":/res/Yin.png");
    weatherTypeMap.insert("雨",":/res/Yu.png");
    weatherTypeMap.insert("雨夹雪",":/res/YuJiaXue.png");
    weatherTypeMap.insert("阵雨",":/res/ZhenYu.png");
    weatherTypeMap.insert("阵雪",":/res/ZhenXue.png");
    weatherTypeMap.insert("中到大雨",":/res/ZhongDaoDaYu.png");
    weatherTypeMap.insert("中到大雪",":/res/ZhongDaoDaXue.png");
    weatherTypeMap.insert("中雨",":/res/ZhongYu.png");
    weatherTypeMap.insert("中雪",":/res/ZhongXue.png");

最后在解析Json的逻辑(parseWeatherJson())中更新天气Icon

ui->labelWeather->setPixmap(weatherTypeMap[objRoot["wea"].toString()]);

获取七天天气数据

由于返回的数据量较大,这里创建一个新的类Day来管理,当然用结构体也行。且解析Json数据的函数也要更改。。。6

class Day
{
public:
    Day();
    QString mDate;
    QString mWeek;
    QString mTemp;
    QString mCity;
    QString mWeatherType;
    QString mTempLow;
    QString mTempHigh;
    QString mTip;
    QString mFx;
    QString mFl;
    QString mPM25;
    QString mHum;
    QString mAirQ;
}

然后在Widget类内创建一个实例并添加一个更新UI的接口

class Widget:public QWidget
{
public:
	Day days[7];//其实我感觉只要6天数据也行,反正视频里就做了6天的UI
private:
	void improvedParseWeatherJson(QByteArray rawData);//修改过的解析json函数
	void updateUI();
}

具体实现如下

void Widget::updateUI()
{
	//日期
    ui->labelDate->setText(days[0].mDate+" "+days[0].mWeek);
    //城市
    ui->labelCity->setText(days[0].mCity+"市");
    //当前温度
    ui->labelTMP->setText(days[0].mTemp+"℃");
    ui->labelTMPRange->setText(days[0].mTempLow+"~"+days[0].mTempHigh);
    //天气类型
    ui->labelWeatherT->setText(days[0].mWeatherType);
    ui->labelWeather->setPixmap(weatherTypeMap[days[0].mWeatherType]);
    //感冒指数
    ui->ganmao->setText(days[0].mTip);
    //风向与风力
    ui->labelFXT->setText(days[0].mFx);
    ui->labelFXD->setText(days[0].mFl);
    //PM2.5
    ui->labelPM25D->setText(days[0].mPM25);
    //湿度
    ui->labelHumidD->setText(days[0].mHum);
    //空气质量
    ui->labelAirQD->setText(days[0].mAirQ);
}

void Widget::improvedParseWeatherJson(QByteArray rawData)
{
    QJsonDocument jsonDoc=QJsonDocument::fromJson(rawData);
    if(!jsonDoc.isNull()&&jsonDoc.isObject())
    {
        QJsonObject jsonRoot=jsonDoc.object();
        days[0].mCity=jsonRoot["city"].toString();
        days[0].mPM25=jsonRoot["aqi"].toObject()["pm25"].toString();
        if(jsonRoot.contains("data")&&jsonRoot["data"].isArray())
        {
            QJsonArray weaArray=jsonRoot["data"].toArray();
            for(int i=0;i<weaArray.size();i++)
            {
                QJsonObject obj=weaArray[i].toObject();
                days[i].mDate=obj["date"].toString();
                days[i].mWeek=obj["week"].toString();
                days[i].mWeatherType=obj["wea"].toString();
                days[i].mTemp=obj["tem"].toString();
                days[i].mTempLow=obj["tem2"].toString();
                days[i].mTempHigh=obj["tem1"].toString();
                days[i].mFx=obj["win"].toArray()[0].toString();//风向是个数组
                days[i].mFl=obj["win_speed"].toString();
                days[i].mAirQ=obj["air_level"].toString();
                days[i].mTip=obj["air_tips"].toString();
                days[i].mHum=obj["humidity"].toString();
            }
        }
    }
    updateUI();
}

更新UI的逻辑基本从旧的parseWeatherJson复制,然后根据天气API提供的七日Json数据格式与自定义类Day进行更改

更新天气UI

更新widget04中的UI,暂时不做0405和0404的
看完了这两P(P169和P170)了,这个Up主用的方法简单粗暴但效率很低。实际中不会这么写代码的,看看就行,但我们这是demo,功能简陋点也没啥,主要还是熟悉Qt各API的用法
定义一些vector来管理widget04中的label

//定义在Widget内部
    QVector<QLabel*>mDateV;
    QVector<QLabel*>mDayV;
    QVector<QLabel*>mWeaIconV;//管理天气图标
    QVector<QLabel*>mWeaTypeV;//管理天气类型
    QVector<QLabel*>mAQV;//管理空气质量
    QVector<QLabel*>mFxV;//管理风向
    QVector<QLabel*>mFlV;//管理风力

Widget构造函数内初始化这些vector,把之前改好名的label全部丢进去

mDateV<<ui->labelDate1<<ui->labelDate2
           <<ui->labelDate3<<ui->labelDate4
           <<ui->labelDate5<<ui->labelDate6;

    mDayV<<ui->labelDay1<<ui->labelDay2
          <<ui->labelDay3<<ui->labelDay4
          <<ui->labelDay5<<ui->labelDay6;

    mWeaTypeV<<ui->labelWeatherT1<<ui->labelWeatherT2
              <<ui->labelWeatherT3<<ui->labelWeatherT4
              <<ui->labelWeatherT5<<ui->labelWeatherT6;

    mWeaIconV<<ui->WeatherIcon1<<ui->WeatherIcon2
              <<ui->WeatherIcon3<<ui->WeatherIcon4
              <<ui->WeatherIcon5<<ui->WeatherIcon6;

    mAQV<<ui->labelAQ1<<ui->labelAQ2
         <<ui->labelAQ3<<ui->labelAQ4
         <<ui->labelAQ5<<ui->labelAQ6;

    mFxV<<ui->labelFx1<<ui->labelFx2
         <<ui->labelFx3<<ui->labelFx4
         <<ui->labelFx5<<ui->labelFx6;

    mFlV<<ui->labelFl1<<ui->labelFl2
         <<ui->labelFl3<<ui->labelFl4
         <<ui->labelFl5<<ui->labelFl6;

把这段丢进updateUI函数

 for(int i=0;i<6;i++)
    {
        //设置日期
        QStringList daylist=days[i].mDate.split("-");//格式2025-09-19,按"-"分割
        mDayV[i]->setText(days[i].mWeek);
        mDayV[0]->setText("今天");
        mDayV[1]->setText("明天");
        mDayV[2]->setText("后天");
        mDateV[i]->setText(daylist.at(1)+"-"+daylist.at(2));//拼接

        //设置图片
        //其实完全可以用模糊匹配
        int index=days[i].mWeatherType.indexOf("转");
        if(index!=-1)
        {
            //暂时先使用“转”字左边天气的icon
            //例如:晴转多云显示晴icon,多云转晴显示多云icon
            pixmap=weatherTypeMap[days[i].mWeatherType.left(index)];
        }
        else
        {
            pixmap=weatherTypeMap[days[i].mWeatherType];
        }
        //缩放图片
        //scaled需要三个参数:需要缩放的大小、缩放比例、转换模式(后边俩是枚举)
        pixmap=pixmap.scaled
        (mWeaIconV[i]->size(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
        
        mWeaIconV[i]->setPixmap(pixmap);
        mWeaIconV[i]->setMaximumWidth(ui->widget02->width()/6.5);
        mWeaIconV[i]->setMaximumHeight(50);
        mWeaTypeV[i]->setText(days[i].mWeatherType);

        //设置空气质量
        QString airQstr=days[i].mAirQ;
        mAQV[i]->setText(airQstr);
        //也可以用switch加enum实现
        if(airQstr=="优")
            mAQV[i]->setStyleSheet("background-color:rgb(150,213,32);border-radius:7px;color:rgb(245,245,245)");
        else if(airQstr=="良")
            mAQV[i]->setStyleSheet("background-color:rgb(150,213,150);border-radius:7px;color:rgb(245,245,245)");
        else if(airQstr=="轻度")
            mAQV[i]->setStyleSheet("background-color:rgb(200,200,100);border-radius:7px;color:rgb(245,245,245)");
        else if(airQstr=="中度")
            mAQV[i]->setStyleSheet("background-color:rgb(150,57,57);border-radius:7px;color:rgb(245,245,245)");
        else if(airQstr=="重度")
            mAQV[i]->setStyleSheet("background-color:rgb(150,0,0);border-radius:7px;color:rgb(245,245,245)");

        //设置风向与风力
        mFxV[i]->setText(days[i].mFx);
        index=days[i].mFl.indexOf("转");
        if(index!=-1)
        {
            //和上边的逻辑一样
            mFlV[i]->setText(days[i].mFl.left(index));
        }
        else
            mFlV[i]->setText(days[i].mFl);
    }

备注:第二个参数用法
在这里插入图片描述
第三个参数:

作用
Qt::FastTransformation 0 快速非平滑缩放
Qt::SmoothTransformation 1 平滑缩放(使用bilinear filtering)

其实有时候天气类型太长了会导致文字直接跑到label外去(比如大暴雨到特大暴雨),但我懒得改了,就这样吧。这么一想,还不如一开始就用text edit

绘制温度曲线图

使用事件过滤器实现
Widget类内定义一事件过滤器

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

其实现如下(常用写法)

bool Widget::eventFilter(QObject *watched, QEvent *event)
{
    if(watched==ui->widget0404 && event->type()==QEvent::Paint){
        drawLineHigh();
        return true;//表示事件已被处理
    }
    if(watched==ui->widget0405 && event->type()==QEvent::Paint){
        drawLineLow();
        return true;
    }
    return QWidget::eventFilter(watched,event);
}

绘制逻辑如下

void Widget::drawLineHigh()
{
    QPainter painter(ui->widget0404);//在0404内画
    painter.setRenderHint(QPainter::Antialiasing,true);//打开抗锯齿
    painter.setBrush(Qt::yellow);
    painter.setPen(Qt::yellow);

    int avg=0;
    int sum=0;
    int middle=ui->widget0404->height()/2;
    int pOffset=0;
    for(int i=0;i<6;i++)
        sum+=days[i].mTempHigh.toInt();
    avg=sum/6;


    QPoint points[6];
    for(int i=0;i<6;i++){
        points[i].setX(mAQV[i]->x()+mAQV[i]->width()/2);
        pOffset=(days[i].mTempHigh.toInt()-avg)*2.5;
        points[i].setY(middle-pOffset);
        painter.drawEllipse(points[i],3,3);//画六个点
        painter.drawText(points[i].x()-15,points[i].y()-10,days[i].mTempHigh+"℃");//画当天气温
    }

    for(int i=0;i<5;i++){
        painter.drawLine(points[i],points[i+1]);//画五根线
    }
}

最终效果
在这里插入图片描述
还是有很多问题,但我懒得改了,我只关心如何实现功能,至于前端这玩意用QML搞更好

优化

  1. 优化UI:懒得改。详情见P173
  2. 添加回车搜索:就为lineEdit添加个槽函数,里边调用搜索按钮的槽函数就行了
  3. 移植至Linux:懒得做。详情见P174至P179
  4. 打包:
    想要生成.exe文件,首先得在创建项目时勾选上release,exe文件在build目录下的msvc/mingw下的release中
    如果运行exe时弹出错误告诉你缺少依赖库,可以这么干
    打开Qt命令行,cd至.exe在的文件夹,然后输入windeployqt,后边跟上你的exe文件名
windeployqt your_project_name.exe

这是Qt部署工具,可以自动帮你把缺少的库拷贝过来,然后就能正常运行了,很方便

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐