QT天气预报(定位当地城市显示当地城市天气,显示搜索城市天气)

目录

视频教程

【QT开发专题-天气预报】1. 效果演示、技术分析_哔哩哔哩_bilibili

前置知识

效果演示

布局

代码实现

实现自定义拖动窗体功能

利用网络获取天气

关联信号槽

发送http请求

调用getWeatherInfo()函数来从网络中获取天气:

接收服务端数据

天气解析

解析昨天的天气情况

解析近五天的天气情况:

解析今天的天气数据

更新UI

创建对应的数组用来存对应的数据          

​编辑把控件添加到控件数组(方便使用循环处理)

UpdatatUI

实现天气搜索功能

绘制温度曲线

安装事件过滤器

声明三个函数

​编辑

高低温曲线的绘制

刷新UI

成品效果演示

工作流程1总结

优化

定位当前城市

工作流程2总结

完整代码


视频教程

【QT开发专题-天气预报】1. 效果演示、技术分析_哔哩哔哩_bilibili

前置知识

Json和Http专栏

效果演示

布局

控件和对应的控件名称:

左侧:

右侧: 

 重点说一下这个布局:

代码实现

取消主界面自带边框

    setWindowFlag(Qt::FramelessWindowHint);  //设置窗口无边框
    setFixedSize(width(),height());  //设置窗口固定大小

 设置右键弹出退出按钮

    mExitAct->setText("退出");
    mExitAct->setIcon(QIcon(":/res/close.ico"));
    mExitMenu->addAction(mExitAct);  //将我们的行为添加到出菜单里

响应鼠标事件

 //弹出右键菜单
void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
    mExitMenu->exec(QCursor::pos());  //传送鼠标位置
}

 绑定信号槽

    connect(mExitAct,QAction::triggered,this,[=]{
        qApp->exit(0);
    });

去掉了系统自带的标题栏就无法拖动窗口了,我们需要自己实现通过鼠标拖动窗口的功能.

实现自定义拖动窗体功能

定义一个变量

    QPoint mOffset;  //鼠标离左上角的距离

定义两个方法

   //处理鼠标点击事件   

   void mousePressEvent(QMouseEvent *event);

   //处理鼠标移动事件
    void mouseMoveEvent(QMouseEvent *event);

方法实现

//处理鼠标点击事件
void MainWindow::mousePressEvent(QMouseEvent *event)
{
    mOffset = event->globalPos() - this->pos();
}

//处理鼠标移动事件
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    this->move(event->globalPos() - mOffset);
}

当鼠标点击时会调

用mousePressEvent()函数,获取鼠标点击的位置,当鼠标按住移动的时候会调用 mouseMoveEvent()函数,会用鼠标当前位置减去左上角位置就是移动的位置.从而实现拖动窗体的效果.

利用网络获取天气

声明一个 QNetworkAccessManager类型的对象:

 QNetworkAccessManager *mNetAccessManager;

把 mNetAccessManager对象创建出来:

 mNetAccessManager =new QNetworkAccessManager(this);

关联信号槽

将mNetworkAccessManager的finish信号,与自定义的onReplied槽函数进行关联: 

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{    
mNetAccessManager =new QNetworkAccessManager(this);
connect(mNetAccessManager,&QNetworkAccessManager::finished,this,&MainWindow::onReplied);
getWeatherInfo("101010100");
}

发送http请求

在mainwindow.h文件里声明一个getWeatherInfo()函数用来发送http的成员函数:

class MainWindow : public QMainWindow
{ 
protected:
 void getWeatherInfo(QString citycode);
}

调用getWeatherInfo()函数来从网络中获取天气:

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{    
//请求北京的天气
getWeatherInfo("101010100");  //北京的城市码
}
//通过输入一个城市的代码获取这个城市的天气
void MainWindow::getWeatherInfo(QString citycode)
{
    QUrl url("http://t.weather.itboy.net/api/weather/city/101010100"+citycode);
    mNetAccessManager->get(QNetworkRequest(url));
}

接收服务端数据

当http请求完毕,返回数据的时候,mNetAccessManager就会发射一个finished信号, 进而调用onReplied()槽函数.

定义onReplied()函数:

void MainWindow::onReplied(QNetworkReply *reply)
{
    qDebug()<<"onReplied success";
    int status_code=reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
}

此时响应头,状态码,响应体,城市码,这些都在reply里存着.我们可以将这些信息打印出来看看:

void MainWindow::onReplied(QNetworkReply *reply)
{
    qDebug()<<"onReplied success";
    int status_code=reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

    qDebug()<<"operation: "<<reply->operation();
    qDebug()<<"status code: "<<status_code;
    qDebug()<<"url: "<<reply->url();
    qDebug()<<"raw header: "<<reply->rawHeaderList();
}

增强代码健壮性:

void MainWindow::onReplied(QNetworkReply *reply)
{
    qDebug()<<"onReplied success";
    int status_code=reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();


    if(reply->error()!=QNetworkReply::NoError||status_code!=200)
    {
        qDebug()<<reply->errorString().toLatin1().data();
        QMessageBox::warning(this,"天气","请求数据失败",QMessageBox::Ok);
    }
    else
    {
        QByteArray byteArray = reply->readAll();
        qDebug()<<"read all: "<<byteArray.data();
    }
    reply->deleteLater();
}

 至此我们已经可以获取出北京市的天气了:

我们把这些数据放到json解析器就可以看的比较清楚: 

天气解析

在mianwindow.h中年声明两个变量:

    Today mToday;
    Day mDay[6];

mToday用来存放今天的天气的情况,mDay[]数组用来存放其他天的天气情况 

解析昨天的天气情况

//解析yesterday
    //解析日期,周几,天气类型
    QJsonObject objData = rootobj.value("data").toObject();
    QJsonObject objYesterday =objData.value("yesterday").toObject();
    mDay[0].week=objYesterday.value("week").toString();
    mDay[0].date=objYesterday.value("ymd").toString();
    mDay[0].type=objYesterday.value("type").toString();


    //解析高低温
    QString s;
    s=objYesterday.value("high").toString().split(" ").at(1);  //18°
    s.left(s.length()-1);  //18
    mDay[0].high=s.toInt();


    s=objYesterday.value("low").toString().split(" ").at(1);  //18°
    s.left(s.length()-1);  //18
    mDay[0].low=s.toInt();

    //风向风力
    objYesterday.value("fx").toString();
    objYesterday.value("fl").toString();

    //污染指数
    mDay[0].aqi=objYesterday.value("aqi").toDouble();

解析近五天的天气情况:

  //3.解析forecast
    QJsonArray forecastArr =objData.value("forecast").toArray();
    for(int i=0;i<5;i++)
    {
        QJsonObject objForeacast =forecastArr[i].toObject();
        mDay[i+1].week=objForeacast.value("week").toString();  //获取一下week
        mDay[i+1].date=objForeacast.value("ymd").toString();  //获取一下ymd


        //天气类型
        mDay[i+1].type=objForeacast.value("type").toString();


        //高温低温
        QString s;
        s=objForeacast.value("high").toString().split(" ").at(1);  //18°
        s.left(s.length()-1);  //18
        mDay[0].high=s.toInt();


        s=objForeacast.value("low").toString().split(" ").at(1);  //18°
        s.left(s.length()-1);  //18
        mDay[0].low=s.toInt();


        //风向风力
        objForeacast.value("fx").toString();
        objForeacast.value("fl").toString();

        //污染指数
        mDay[0].aqi=objForeacast.value("aqi").toDouble();
    }

解析今天的天气数据

    //4.解析今天的天气情况
    mToday.ganmao=objData.value("ganmao").toString();
    mToday.wendu=objData.value("wendu").toInt();
    mToday.quality=objData.value("quality").toString();
    mToday.shidu=objData.value("shidu").toString();
    mToday.pm25=objData.value("pm25").toInt();
    
    mToday.type=mDay[1].type;
    mToday.fx=mDay[1].fx;
    mToday.fl=mDay[1].fl;
    mToday.high=mDay[1].high;
    mToday.low=mDay[1].low;

更新UI

创建对应的数组用来存对应的数据          

mainwindows.h

把控件添加到控件数组(方便使用循环处理)


MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
//控件添加到控件数组
    //添加日期
    mWeekList<<ui->lb_week0<<ui->lb_week1<<ui->lb_week2<<ui->lb_week3<<ui->lb_week4<<ui->lb_week5;
    //添加星期
    mDateList<<ui->lb_date0<<ui->lb_date1<<ui->lb_date2<<ui->lb_date3<<ui->lb_date4<<ui->lb_date5;
    //添加天气图标
    mTypeIconList<<ui->lb_con0<<ui->lb_con1<<ui->lb_con2<<ui->lb_con3<<ui->lb_con4<<ui->lb_con5;
    //添加天气情况
    mTypeList<<ui->lb_type0<<ui->lb_type1<<ui->lb_type2<<ui->lb_type3<<ui->lb_type4<<ui->lb_type5;
    //添加天气污染情况
    mAqiList<<ui->lb_Aqi0<<ui->lb_Aqi1<<ui->lb_Aqi1<<ui->lb_Aqi3<<ui->lb_Aqi0<<ui->lb_Aqi2<<ui->lb_Aqi5;
    //添加风向情况
    mFxList<<ui->lb_fx0<<ui->lb_fx1<<ui->lb_fx2<<ui->lb_fx3<<ui->lb_fx4<<ui->lb_fx5;
    //添加风力情况
    mFlList<<ui->lb_fl0<<ui->lb_fl1<<ui->lb_fl2<<ui->lb_fl3<<ui->lb_fl4<<ui->lb_fl5;
}

UpdatatUI

给某个控件刷上对应的数据:

void MainWindow::updateUI()
{
//标题
    //设置日期 城市
    //注意返回来的值为“20230728”这种格式,要进行转换2023/07/28
    ui->lb_date->setText(QDateTime::fromString(mToday.date,"yyyyMMdd").toString("yyyy/MM/dd") + " " + mDay[1].week);
    ui->lb_city->setText(mToday.city);
//左侧图
    //更新今天
    //ui->lblTypeIcon->setPixmap(mTypeIconMap[mToday.type]);
    ui->lb_temperature->setText(mToday.wendu);
    ui->lb_type->setText(mToday.type);
    ui->lb_LowHigh->setText(QString::number(mToday.low) + "°" +"~" + QString::number(mToday.high) + "°");
    ui->lb_ganmao->setText("感冒指数:" + mToday.ganmao);
    ui->lb_Windfx->setText(mToday.fx);
    ui->lb_Winfl->setText(mToday.fl);
    ui->lb_PM25->setText(QString::number(mToday.pm25));
    ui->lb_shidu->setText(mToday.shidu);
    ui->lb_quality->setText(mToday.quality);
    
    
//右侧图
    //更新6天
    for(int i=0 ; i<6 ; i++)
    {
        //更新星期
        mWeekList[i]->setText("周" + mDay[i].week.right(1)); //数据是”星期六“,取右边第一位
        ui->lb_week0->setText("昨天");
        ui->lb_week1->setText("今天");
        ui->lb_week2->setText("明天");

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

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

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


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

注意事项:

(1)

我们可以看到服务器返回的date数据格式是"yyyMMdd"格式的

而我们想要我们的天气标题格式是yyy/MM/dd,并且后面还有个星期X:

因此我们可以格式改完之后再在加上week数据:

(2)

在获取其他天数的week日期是"星期X"的格式:

但是我们想显示的week是"周X"格式: 

因此我们需要从服务器返回的week数据中抽出"X",再在前面加上"周"进行显示.

(3)

从服务器返回的ymd数据格式为yyyy-MM-dd格式

我们需要的是MM/dd格式:所以我们可以以"-"为分隔符,提取出来MM,dd.

实现天气搜索功能

我们知道我们是通过向服务器发送对应的城市码来获取这个城市的天气的.我们现在想实现写入城市获取对应的城市码,再通过城市码获取对应的天数.

有一套写好的json格式的数据,我们直接引入这套数据就可以了.

 创建一个头文件weatherTool.h

首先我们要创建一个map数组来接受citycode.json文件中对应的城市名称和城市码.

我们可以实现一个初始化函数来完成这一功能.

接着我们写一个getcitycode函数,用来接收我们输入的城市名返回对应的城市码.要注意的是,如果说我们输入的是"北京"这样的城市,有可能citycode.json里存的是"北京市",那么map里肯定就查找不到"北京"城市,我们可以给其加上"市"之后再执行查找.

#ifndef WEATEHER_H
#define WEATEHER_H

#include<QmAP>
#include<QFile>
#include<QString>
#include<QJsonArray>
#include<QJsonDocument>
#include<QJsonParseError>
#include<QJsonValue>
#include<QDebug>

class WeatherTool
{
private:
    static QMap<QString,QString> mcityMap;

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

    }


public:
    static QString getcitycode(QString cityname)
    {
        // 初始化map
        if (mcityMap.isEmpty()) //如果map里是空的,那就初始化Map,往map里插入值
        {
            InitcityMap();
        }
        // 根据城市名字遍历map,获取城市编码
        QMap<QString, QString>::iterator it = mcityMap.find(cityname);
        // 特殊:输入北京/北京市都可以找到
        if (it == mcityMap.end())
        {
            it = mcityMap.find(cityname + "市");
        }
        if (it == mcityMap.end())
        {
            it = mcityMap.find(cityname + "区");
        }
        if (it == mcityMap.end())
        {
            it = mcityMap.find(cityname + "县");
        }
        // 如果遍历到有这个城市名字,就返回编码
        if (it != mcityMap.end())
        {
            return it.value();
        }

        return ""; // 没有就返回空
    }
};

QMap<QString,QString> WeatherTool::mcityMap={};
#endif // WEATEHER_H

实现两种搜索响应方式:

mainwindow.cpp

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

//输入框回车搜索
void MainWindow::on_le_city_returnPressed()
{
    QString cityname = ui->le_city->text();
    getWeatherInfo(cityname);
}

绘制温度曲线

安装事件过滤器

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
     ui->lb_HigtCurve->installEventFilter(this);
     ui->lb_LowCurve->installEventFilter(this);
}

声明三个函数

    bool eventFilter(QObject *watched, QEvent *event) override; //重写绘图事件

    //绘制最高低温曲线
    void paintHight();
    void paintLow();

 eventFilter事件过滤器

 如果监控的是lb_HigtCurve控件,就判断lb_HigtCurve控件是否发出Paint信号,如果发出,那么就执行 paintHight()进行绘制若干天的最高温曲线.lb_LowCurve同样如此.

我们只对lb_HigtCurve和lb_LowCurve控件进行监控,其他控件仍然用父类的eventFilter()默认过滤器

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

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

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

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

 小结:

在构造里我们安装了两个事件过滤器,当我们的lb_HigtCurve和lb_LowCurve控件有事件发生时,就会被当前窗口拦截,然后执行eventFilter()方法.如果lb_HigtCurve标签就绘制高温曲线,如果是lb_LowCurve标签就绘制低温曲线.

高低温曲线的绘制

void MainWindow::paintHight()
{

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

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

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

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

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

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


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

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

}

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

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

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

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

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

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


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

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

刷新UI

void update()
{
    .......
    ui->lb_HigtCurve->update();
    ui->lb_LowCurve->update();
}

成品效果演示

工作流程1总结

在初始化的时候,绑定finished信号和onReplied()槽函数.在构造函数中会请求网络,当我们点击输入框输入城市名称的时候会调用getWeratherInfo()会​​​​​​函数,getWeatherInfo()​​​​​​会在map里根据输入的城市名称查找对应的城市天气码,并且通过该城市天气码向国家气象局提供的天气API接口发送请求该城市近七天的天气情况,在请求完成之后会发出一个finish信号.onRepalied()槽函数会收到这一信号,并通过一个数组存放获取到的所有的天气参数.之后onReplalied()函数会把数组传给parseJson()函数.parseJson()数函数会解析数组里存放的所有天气参数值,并将今天的天气值存放到mToday类里, 将其他6天情况存放到mDay类里.最后parseJson()函数会调用updateUI()函数将mToday和mDay[]里的值刷新到对应的控件上,进行显示.

优化

在初始时输入框里有我们设置的默认文本,而我们在输入城市时必须先把默认文本手动清空,不符合实际情况,因此我们需要设置当输入框响应焦点时不显示默认文本.

修改:

不要在ui设计界面直接在输入框里输入默认值,可以在构造函数里用setPlaceholderText()函数设置默认值,这样我们在手动输入城市名称的时候不会受影响:

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->le_city->setPlaceholderText( "请输入城市名称:" );
}

定位当前城市

在上面情况当中,默认不会显示当前城市的天气.我想实现这个功能.这里可以使用百度定位API.

百度定位API文档如下:

https://api.map.baidu.com/lbsapi/cloud/ip-location-api.htm

首先注册百度开发者平台,然后申请AK,AK记得申请服务端的,IP白名单填写"0.0.0.0/0".

获取的AK密钥如下:

mainwindow.h

QNetworkAccessManager *mNetAccessManager;

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) , ui(new Ui::MainWindow)
{    mNetAccessManager =new QNetworkAccessManager(this);
    connect(mNetAccessManager,&QNetworkAccessManager::finished,this,&MainWindow::Json_city);
    gitcitycode2();
}

//http发送请求定位
void MainWindow::gitcitycode2()
{
    QNetworkRequest request;
    request.setUrl(QUrl("https://api.map.baidu.com/location/ip?ak=你的AK&coor=bd09ll"));
    mNetAccessManager->get(request);
    qDebug() << "发送了定位请求";
}

//获取定位 locat_city就是获取的当前城市的名称

void MainWindow::Json_city(QNetworkReply *reply)
{
     qDebug()<<"Json_city success";
    QString locat_city;
    QString all = reply->readAll();
    qDebug()<<all;
    //unicode 转化为汉字
    QString filename = all;
    do
    {
        int idx = filename.indexOf("\\u");
        QString strHex = filename.mid(idx, 6);
        strHex = strHex.replace("\\u", QString());
        int nHex = strHex.toInt(0, 16);
        filename.replace(idx, 6, QChar(nHex));
    } while (filename.indexOf("\\u") != -1);
        //json解析过程
    QJsonDocument  Document;
    QJsonParseError json_error;
    QJsonDocument json_recv = QJsonDocument::fromJson(all.toUtf8(),&json_error);//解析json对象
    QJsonObject object = json_recv.object();
    if(object.contains("content"))
    {
        QJsonValue value = object.value("content");
        if(value.isObject())
        {
            QJsonObject object_1 = value.toObject();
            if(object_1.contains("address_detail"))
            {
                QJsonValue value_1 = object_1.value("address_detail");
                if(value_1.isObject())
                {
                    QJsonObject object_2 = value_1.toObject();
                    locat_city =object_2.value("city").toString();
                    qDebug()<<locat_city;
                }
            }
        }
    }
    getWeatherInfo(locat_city);  //把获取的当前城市名称传过去
}

效果 

工作流程2总结

   在初始化的时候,绑定finished信号和Json_city()槽函数.在构造函数中调用gitcitycode2()函数,gitcitycode2()函数会通过Http发送网络定位请求.并且在请求完成后发射一个finished信号.Json_city()函数收到这个信号后会被响应,其内部会对获取到的服务器返回的Json数据进行解析,我这里把解析出来的本地城市名称传给getWeatherInfo()函数,getWeatherInfo()函数会从map中获取该城市对应的天气城市码,并通过该城市码向国家气象局获取天气,请求完成之后发射一个finished信号,onReplied()函数会收到该信号并响应,接下来就和工作流程1中的流程一样了.

完整代码

weather · 孙鹏宇/Qt - 码云 - 开源中国 (gitee.com)

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孙鹏宇.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值