基于Qt的天气预报

窗口设置

天气预报的界面一般是没有退出窗口的,所以要设置窗口无边距和固定窗口大小,如下:

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

右键退出

由于窗口没有退出按钮,所以要通过右键弹出菜单来退出程序。
首先要创建菜单和动作,如下:

menu = new QMenu(this);      //构建菜单
action = new QAction("退出"); //构建动作
menu->addAction(action);     //给菜单添加动作

要右键弹出菜单,就要重写void contextMenuEvent(QContextMenuEvent* event)函数

void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
    menu->exec(QCursor::pos()); //使菜单在鼠标右击位置弹出
    event->accept();            //使event不再传递
}

触发动作槽函数

connect(action,&QAction::triggered,this,[=]{
        qApp->exit();   //退出程序
    });

拖动窗口

因为要用到鼠标左键拖拽窗口,所以要重写三个鼠标事件函数

void mousePressEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void MainWindow::mousePressEvent(QMouseEvent *event)
{
    //获取鼠标当前位置与窗口左上角的差值
    if(event->button() == Qt::LeftButton){
        _isDrag = true;
        _point = event->globalPosition().toPoint() - this->pos();
    }
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if(_isDrag){
        //移动窗口
        move(event->globalPosition().toPoint() - _point);
    }
}

void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton){
        _isDrag = false;
    }
}

需要的类

程序中需要的类有3个,分别是:

存放天气数据的类

//存放今天天气数据类
class Today
{
public:
    Today()
    {
        date = "2023-2-27";
        city = "广州";

        ganmao = "感冒指数";

        wendu = 0;
        shidu = "0%";
        pm25 = 0;
        quality = "无数据";

        type = "多云";

        fl = "2级";
        fx = "南风";

        high = 30;
        low = 18;
    }
    QString date;
    QString city;

    QString ganmao;

    QString wendu;
    QString shidu;
    int pm25;
    QString quality;

    QString type;

    QString fx;
    QString fl;

    int high;
    int low;
};

//存放五天天气数据类
class Date
{
public:
    Date()
    {
        date = "2023-2-27";
        week = "周一";

        type = "多云";

        high = 0;
        low = 0;

        fx = "南风";
        fl = "2级";

        aqi = 0;
    }
    QString date;
    QString week;

    QString type;

    int high;
    int low;

    QString fx;
    QString fl;

    int aqi;
};

解析城市编码的类

//城市编码类,因为每个城市都有唯一且固定的编码,所以采用单例设计模式中的饿汉模式
class WeatherTool
{
public:
    //禁用该类的拷贝构造函数和拷贝赋值操作符重载函数
    WeatherTool(const WeatherTool& obj) = delete;
    WeatherTool& operator = (const WeatherTool& obj) = delete;
    //返回该单例对象
    static WeatherTool* getInstance()
    {
        return _weathertool;
    }

    //根据城市获取对应编码
    static QString getCityCode(QString cityname);

private:
    WeatherTool() = default;            //设为默认构造函数
    static QMap<QString,QString> _map;  //存放城市及对应编码
    static WeatherTool* _weathertool;   //单例对象

    //初始化map
    static void initCityMap();
};

将json文件中的城市及对应编码解析出来后,存放到一个map中,map键值对是城市名称及其对应编码

//根据城市获取对应编码
QString WeatherTool::getCityCode(QString cityname)
{
    if(_map.isEmpty())  initCityMap();  //初始化map
    QMap<QString,QString>::iterator it = _map.find(cityname);
    if(it == _map.end()){
        //搜索城市后戴市字
        it = _map.find(cityname + "市");
    }
    if(it == _map.end()){
        //搜索城市后戴市字
        it = _map.find(cityname + "县");
    }
    //找到了城市对应编码
    if(it != _map.end()){
        return it.value();
    }
    return "";
}

//初始化map
void WeatherTool::initCityMap()
{
    QString filename = QCoreApplication::applicationDirPath();//获取当前程序允许的路径
    filename += "/city.json";           //json文件路径
    QFile file(filename);               //创建文件
    file.open(QIODevice::ReadOnly | QIODevice::Text);   //以文本形式读取
    QByteArray json = file.readAll();  //获取所有数据
    file.close();                       //关闭文件
    QJsonParseError err;                //存放错误信息
    QJsonDocument doc = QJsonDocument::fromJson(json,&err);
    QJsonArray citys = doc.array();     //转换为数组类型
    //获取json中的城市及编码
    for(int i = 0;i < citys.size();++i){
        QString city_name = citys[i].toObject().value("city_name").toString();
        QString city_code = citys[i].toObject().value("city_code").toString();
        if(city_code.size() > 0){
            //将城市及编码放入map
            _map.insert(city_name,city_code);
        }
    }

}

解析天气数据的类

//解析天气JSON的类
class WeatherJson : public QObject
{
    Q_OBJECT
public:
    WeatherJson();

    //发送http请求获取天气数据
    void getCityInfo(QString cityname);

    //解析JSON数据
    void parseJson(QByteArray& array);

    QNetworkAccessManager* getNetManeger();

    Today getToday();

    Date* getDate();

public slots:
    //发送请求结束后的槽函数
    void onReply(QNetworkReply* reply);

signals:
    void changeUI();

private:

    //HTTP
    QNetworkAccessManager* networkaccessmaneger;

    //天气数据类
    Today today;
    Date date[5];

};

首先要发送http请求,然后解析json文件

//发送http请求获取天气数据
void WeatherJson::getCityInfo(QString cityname)
{
    QString citycode = WeatherTool::getInstance()->getCityCode(cityname);//获取城市对应编码
    if(citycode.isEmpty()){
        QMessageBox::warning(0,"天气","请检查输入是否正确!",QMessageBox::Ok);
        return;
    }
    QUrl url("http://t.weather.sojson.com/api/weather/city/" + citycode);
    networkaccessmaneger->get(QNetworkRequest(url));
}
//解析JSON数据
void WeatherJson::parseJson(QByteArray &array)
{
    //存放错误信息
    QJsonParseError err;
    QJsonDocument doc = QJsonDocument::fromJson(array,&err);
    if(err.error != QJsonParseError::NoError)   return;

    QJsonObject rootobj = doc.object();

    //解析日期和城市
    today.date = rootobj.value("date").toString();
    today.city = rootobj.value("cityInfo").toObject().value("city").toString();

    //解析yesterday
    QJsonObject objData = rootobj.value("data").toObject();
    QJsonObject objyester = objData.value("yesterday").toObject();
    date[0].date = objyester.value("ymd").toString();
    date[0].week = objyester.value("week").toString();
    date[0].type = objyester.value("type").toString();
    //最高温
    QString s = objyester.value("high").toString().split(" ").at(1);
    date[0].high = s.left(s.length()-1).toInt();
    //最低温
    s = objyester.value("low").toString().split(" ").at(1);
    date[0].low = s.left(s.length()-1).toInt();
    //风力及等级
    date[0].fx = objyester.value("fx").toString();
    date[0].fl = objyester.value("fl").toString();
    //污染指数
    date[0].aqi = objyester.value("aqi").toInt();

    //解析forcast中5天的数据
    QJsonArray forecastArr = objData.value("forecast").toArray();
    for(int i = 0;i < 4;i++){
        QJsonObject objForecast = forecastArr[i].toObject();
        date[i+1].date = objForecast.value("ymd").toString();
        date[i+1].week = objForecast.value("week").toString();
        date[i+1].type = objForecast.value("type").toString();
        //最高温
        QString s = objForecast.value("high").toString().split(" ").at(1);
        date[i+1].high = s.left(s.length()-1).toInt();
        //最低温
        s = objForecast.value("low").toString().split(" ").at(1);
        date[i+1].low = s.left(s.length()-1).toInt();
        //风力及等级
        date[i+1].fx = objForecast.value("fx").toString();
        date[i+1].fl = objForecast.value("fl").toString();
        //污染指数
        date[i+1].aqi = objForecast.value("aqi").toInt();
    }
    //解析今天的数据
    today.ganmao = objData.value("ganmao").toString();
    today.wendu = objData.value("wendu").toString();
    today.shidu = objData.value("shidu").toString();
    today.pm25 = objData.value("pm25").toInt();
    today.quality = objData.value("quality").toString();
    today.type = date[1].type;
    today.fx = date[1].fx;
    today.fl = date[1].fl;
    today.high = date[1].high;
    today.low = date[1].low;
}

QNetworkAccessManager* WeatherJson::getNetManeger()
{
    return networkaccessmaneger;
}

Today WeatherJson::getToday()
{
    return today;
}

Date* WeatherJson::getDate()
{
    return date;
}

mainwindow.cpp

发送http请求结束后,会触发槽函数

//发送请求结束后的槽函数
void WeatherJson::onReply(QNetworkReply *reply)
{
    int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    //如果请求失败
    if(reply->error() != QNetworkReply::NoError || status_code != 200){
        //输出错误信息
        qDebug() << reply->errorString().toLatin1().data();
        QMessageBox::warning(0,"天气","请求数据失败!",QMessageBox::Ok);
    }else{
        QByteArray array = reply->readAll();    //读取数据
        parseJson(array);
        emit changeUI();
    }
    reply->deleteLater();   //析构
}

在该槽函数中发生信号changeUI(),主函数中接收到后会更新UI界面显示天气数据

绘制温度曲线

绘制最高最低温曲线用到了事件过滤器

//给绘图控件添加事件过滤器
    ui->highLabel->installEventFilter(this);
    ui->lowLabel->installEventFilter(this);
//绘制温度曲线
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    //最高温
    if(watched == ui->highLabel && event->type() == QEvent::Paint){
        paintHigh();
    }
    //最低温
    if(watched == ui->lowLabel && event->type() == QEvent::Paint){
        paintLow();
    }
    return QWidget::eventFilter(watched,event);
}
void MainWindow::paintHigh()
{
    QPainter painter(ui->highLabel);
    //抗锯齿
    painter.setRenderHint(QPainter::Antialiasing,true);
    //获取x坐标
    int pointx[5] = {0};
    for(int i = 0;i < 5;i++){
        pointx[i] = weeklist[i]->pos().x() + weeklist[i]->width()/2;
    }
    //获取y坐标
    int value = 0;
    for(int i = 0;i < 5;i++){
        value += date[i].high;
    }
    value = value/5;    //最高温平均值
    int pointy[5] = {0};
    for(int i = 0;i < 5;i++){
        pointy[i] = ui->highLabel->height()/2 - ((date[i].high - value) * 3);
    }
    QPen pen = painter.pen();
    pen.setWidth(1);
    pen.setColor(QColor(255,170,0));
    painter.setPen(pen);
    painter.setBrush(QColor(255,170,0));
    //开始绘制
    for(int i = 0;i < 5;i++){
        //显示点
        painter.drawEllipse(QPoint(pointx[i],pointy[i]),3,3);
        //显示温度
        painter.drawText(pointx[i]-10,pointy[i]-10,QString::number(date[i].high) + "°C");
    }
    //绘制曲线
    for(int i = 0;i < 4;i++){
        if(i == 0){
            pen.setStyle(Qt::DotLine);  //虚线
            painter.setPen(pen);
        }else{
            pen.setStyle(Qt::SolidLine);  //实线
            painter.setPen(pen);
        }
        painter.drawLine(pointx[i],pointy[i],pointx[i+1],pointy[i+1]);
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值