Qt项目天气预报(8) - 绘制温度曲线 + 回车搜索(最终篇)

全部内容在专栏

Qt项目 天气预报_mx_jun的博客-CSDN博客

目录

绘制温度曲线

事件过滤器在子控件上绘图

    子控件下载事件过滤器

事件过滤器进行绘图 - eventFilter

画初步高温曲线

画初步低温曲线

效果演示

 画低温曲线

 画高温曲线

效果演示

按下回车搜索:

returnPress()槽函数

整体代码

widget.h

widget.cpp

day.h

day.cpp(无内容)

citycodeutils.h

citycodeutils.cpp

整体ui预览

项目总结: 


绘制温度曲线

事件过滤器在子控件上绘图


//难点 -- 我们已经添加了很多控件和样式表,在大的this对象上绘图有难度
//我们可以调用事件过滤器去在子控件上绘图 


    子控件下载事件过滤器


    ui->widget0404->installEventFilter(this);
    ui->widget0405->installEventFilter(this);


事件过滤器进行绘图 - eventFilter

bool Widget::eventFilter(QObject *watched, QEvent *event)
{
    if(watched == ui->widget0404  && event->type() == QEvent::Paint){//在这个控件触发绘图事件,就调用api绘图
     drawTempLineHigh();
     return true; //表示事件已经被处理
    }
    if(watched == ui->widget0405  && event->type() == QEvent::Paint){//在这个控件触发绘图事件,就调用api绘图
     drawTempLineLow();
     return true; //表示事件已经被处理
    }
    return QWidget::eventFilter(watched, event);
}

画初步高温曲线

void Widget::drawTempLineHigh()
{
    //在widget0404 上绘图
  QPainter painter(ui->widget0404);
  painter.setPen(Qt::yellow);
  painter.drawLine(QPoint(10,10),QPoint(30,30));

}

画初步低温曲线


 

void Widget::drawTempLineLow()
{
    //在widget0405 上绘图
  QPainter painter(ui->widget0405);
  painter.setPen(Qt::yellow);
  painter.drawLine(QPoint(10,10),QPoint(30,30));

}

效果演示


 

 画低温曲线

void Widget::drawTempLineLow()
{
    //在widget0405 上绘图
  QPainter painter(ui->widget0405);
  painter.setPen(QColor(70, 192, 203));
  painter.setBrush(QColor(70, 192, 203));//设置画刷,让圆变成实心
  painter.setRenderHint(QPainter::Antialiasing,true);

  // 计算七天最大温度的平均值
  int ave;
  int sum = 0;
  int offset = 0; // 偏移值
  int middle = ui->widget0405->height()/2;
  for(int i=0;i<6;++i){
  sum += day[i].mTempLow.toInt();
  }
  ave = sum/6;
  //定义出6个点
  QPoint points[6];
  for(int i=0;i<6;++i){
   points[i].setX(mAirqList[i]->x() + mAirqList[i]->width()/2); // 设置在对应上方控件的中间位置
   offset = (day[i].mTempLow.toInt() - ave)*4; // 计算偏移值
   points[i].setY(middle-offset); // 记得y轴正向朝下,so我们这里是-
   // 画出6个温度点
   painter.drawEllipse(QPoint(points[i]),3,3);
   // 画出对应温度
   painter.drawText(points[i].x()-15,points[i].y()-15,day[i].mTempLow+"°");
  }

  //画出5条线将6个点相连接
  for(int i=0;i<5;++i){
      painter.drawLine(points[i],points[i+1]);
  }

}


 


 画高温曲线
 


void Widget::drawTempLineHigh()
{
    //在widget0404 上绘图
  QPainter painter(ui->widget0404);
  painter.setPen(Qt::yellow);
  painter.setBrush(Qt::yellow);//设置画刷,让圆变成实心
  painter.setRenderHint(QPainter::Antialiasing,true);

  // 计算七天最大温度的平均值
  int ave;
  int sum = 0;
  int offset = 0; // 偏移值
  int middle = ui->widget0404->height()/2;
  for(int i=0;i<6;++i){
  sum += day[i].mTempHigh.toInt();
  }
  ave = sum/6;
  //定义出6个点
  QPoint points[6];
  for(int i=0;i<6;++i){
   points[i].setX(mAirqList[i]->x() + mAirqList[i]->width()/2); // 设置在对应上方控件的中间位置
   offset = (day[i].mTempHigh.toInt() - ave)*4; // 计算偏移值
   points[i].setY(middle-offset); // 记得y轴正向朝下,so我们这里是-
   // 画出6个温度点
   painter.drawEllipse(QPoint(points[i]),3,3);
   // 画出对应温度
   painter.drawText(points[i].x()-15,points[i].y()-15,day[i].mTempHigh+"°");
  }

  //画出5条线将6个点相连接
  for(int i=0;i<5;++i){
      painter.drawLine(points[i],points[i+1]);
  }

}

效果演示



按下回车搜索:

returnPress()槽函数

//按下回车刷新
void Widget::on_lineEditCity_returnPressed()
{
  on_pushButton_clicked(); // 回车被按下,调用搜索槽函数
}

整体代码

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QLabel>
#include <QMenu>
#include <QNetworkReply>
#include <QWidget>
#include <QList>

#include "citycodeutils.h"
#include "day.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Day day[7];
    // 定义7个列表去存放我们的label控件内容
    QList<QLabel *> mDateList;
    QList<QLabel *> mWeekList;
    QList<QLabel *> mIconList;
    QList<QLabel *> mWeatypeList;
    QList<QLabel *> mAirqList;
    QList<QLabel *> mFxList;
    QList<QLabel *> mFlList;


    Widget(QWidget *parent = nullptr);
    ~Widget();

protected:
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
bool eventFilter(QObject *watched,QEvent *event);

public slots:
 void readHttpReply(QNetworkReply* reply);

private slots:
 void on_pushButton_clicked();

 void on_lineEditCity_returnPressed();

private:
    Ui::Widget *ui;
    QMenu *menuQuit;
    QPoint mOffset; //偏移值
    QNetworkReply* reply;

    QString urlyiKe; // 定义全局的url
    QNetworkAccessManager *manager;
    CityCodeUtils cityCodeUtils;
    QMap<QString,QString> mTypeMap;

    void parseWeatherJsonData(QByteArray rawData);
    void parseWeatherJsonDataNew(QByteArray rawData);// 七天的
    void updateUI();
    void drawTempLineHigh();
    void drawTempLineLow();
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QMouseEvent>
#include <QDebug>
#include <QNetworkAccessManager>
#include <QMessageBox>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QPainter>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    setFixedSize(586,1048); // 固定大小
    setWindowFlag(Qt::FramelessWindowHint); //去除上方边框

    menuQuit = new QMenu(this);
    //设置菜单项文字颜色:白色
    menuQuit->setStyleSheet("QMenu::item{color:white}");

    //创建行为对象 -- 当调用这种行为打的时候弹出close.png这张图片, 指向这个图片的时候显示"退出"字样
    QAction *closeAct = new QAction(QIcon(":/close.png"), tr("退出"), this);
    menuQuit->addAction(closeAct); //为menu添加退出行为
    // 为menu绑定信号与槽
    connect(menuQuit,&QMenu::triggered,this,[=](){
        this->close();
    });



    //由QNetworkAccessManager 发起request请求:
    //实例化network对象
    manager = new QNetworkAccessManager(this);
    connect(manager, &QNetworkAccessManager::finished,[](){
        qDebug()<<"manager Finnish!";
    });

    // http://t.weather.itboy.net/api/weather/city/101010100
    QUrl urlItBoy("http://t.weather.itboy.net/api/weather/city/101010100");
    //http://v1.yiketianqi.com/api?unescape=1&version=v91&appid=65521391&appsecret=Dv2eKMLL&ext=&cityid=
    // 一天
    //urlyiKe ="http://v1.yiketianqi.com/api?unescape=1&version=v61&appid=65521391&appsecret=Dv2eKMLL";
    //七天
    urlyiKe ="http://v1.yiketianqi.com/api?unescape=1&version=v9&appid=65521391&appsecret=Dv2eKMLL";


    QUrl urlTianQi(urlyiKe);

    //QNetworkRequest - 指定请求的url地址
    QNetworkRequest res(urlTianQi); //根据网址实例化QUrl对象,再根据这个对象实例化QNetworkRequest对象
    reply = manager->get(res);
    //QNetworkReply网络请求后进行信号读取
    connect(manager,&QNetworkAccessManager::finished,this,&Widget::readHttpReply);



    //初始化七天数据列表
    mWeekList<<ui->labelday1<<ui->labelday2
             <<ui->labelday3<<ui->labelday4
             <<ui->labelday5<<ui->labelday6;

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

   mIconList<<ui->labelWeahterIcon0<<ui->labelWeahterIcon1
            <<ui->labelWeahterIcon2<<ui->labelWeahterIcon3
            <<ui->labelWeahterIcon4<<ui->labelWeahterIcon5;

  mWeatypeList<<ui->labelWeatherTypeDate0<<ui->labelWeatherTypeDate1
              <<ui->labelWeatherTypeDate2<<ui->labelWeatherTypeDate3
              <<ui->labelWeatherTypeDate4<<ui->labelWeatherTypeDate5;

 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;

    // 根据天气插入对应图标
    //根据keys,设置icon的路径

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


    //下载事件过滤器
    ui->widget0404->installEventFilter(this);
    ui->widget0405->installEventFilter(this);

}

/*
 QNetworkAccessManager *manager = new QNetworkAccessManager(this);
 connect(manager, &QNetworkAccessManager::finished,
         this, &MyClass::replyFinished);

 manager->get(QNetworkRequest(QUrl("http://qt-project.org")));
*/



Widget::~Widget()
{
    delete ui;
}
/*
 QMenu menu;
 QAction *at = actions[0]; // Assumes actions is not empty
 foreach (QAction *a, actions)
     menu.addAction(a);
 menu.exec(pos, at);
*/

//鼠标按下事件
void Widget::mousePressEvent(QMouseEvent *event)
{
    //重写鼠标右键事件
    if(event->button() == Qt::RightButton){
        qDebug()<<"右键";
        menuQuit->exec(QCursor::pos()); // 弹出位置为鼠标当前的位置
    }


    //重写鼠标左键事件 --  实现拖动窗口
    //鼠标当前位置: event->globalPos()
    //窗口当前位置:this->pos()

    //新窗口位置:
    //1.当鼠标左键被按下的时候记录鼠标/窗口当前值,还有鼠标与窗口的相对值 event->pos() --鼠标相对窗口的坐标
    //2.鼠标左键释放的时候获得鼠标当前值,对应的窗口位置也根据相对距离进行偏移

    if(event->button() == Qt::LeftButton){
        qDebug()<<"左键";
        //pos() 是相对整个widget页面的坐标  globalpos() 才是相对真个电脑窗口的坐标
        //以下两种方式均可得到偏移值
        //mOffset = event->globalPos()-this->pos();
        mOffset = event->pos();
        //qDebug()<<mOffset.x()<<"  "<<mOffset.y();
    }

}

//鼠标移动事件
void Widget::mouseMoveEvent(QMouseEvent *event)
{
    // 将窗口根据鼠标当前位置和偏移值进行移动(这个值是固定的,作为窗口移动的桥梁)
    this->move(event->globalPos()-mOffset);
}

// 事件过滤器进行绘图
bool Widget::eventFilter(QObject *watched, QEvent *event)
{
    if(watched == ui->widget0404  && event->type() == QEvent::Paint){//在这个控件触发绘图事件,就调用api绘图
     drawTempLineHigh();
     return true; //表示事件已经被处理
    }
    if(watched == ui->widget0405  && event->type() == QEvent::Paint){//在这个控件触发绘图事件,就调用api绘图
     drawTempLineLow();
     return true; //表示事件已经被处理
    }
    return QWidget::eventFilter(watched, event);
}


// 解析获取到的json数据
void Widget::parseWeatherJsonData(QByteArray rawData)
{
    QJsonDocument jsonObj = QJsonDocument::fromJson(rawData); // 先把原始数据转为JSON类型

    if(!jsonObj.isNull() && jsonObj.isObject()){ // jsonObj不为空,并且是Obeject类型
        QJsonObject objRoot = jsonObj.object();
        //解析我们获得的json数据, 填入到相关 控件中

        //解析日期
        QString date = objRoot["date"].toString();
        QString week = objRoot["week"].toString();
        ui->labelCurrentData->setText(date + " " + week); // 把读取到的日期和星期加入到右上角的控件  labelCurrentData 中

        //解析城市名称
        QString cityName =objRoot["city"].toString();
        ui->labelCity->setText(cityName+"市");

        //解析当前温度
        QString curTem = objRoot["tem"].toString();
        ui->labelTemp->setText(curTem+"℃"); // 显示当前温度
        QString lowTem = objRoot["tem2"].toString();
        QString highTem = objRoot["tem1"].toString();
        ui->labelTempRange->setText(lowTem + "~" +highTem +"℃"); // 显示温度范围

        //解析天气类型
        ui->labelWeatherType->setText(objRoot["wea"].toString());
        ui->labelWeatherIcon->setPixmap(mTypeMap[objRoot["wea"].toString()]); // 根据键值对匹配对应图片

        //解析感冒指数
        ui->labelGanMao->setText(objRoot["air_tips"].toString());


        //解析风向
        ui->labelFengXiang->setText(objRoot["win"].toString()); //风向
        ui->labelFengXiangData->setText(objRoot["win_speed"].toString());//风力

        //解析PM2.5
        ui->labelPM25Data ->setText(objRoot["air_pm25"].toString());
        //湿度
        ui->labelShiDuData->setText(objRoot["humidity"].toString());
        //空气质量
        ui->labelAriData->setText(objRoot["air_level"].toString());
    }
}

//七天json的数据解析
void Widget::parseWeatherJsonDataNew(QByteArray rawData)
{
    QJsonDocument jsonDoc = QJsonDocument::fromJson(rawData);
    if(!jsonDoc.isNull() && jsonDoc.isObject()){
     QJsonObject jsonRoot = jsonDoc.object();
     //解析城市
     day[0].mCity = jsonRoot["city"].toString();
     day[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();
        qDebug()<<obj["date"].toString()<<obj["wea"].toString();
        // 将解析到这七年每天的数据解析到我们的数组中
        day[i].mDate = obj["date"].toString();
        day[i].mWeek = obj["week"].toString();
        day[i].mWeathType = obj["wea"].toString();
        day[i].mTemp = obj["tem"].toString();
        day[i].mTempLow = obj["tem2"].toString();
        day[i].mTempHigh = obj["tem1"].toString();
        day[i].mFx = obj["win"].toArray()[0].toString();
        day[i].mFl = obj["win_speed"].toString();
        day[i].mAirq = obj["air_level"].toString();
        // 给出穿建议
        //day[i].mTips = obj["air_tips"].toString();
        day[i].mTips = obj["index"].toArray()[3].toObject()["desc"].toString();

        day[i].mHu = obj["humidity"].toString();
       }
     }
    }
// 定义一个函数去给 ui更新数据
    updateUI();

}

// 更新ui界面上的信息
void Widget::updateUI()
{
    //解析我们获得的json数据, 填入到相关 控件中

    QPixmap pixmap;

    //解析日期

    ui->labelCurrentData->setText(day[0].mDate + " " + day[0].mWeek); // 把读取到的日期和星期加入到右上角的控件  labelCurrentData 中

    //解析城市名称

    ui->labelCity->setText(day[0].mCity+"市");

    //解析当前温度
    ui->labelTemp->setText(day[0].mTemp+"℃"); // 显示当前温度
    ui->labelTempRange->setText(day[0].mTempLow + "~" +day[0].mTempHigh +"℃"); // 显示温度范围

    //解析天气类型
    ui->labelWeatherType->setText(day[0].mWeathType);
    ui->labelWeatherIcon->setPixmap(mTypeMap[day[0].mWeathType]); // 根据键值对匹配对应图片

    //解析感冒指数
    ui->labelGanMao->setText(day[0].mTips);


    //解析风向
    ui->labelFengXiang->setText(day[0].mFx); //风向
    ui->labelFengXiangData->setText(day[0].mFl);//风力

    //解析PM2.5
    ui->labelPM25Data ->setText(day[0].mPm25);
    //湿度
    ui->labelShiDuData->setText(day[0].mHu);
    //空气质量
    ui->labelAriData->setText(day[0].mAirq);
    // 更新七个QList的数据
    for(int i=0;i<6;++i){
     mWeekList[i]->setText(day[i].mWeek);


     QStringList   daylist  = day[i].mDate.split('-'); //分割字符串 -
     mDateList[i]->setText(daylist.at(1) + "-" + daylist.at(2)); // 原本是2024-6-24 ,我们只要后两位

     // 缩放图标的大小让他能够匹配上

     int index =day[i].mWeathType.indexOf("转"); //包含'转'的天气
     if(index != -1){//包含'转'
            pixmap  = mTypeMap[day[i].mWeathType.left(index)]; // 拿到'转'左边的天气图片,例:晴转多云,拿到晴
     }
     else{
     pixmap  = mTypeMap[day[i].mWeathType];
     }
     pixmap  = pixmap.scaled(mIconList[i]->size(),Qt::KeepAspectRatio); //缩放图标的大小为图片大小,并用KeepAspectRatio 参数,不让图片被拉伸

     mIconList[i]->setPixmap(pixmap);
     mWeatypeList[i]->setText(day[i].mWeathType);
     // 根据空气质量情况设置对应的颜色
     QString  airQ = day[i].mAirq;
     mAirqList[i]->setText(airQ);
     //设置对应样式表
     if(airQ == "优"){
      mAirqList[i]->setStyleSheet(
              "color: rgb(230, 230, 230); background-color: rgb(130, 213, 32); border-radius: 7px");
     }
     if(airQ == "良"){
      mAirqList[i]->setStyleSheet(
              "color: rgb(230, 230, 230); background-color: rgb(255, 187, 69); border-radius: 7px");
     }
     if(airQ == "轻度污染"){
      mAirqList[i]->setStyleSheet(
              "color: rgb(230, 230, 230);background-color: rgb(239, 121, 24);border-radius: 7px");
     }
     if(airQ == "中度污染"){
      mAirqList[i]->setStyleSheet(
              "color: rgb(230, 230, 230); background-color: rgb(255, 17, 17); border-radius: 7px");
     }
     if(airQ == "重度污染"){
      mAirqList[i]->setStyleSheet(
              "color: rgb(230, 230, 230); background-color: rgb(153, 0, 0); border-radius: 7px");
     }



     mFxList[i]->setText(day[i].mFx);
     // 风力也会涉及"转",我们设置为左边的即可
     index = day[i].mFl.indexOf("转");
     if(index != -1){
     mFlList[i]->setText(day[i].mFl.left(index));
     }
     else{
     mFlList[i]->setText(day[i].mFl);
     }
    }
    mWeekList[0]->setText("今天");
    mWeekList[1]->setText("明天");
    mWeekList[2]->setText("后天");

    update(); // 调用我们的绘图事件
}

// 画高温曲线
void Widget::drawTempLineHigh()
{
    //在widget0404 上绘图
  QPainter painter(ui->widget0404);
  painter.setPen(Qt::yellow);
  painter.setBrush(Qt::yellow);//设置画刷,让圆变成实心
  painter.setRenderHint(QPainter::Antialiasing,true);

  // 计算七天最大温度的平均值
  int ave;
  int sum = 0;
  int offset = 0; // 偏移值
  int middle = ui->widget0404->height()/2;
  for(int i=0;i<6;++i){
  sum += day[i].mTempHigh.toInt();
  }
  ave = sum/6;
  //定义出6个点
  QPoint points[6];
  for(int i=0;i<6;++i){
   points[i].setX(mAirqList[i]->x() + mAirqList[i]->width()/2); // 设置在对应上方控件的中间位置
   offset = (day[i].mTempHigh.toInt() - ave)*4; // 计算偏移值
   points[i].setY(middle-offset); // 记得y轴正向朝下,so我们这里是-
   // 画出6个温度点
   painter.drawEllipse(QPoint(points[i]),3,3);
   // 画出对应温度
   painter.drawText(points[i].x()-15,points[i].y()-15,day[i].mTempHigh+"°");
  }

  //画出5条线将6个点相连接
  for(int i=0;i<5;++i){
      painter.drawLine(points[i],points[i+1]);
  }

}

// 画低温曲线
void Widget::drawTempLineLow()
{
    //在widget0405 上绘图
  QPainter painter(ui->widget0405);
  painter.setPen(QColor(70, 192, 203));
  painter.setBrush(QColor(70, 192, 203));//设置画刷,让圆变成实心
  painter.setRenderHint(QPainter::Antialiasing,true);

  // 计算七天最大温度的平均值
  int ave;
  int sum = 0;
  int offset = 0; // 偏移值
  int middle = ui->widget0405->height()/2;
  for(int i=0;i<6;++i){
  sum += day[i].mTempLow.toInt();
  }
  ave = sum/6;
  //定义出6个点
  QPoint points[6];
  for(int i=0;i<6;++i){
   points[i].setX(mAirqList[i]->x() + mAirqList[i]->width()/2); // 设置在对应上方控件的中间位置
   offset = (day[i].mTempLow.toInt() - ave)*4; // 计算偏移值
   points[i].setY(middle-offset); // 记得y轴正向朝下,so我们这里是-
   // 画出6个温度点
   painter.drawEllipse(QPoint(points[i]),3,3);
   // 画出对应温度
   painter.drawText(points[i].x()-15,points[i].y()-15,day[i].mTempLow+"°");
  }

  //画出5条线将6个点相连接
  for(int i=0;i<5;++i){
      painter.drawLine(points[i],points[i+1]);
  }

}




//http网络请求后进行读取槽函数
void Widget::readHttpReply(QNetworkReply* reply)
{

    int resCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();//404
    qDebug()<<resCode;
    if(reply->error() == QNetworkReply::NoError && resCode == 200){ // 没出错的情况下执行
        //大多数服务器网址返回的编码格式是 utf-8,需要进行格式转化
        QByteArray data = reply->readAll();
        //parseWeatherJsonData(data);
        parseWeatherJsonDataNew(data);
        //qDebug()<<QString::fromUtf8(data); // 将读到utf-8格式的数据转为QString类型进行输出
    }
    else{
        //qDebug()<<"请求失败"<<reply->errorString();
        QMessageBox msg;
        msg.setWindowTitle("错误");
        msg.setText("网络请求失败!");
        msg.setStyleSheet("QPushButton{color:red};");//设置按钮样式
        msg.setStandardButtons(QMessageBox::Ok); //添加Ok按钮
        msg.exec();// 调用QMessageBox对象
    }
}



//根据用户输入城市名字获取数据
void Widget::on_pushButton_clicked()
{
    QString cityNameFromUser = ui->lineEditCity->text();
    QString cityCode = cityCodeUtils.getCityCodeFromName(cityNameFromUser);
    if(cityCode != ""){ // 能匹配到根据城市id 匹配 url
        urlyiKe += "&cityid=" +cityCode;
        qDebug()<<urlyiKe;
        manager->get(QNetworkRequest(QUrl(urlyiKe)));
    }
    else{ // 没找到

        QMessageBox msg;
        msg.setWindowTitle("错误");
        msg.setText("请输入正确的城市名称!");
        msg.setStyleSheet("QPushButton{color:red};");//设置按钮样式
        msg.setStandardButtons(QMessageBox::Ok); //添加Ok按钮
        msg.exec();// 调用QMessageBox对象
    }

}

//按下回车刷新
void Widget::on_lineEditCity_returnPressed()
{
  on_pushButton_clicked(); // 回车被按下,调用搜索槽函数
}

day.h

#ifndef DAY_H
#define DAY_H

#include <QString>



class Day
{
public:
    Day();

QString mDate;
QString mWeek;
QString mCity;
QString mTemp;
QString mWeathType;
QString mTempLow;
QString mTempHigh;

QString mTips;
QString mFx;
QString mFl;
QString mPm25;
QString mHu;
QString mAirq;

};

#endif // DAY_H

day.cpp(无内容)

#include "day.h"

Day::Day()
{

}

citycodeutils.h

#ifndef CITYCODEUTILS_H
#define CITYCODEUTILS_H

#include <QMap>



class CityCodeUtils
{
public:
    CityCodeUtils();

    QMap<QString,QString> cityMap={};
    QString getCityCodeFromName(QString cityName);

    void initCityMap();


};

#endif // CITYCODEUTILS_H

citycodeutils.cpp

#include "citycodeutils.h"

#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>

CityCodeUtils::CityCodeUtils()
{

}

//初始化QMap 并寻找城市名
QString CityCodeUtils::getCityCodeFromName(QString cityName)
{

    if(cityMap.isEmpty()){ // 这个map为空就初始化
    initCityMap(); // 初始化QMap,把json文件内容中的city_name city_code-以键值对的形式添加到QMap对象cityMao中
    }
    //根据城市名寻找对应的QMap对象
    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 ""; // 四种判断都找不到就返回"" --> 会给出对应QMessageBox的报错
    }

   return it.value();
}

// 初始化QMap,把json文件内容中的city_name city_code-以键值对的形式添加到QMap对象cityMao中
void CityCodeUtils::initCityMap()
{
    QFile file(":/citycode.json");
    file.open(QIODevice::ReadOnly);
    QByteArray rawData = file.readAll();
    file.close();

    QJsonDocument jsonDoc = QJsonDocument::fromJson(rawData);

    if(jsonDoc.isArray()){
        QJsonArray citys = jsonDoc.array();
        for(QJsonValue value:citys){
            if(value.isObject()){
                //读取对应键值对
                QString cityName = value["city_name"].toString();
                QString cityCode = value["city_code"].toString();
                //添加到QMap对象中进行初始化
                cityMap.insert(cityName,cityCode);
            }

        }

    }
}

整体ui预览

更详细的ui界面请看第一篇:  Qt项目天气预报(1) - ui界面搭建-CSDN博客

项目总结: 

本次项目包含了qt的很多内容:

光是ui界面搭建就需要花上半天,通过stylelsheet  样式表 的编写 让我们控件更加美观

通过http协议 获得天气API 的json数据

通过json几个常用类(

QJsonDocument  - 表示JSON数据结构,可以包含一个对象(QJsonObject)或数组(QJsonArray)
QJsonObject - 表示JSON对象,即键值对的集合 {}

QJsonArray- 表示JSON数组,即有序的值集合[]

)进行json数据的解析,并把解析到的数据与控件关联起来更新控件数据

同时通过QList去管理多个控件组

通过QPainter 配合事件过滤器去进行温度曲线的绘制 ... 

喜欢的朋友别忘了点赞,收藏,转发,谢谢啦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/758570.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ETAS工具导入DEXT生成Dcm及Dem模块(二)

文章目录 前言DcmDcmDsdDcmDslDcmDspDcmPageBufferCfgDem报错解决总结前言 之前一篇文章介绍了导入DEXT之后在cfggen之前的更改,cfggen完成之后,就可以生成dcm,dem的配置了,但生成完配置后,如果直接生成BSW代码,会报错。本文介绍在cfggen完成后,生成BSW代码前的修改 Dc…

Go环境安装---附带每一步截图

Windows环境 Go安装包下载 下载后直接安装步骤按照即可。 测试 winR 输入cmd 在命令行输出go version可以看到自己的版本。 go env 查看环境变量 在桌面创建hello.go的文件 编写代码。注意&#xff0c;编码必修是UTF-8 在命令行输入路径刚刚代码所在的路径&#x…

【从零开始学架构 架构基础】三 架构设计的复杂度来源:高可用复杂度来源

架构设计的复杂度来源其实就是架构设计要解决的问题&#xff0c;主要有如下几个&#xff1a;高性能、高可用、可扩展、低成本、安全、规模。复杂度的关键&#xff0c;就是新旧技术之间不是完全的替代关系&#xff0c;有交叉&#xff0c;有各自的特点&#xff0c;所以才需要具体…

tomcat8.5在windows下运行出现日志中文乱码

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; h…

八月份的护网行动如何参加?

护网行动背景 什么是“护网行动”&#xff1f; 指挥机构∶由公安机关统一组织的"网络安全实战攻防演习"。 护网分为两级演习∶公安部对总部&#xff0c;省厅对省级公司。 什么是“实战攻防演习” 每支队伍3-5 人组成&#xff0c;明确目标系统&#xff0c;不限制攻…

SerDes介绍以及原语使用介绍(4)ISERDESE2原语仿真

文章目录 前言一、iserdese2_module模块二、oserdese2_module模块三、顶层模块四、仿真结果分析 前言 上文详细介绍了ISERDESE2原语的使用&#xff0c;本文根据仿真对ISERDESE2原语的使用进一步加深印象。在仿真时&#xff0c;与OSERDESE进行回环。 一、iserdese2_module模块…

【C语言】指针剖析(2)

©作者:末央&#xff06; ©系列:C语言初阶(适合小白入门) ©说明:以凡人之笔墨&#xff0c;书写未来之大梦 目录 一、数组名1.概念2.sizeof和&里面的数组名sizeof& 二、使用指针访问数组三、一维数组传参本质四、指针数组1.概念实例&#xff08;模拟二维数…

C语言中常用的运算符、表达式和语句

C语言是一种通用的、高级的编程语言&#xff0c;其历史可以追溯到20世纪60年代末至70年代初。C语言最初是由丹尼斯里奇&#xff08;Dennis Ritchie&#xff09;在贝尔实验室为开发UNIX操作系统而设计的。它继承了许多B语言的特性&#xff0c;而B语言则是由迷糊老师&#xff08;…

C#基于SkiaSharp实现印章管理(3)

本系列第一篇文章中创建的基本框架限定了印章形状为矩形&#xff0c;但常用的印章有方形、圆形等多种形状&#xff0c;本文调整程序以支持定义并显示矩形、圆角矩形、圆形、椭圆等4种形式的印章背景形状。   定义印章背景形状枚举类型&#xff0c;矩形、圆形、椭圆相关的尺寸…

springboot宠物医院管理系统-计算机毕业设计源码07221

目 录 1 绪论 1.1 选题背景和意义 1.2国内外研究现状 1.3论文结构与章节安排 2 宠物医院管理系统系统分析 2.1 可行性分析 2.1.1技术可行性分析 2.1.2 操作可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分…

docker配置国内镜像加速器

1、搜索阿里云 2、搜索容器镜像服务 点击管理控制台 配置镜像加速器

uniapp部署服务器,uniapp打包H5部署服务器,uniapp将config.js抽离

目录 步骤一.在static文件夹下新建config.js文件 config.js文件说明 在config.js中放入使用的请求的接口地址,资源路径等 congfig.js中的变量在页面中如何使用 步骤二.manifest.json配置 1.在项目根目录(与app.vue同级)创建template.h5.html文件 2.在manifest.json配置刚刚创…

手机屏幕贴合项目(ni视觉如何找矩形的角坐标)

首先&#xff0c;我们存储了cg和dito感兴趣八个角图像的模板&#xff0c;用来匹配位置。 cover指的是cg的四个角模板&#xff0c;lcm是dito四个角匹配模板。 其次&#xff0c;我们采集的8副图像&#xff08;m_DlgCCDViewArr[2][4]&#xff09;中一定包含匹配模板的特征。 好&…

土体中应力的计算

土中的应力的计算 非水面以下土体中应力的计算&#xff1a;水面以下的土中的应力计算 参考视频&#xff1a; https://www.bilibili.com/video/BV1Rh411J72h/?spm_id_from333.788&vd_source02b2bad477a153eaeb9c48cbbedaf8df 非水面以下土体中应力的计算&#xff1a; 按成…

C++自定义智能指针

template <class T> class counted_ptr;// 智能指针引用计数类 template <class T> class Ref_Ptr {friend class counted_ptr<T>; private:T* m_pTtr; // 实际的指针size_t counted_ptr; // 引用计数Ref_Ptr(T* p);virtual ~Ref_Ptr(); };template <clas…

Golang | Leetcode Golang题解之第200题岛屿数量

题目&#xff1a; 题解&#xff1a; func numIslands(grid [][]byte) int {res : 0for i : 0; i < len(grid); i {for j : 0; j < len(grid[i]); j {if grid[i][j] 1 {resdfs(grid, i, j)}}}return res }func dfs(grid [][]byte, r, c int) {h, w : len(grid), len(gri…

标准版小程序订单中心path审核不通过处理教程

首先看自己小程序是不是已经审核通过并上线状态才在站内信里面提醒的&#xff1f; 如果没有提交过审核&#xff0c;请在提交的时候填写。path地址为&#xff1a;pages/goods/order_list/index 如果是已经上线的小程序&#xff0c;当时没要求填这个&#xff0c;但新的政策要求填…

如何通过Profile快速定位Doris查询瓶颈

1 如何获取profile 参考文档&#xff1a;https://doris.apache.org/zh-CN/docs/query/query-analysis/get-profile 我们时常遇到对应 SQL 执行时间不及预期的情况&#xff0c;为了优化 SQL 达到预期查询时延&#xff0c;通过 Profile 我们能够看出可以做哪些优化。现在说明在…

为何同一PDF文档用不同软件打印效果不同?

通过扫描仪生成的同一PDF文档&#xff0c;同样的设置&#xff0c;为什么别的电脑打出来是白底我的打出来有灰色格子背景&#xff1f;这种情况通常是由于PDF阅读软件的不同造成的差异。 ### 可能的原因和解决方法&#xff1a; 1. **PDF阅读软件的不同**&#xff1a; - **解决方…

小型光纤抗干扰无人机技术详解

一、光纤通信技术应用 光纤通信技术是现代通信技术的重要组成部分&#xff0c;其在小型无人机中的应用为无人机的数据传输带来了革命性的改变。光纤通信具有高速率、大带宽、低损耗和抗电磁干扰等优点&#xff0c;使得无人机在执行任务时能够实时传输高清图像、视频和大量数据…