QT天气预报

QT-天气预报

  •  1.界面设计
  •  2.开发
    •   2.1 重写鼠标右键退出功能
    •   2.2 重写鼠标左键移动窗口
    •   2.3 QtHttp编程获取天气原始数据
      •     2.3.1 发送HTTP请求
      •     2.3.2 读取数据
      •     2.3.3 处理网络失败请求
    •   2.4 JSON数据
      •     2.4.1 QT生成JSON数据
      •     2.4.2 QT解析JSON数据
    •   2.5 获取当前城市天气数据
    •   2.6 获取不同城市数据信息
    •   2.7 QMap
      •     2.7.1 将CityName与CityCode产生联系
      •     2.7.1 将天气图标与天气类型产生联系
    •   2.8 获得最近七天的数据
    •   2.9 事件过滤器在子控件上画线
    •   2.10 LineEdit的returnPressed()
  •  3.最终效果

 1.界面设计

在这里插入图片描述

 2.开发

  2.1 重写鼠标右键退出功能

	重写鼠标右键点击事件 + QMenu:
	/*
 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){
       menuQuit->exec(QCursor::pos());  //光标点击的当前位置执行
    }
    QWidget::mousePressEvent(event);
}

void Widget::rightMouseClicked()
{
    menuQuit = new QMenu(this);
    QAction *closeAct = new QAction(QIcon(":/res/close.png"), tr("退出"), this);
    menuQuit->addAction(closeAct);

    //[signal] void QMenu::triggered(QAction *action)
    connect(menuQuit,&QMenu::triggered,this,[=](){
        this->close();
    });
}

  2.2 重写鼠标左键移动窗口

	如下图所示:
	鼠标右键点击窗口有鼠标的点击坐标:event->globalPos();
	窗口有窗口的坐标:this->Pos();
	在鼠标点击窗口移动的时候,鼠标的坐标A与窗口坐标B相对的偏移量moffset不会变
	QPoint moffset = event->globalPos() - this->Pos();
	窗口移动到图中黑框的位置时,鼠标的坐标处在一个新的A点上,
	但是A点相较于新窗口点C的偏移量与原来的A点相较于B点的偏移量没有改变
	因此,在已知新坐标点A与固定偏移量的情况下C点可求
	新窗口的坐标点位为:event->globalPos() - moffset 
	然后再对鼠标移动事件进行重写

在这里插入图片描述

void Widget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::RightButton){
       menuQuit->exec(QCursor::pos());  //光标点击的当前位置执行
    }

    //鼠标当前位置:event->globalPos()
    //窗口当前位置:this->pos()
    //窗口新位置: event->globalPos()-moffset
    if(event->button() == Qt::LeftButton){
        qDebug() << event->globalPos()<< this->pos();
        moffset = event->globalPos() - this->pos();
    }

    QWidget::mousePressEvent(event);
}

//重写鼠标左键移动事件
void Widget::mouseMoveEvent(QMouseEvent *event)
{
    this->move(event->globalPos()-moffset);
    QWidget::mouseMoveEvent(event);
}

  2.3 QtHttp编程获取天气原始数据

    2.3.1 发送HTTP请求

类:
	QNetworkAccessManager
	QNetworkRequest
    
    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    QNetworkRequest res(QUrl("http://t.weather.itboy.net/api/weather/city/101010100"));

    2.3.2 读取数据

	QNetworkReply *reply = manager->get(res);
	//网络请求后进行数据读取
    connect(reply,SIGNAL(finished()),this,SLOT(readHttpReply()));

	void Widget::readHttpReply()
	{
    	QByteArray data = reply->readAll();
    	qDebug() << QString::fromUtf8(data);
	}

    2.3.3 处理网络失败请求

	http请求返回200请求成功
void Widget::readHttpReply()
{
    int resCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() <<resCode;
    if(reply->error() == QNetworkReply::NoError && resCode == 200){
        //大多数返回utf-8
        QByteArray data = reply->readAll();
        qDebug() << QString::fromUtf8(data);
    }else{
        QMessageBox msgBox;
        msgBox.setWindowTitle("错误");
        msgBox.setText("网络请求失败");
        msgBox.setStandardButtons(QMessageBox::Ok);
        qDebug() << reply->errorString();
        msgBox.exec();
    }
}

  2.4 JSON数据

    2.4.1 QT生成JSON数据

	键值对-- 对象[] = "值";
类:
	QJsonDocument
	QJsonObject
	QJsonArray
方法:
	1. 创建JSON对象:使用 QJsonObject 来构建JSON对象,并使用键值对填充数据。
	2. 创建JSON数组:使用 QJsonArray 来创建一个数组,并添加元素。
	3. 组合JSON结构:将JSON数组添加到JSON对象中。
	4. 生成JSON文档:通过 QJsonDocument 来处理JSON数据,可以选择格式化(缩进)或压缩形式。
	5. 保存到文件:创建 QFile 对象,打开文件,写入JSON数据,并关闭文件。
    QJsonObject rootObj;
    //添加键值对
    rootObj["cityid"] = "1010100";
    rootObj["date"] = "2024-4-6";
    rootObj["weather"] = "雨夹雪";
    rootObj["tmp"] = 3;

    //添加数组
    QJsonArray jsonArr;
    jsonArr.append("data1");
    jsonArr.append("data2");
    jsonArr.append("data3");
    jsonArr.append(100);
    rootObj["testArr"] = jsonArr;

    //添加对象
    QJsonObject jsonObject;
    jsonObject = rootObj;
    rootObj["jsonObject"] = jsonObject;

    //数组中添加对象
    QJsonArray jsObArr;
    jsObArr.append(jsonObject);
    jsObArr.append(jsonObject);
    rootObj["jsObArr"] = jsObArr;

    //生成JSON文件
    QJsonDocument jsonDoc(rootObj);
    //转成数组
    QByteArray jsonArray = jsonDoc.toJson();
    //写入文件
    QFile file("C:/Users/qzh/Desktop/test.json");
    file.open(QIODevice::WriteOnly);
    file.write(jsonArray);
    file.close();

在这里插入图片描述

    2.4.2 QT解析JSON数据

	1.读取JSON数据
	2.生成JSON文件
	3.转成JSON对象
	QFile file("C:/Users/qzh/Desktop/test.json");
    file.open(QIODevice::ReadOnly);
    QByteArray rawData = file.readAll();
    file.close();

    QJsonDocument jsonDoc = QJsonDocument::fromJson(rawData);
    if(!jsonDoc.isNull() && jsonDoc.isObject()){    //不是json对象转成json对象
        QJsonObject jsonRoot = jsonDoc.object();
        QString strW = jsonRoot["weather"].toString();
        QString strCityId = jsonRoot["cityid"].toString();
        qDebug() << strW;
        qDebug() << strCityId;

        //JSON数组处理
        if(jsonRoot.contains("testArr") && jsonRoot["testArr"].isArray()){
            //1.先转成数组
            QJsonArray testArray = jsonRoot["testArr"].toArray();
            for(QJsonValue val : testArray){
                QJsonValue::Type t = val.type();
                switch(t){
                case QJsonValue::Double:
                    qDebug() << QString::number(val.toDouble());
                    break;
                case QJsonValue::String:
                    qDebug() << val.toString();
                    break;
                case QJsonValue::Object:
                    break;

                }
            }

        }
        //处理json对象
        if(jsonRoot.contains("jsonObject") && jsonRoot["jsonObject"].isObject()){
            //转成Json对象
            QJsonObject jsonObject = jsonRoot["jsonObject"].toObject();
            qDebug() << "jsonObject"<<jsonObject["cityid"].toString();
        }

        //处理JSON数组中的对象
        if(jsonRoot.contains("testArr") && jsonRoot["testArr"].isArray()){
            QJsonArray jsObArr = jsonRoot["jsObArr"].toArray();
            for(QJsonValue val : jsObArr){
                if(val.isObject()){
                    QJsonObject obj = val.toObject();
                    qDebug() << obj["weather"].toString();
                    qDebug() << obj["cityid"].toString();
                }
            }
        }
    }

  2.5 获取当前城市天气数据

全局变量
    QNetworkReply *reply;
    QString strUrl;
    QNetworkAccessManager *manager;
	1.创建一个QNetworkAccessManager对象manager
	manager = new QNetworkAccessManager(this);
	2.发送请求
	strUrl = "http://v1.yiketianqi.com/api?unescape=1&version=v61&appid=87767798&appsecret=7Ujk853M";
    QUrl urlTianQi(strUrl);
    QNetworkRequest res(urlTianQi);
    manager->get(res);
    3.QNetworkReply获得相应,并将相关数据存储在replay中
    4.绑定信号与槽,manager响应完成后触发数据处理
    void Widget::readHttpReply(QNetworkReply *reply)
{
    int resCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    if(reply->error() == QNetworkReply::NoError && resCode == 200){
        //大多数返回utf-8
        QByteArray data = reply->readAll();
        parseWeatherJsonData(data);//解析数据并刷新控件
        qDebug() << QString::fromUtf8(data);
    }else{
        QMessageBox msgBox;
        msgBox.setWindowTitle("错误");
        msgBox.setText("网络请求失败");
        msgBox.setStandardButtons(QMessageBox::Ok);
        qDebug() << reply->errorString();
        msgBox.exec();
    }
}

//解析数据并刷新控件
void Widget::parseWeatherJsonData(QByteArray rawData)
{
    QJsonDocument jsonObj = QJsonDocument::fromJson(rawData);
    if(!jsonObj.isNull() && jsonObj.isObject()){
        QJsonObject objRoot = jsonObj.object();
        //解析日期
        QString date = objRoot["date"].toString();
        QString week = objRoot["week"].toString();
        ui->labelCurrentDate->setText(date+"  "+ week);
        //解析城市名称
        QString cityName = objRoot["city"].toString();
        ui->labelCity->setText(cityName);
        //解析当前温度
        QString currentTmp = objRoot["tem"].toString();
        ui->labelWendu->setText(currentTmp+"℃");
        ui->labelWeatherRange->setText(objRoot["tem2"].toString()+"~"+objRoot["tem1"].toString());
        //解析天气类型
        ui->labelWeatherType->setText(objRoot["wea"].toString());

        //感冒指数
        ui->labelGanmao->setText(objRoot["air_tips"].toString());
        //风向
        ui->labelFXtype->setText(objRoot["win"].toString());
        //风力
        ui->labelFXtype_2->setText(objRoot["win_speed"].toString());
        //PM2.5
        ui->labelPMData->setText(objRoot["air_pm25"].toString());
        //湿度
        ui->labelShiduData->setText(objRoot["humidity"].toString());
        //空气质量
        ui->labelAirData->setText(objRoot["air_level"].toString());
    }
}

  2.6 获取不同城市数据信息

	1.当搜查按钮点击后触发信号与槽
	2.读取当前ui->lineEdit控件的内容
	3.解析json格式的城市编码并与当前控件内容进行匹配
	4.刷新控件-
	由于数据的读取绑定的信号是QNetworkAccessManager::finished,
	所当在点击按钮后重对新的url发送请求完成后会触发槽函数进行数据解析
	和刷新相关控件操作
	void Widget::on_pushButton_clicked()
{
    QString cityNameFromUser = ui->lineEditCity->text();
    QString cityCode = getCityCodeFromJson(cityNameFromUser);
    if(cityCode != NULL){
        strUrl += "&cityid=" + cityCode;                 //拼接url
        manager->get(QNetworkRequest(QUrl(strUrl)));    //发送请求
    }else{
        QMessageBox msgBox;
        msgBox.setWindowTitle("错误");
        msgBox.setText("请输入正确城市名");
        msgBox.setStandardButtons(QMessageBox::Ok);
        qDebug() << reply->errorString();
        msgBox.exec();
    }
}

QString getCityCodeFromJson(QString name)
{
    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 val : citys){
            if(val.isObject()){
                QString cityName = val["city_name"].toString();
                if(cityName == name){
                    return val["city_code"].toString();
                }
            }
        }
        return "";
    }
}

  2.7 QMap

    2.7.1 将CityName与CityCode产生联系

	由于每次打开之前都需要打开文件,会很麻烦,所以引入Map容器
	在打开的时候检查Map容器是否为空,为空则打开文件将文件内容存储在Map容器中,后续只需要检查Map容器是否为空即可

QMap<QString,int> myMap; //创建一个存储QString类型的键和int型的值的map容器
QMap<QString,QString> cityMap;  //创建存储一个QString类型的键和QString类型的值的map容器

QString CityCodeUtils::getCityCodeFromName(QString cityName)
{
    if(cityMap.isEmpty()){
        initCityMap();
    }
     QMap<QString, QString>::iterator it =   cityMap.find(cityName);  //查找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(); //获得cityCode
}

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 val : citys){
            if(val.isObject()){
                QString cityName = val["city_name"].toString();
                QString cityCode = val["city_code"].toString();
                cityMap.insert(cityName,cityCode);  //将cityName和cityCode以键值对的方式插入到map容器中
            }
        }
    }
}

    2.7.1 将天气图标与天气类型产生联系

void Widget::initWeatherIcon()
{
    //根据keys,设置icon的路径
    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->labelWeatherIcon->setPixmap(mTypeMap[objRoot["wea"].toString()]);

  2.8 获得最近七天的数据

	strUrl = "http://v1.yiketianqi.com/api?unescape=1&version=v91&appid=87767798&appsecret=7Ujk853M&ext=";
	1.定义一个新的类Day用于存储一天的全部信息
	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;
};

	2.解析新的url获取的json数据-并将数据存储在数组中
	Day days[7];
	
	void Widget::parseWeatherJsonDataNew(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();
                //qDebug() << obj["date"].toString() << obj["wea"].toString();
                days[i].mDate = obj["date"].toString();
                days[i].mWeek = obj["week"].toString();
                days[i].mWeathType = 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].mTips = obj["air_tips"].toString();
                days[i].mHu = obj["humidity"].toString();

            }
        }
    }
    updateUI();
}

	3.设置QList泛型并初始化
	QList<QLabel *> mDateList;
    QList<QLabel *> mWeekList;
    QList<QLabel *> mIconList;
    QList<QLabel *> mWeaTypeList;
    QList<QLabel *> mAirqList;
    QList<QLabel *> mFxList;
    QList<QLabel *> mFlList;
    void Widget::initDaysElement()
{
    mWeekList << ui->labelday0 << ui->labelday1
              << ui->labelday2 << ui->labelday3
              << ui->labelday4 << ui->labelday5;
    mDateList << ui->labelDate0 << ui->labelDate1
              << ui->labelDate2 << ui->labelDate3
              << ui->labelDate4 << ui->labelDate5;
    mIconList << ui->labelWeatherIcon0 << ui->labelWeatherIcon1
              << ui->labelWeatherIcon2 << ui->labelWeatherIcon3
              << ui->labelWeatherIcon4 << ui->labelWeatherIcon5;
    mWeaTypeList << ui->lbweatherType0 << ui->lbweatherType1
                 << ui->lbweatherType2 << ui->lbweatherType3
                 << ui->lbweatherType4 << ui->lbweatherType5;
    mAirqList << ui->labelq0 << ui->labelq1
              << ui->labelq2 << ui->labelq3
              << ui->labelq4 << ui->labelq5;
    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;
}
	4.通过泛型设置对应控件
	void Widget::updateUI()
{
    QPixmap pixMap;
    //解析日期
    ui->labelCurrentDate->setText(days[0].mDate+"  "+days[0].mWeek);
    //解析城市名称
    ui->labelCity->setText(days[0].mCity+"市");
    //解析当前温度
    ui->labelWendu->setText(days[0].mTemp+"℃");
    ui->labelWeatherRange->setText(days[0].mTempLow+"~"
            +days[0].mTempHigh);
    //解析天气类型
    ui->labelWeatherType->setText(days[0].mWeathType);
    ui->labelWeatherIcon->setPixmap(mTypeMap[days[0].mWeathType]);
    //感冒指数
    ui->labelGanmao->setText(days[0].mTips);
    //风向
    ui->labelFXtype->setText(days[0].mFx);
    //风力
    ui->labelFXtype_2->setText(days[0].mFl);
    //PM2.5
    ui->labelPMData->setText(days[0].mPm25);
    //湿度
    ui->labelShiduData->setText(days[0].mHu);
    //空气质量
    ui->labelAirData->setText(days[0].mAirq);


    for(int i = 0; i < 6; i++){
        mWeekList[0]->setText("今天");
        mWeekList[1]->setText("明天");
        mWeekList[2]->setText("后天");
        mWeekList[i]->setText(days[i].mWeek);
        QStringList dayList = days[i].mDate.split("-"); //2024-4-7 通过-分割成三部分 0:2024, 1:4, 2:7
        mDateList[i]->setText(dayList[1] + "-" +dayList[2]);

        //缩放图片大小与label大小能匹配
        int index = days[i].mWeathType.indexOf("转");    //找不到 “转” 返回-1
        if(index != -1){
            pixMap = mTypeMap[days[i].mWeathType.left(index)];  //找到了字符转的位置,将左边取出
        }else{
            pixMap = mTypeMap[days[i].mWeathType];
        }
        pixMap = pixMap.scaled(mIconList[i]->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
        mIconList[i]->setMaximumHeight(50);
        mIconList[i]->setMinimumWidth(ui->widget0402->width()/6.5);
        mIconList[i]->setPixmap(pixMap);
        mWeaTypeList[i]->setText(days[i].mWeathType);

        QString airQ = days[i].mAirq;

        mAirqList[i]->setText(days[i].mAirq);
        if( airQ == "优"){
            mAirqList[i]->setStyleSheet("background-color:rgb(150,213,32);border-radius: 10px;");
        }else if(airQ == "良"){
            mAirqList[i]->setStyleSheet("background-color:rgb(241,224,103);border-radius: 10px;");
        }else if(airQ == "轻度"){
            mAirqList[i]->setStyleSheet("background-color:rgb(255,199,199);border-radius: 10px;");
        }else if(airQ == "中度"){
            mAirqList[i]->setStyleSheet("background-color:rgb(255,17,17);border-radius: 10px;");
        }else if(airQ == "重度"){
            mAirqList[i]->setStyleSheet("background-color:rgb(153,0,0);border-radius: 10px;");
        }


        mFlList[i]->setText(days[i].mFl);
        index = days[i].mFl.indexOf("转");
        if(index != -1){
            mFlList[i]->setText(days[i].mFl.left(index));
        }else{
            mFlList[i]->setText(days[i].mFl);
        }
        mFxList[i]->setText(days[i].mFx);
    }
}

  2.9 事件过滤器在子控件上画线

	若直接通过重写paintEvent事件,则会被layout遮挡
	因此通过事件过滤对事件过滤在子控件上画线
    ui->widget0404->installEventFilter(this);
    ui->widget0405->installEventFilter(this);

bool Widget::eventFilter(QObject *watched, QEvent *event)
{
    if(watched == ui->widget0404 && event->type() == QEvent::Paint){
        drawTempLineHight();
        return true; //事件被处理返回true
    }
    if(watched == ui->widget0405 && event->type() == QEvent::Paint){
        drawTempLineLow();
        return true; //事件被处理返回true
    }
    return QWidget::eventFilter(watched,event);
}

void Widget::drawTempLineHight()
{
    QPainter painter(ui->widget0404);   //在0404子控件上画画
    painter.setRenderHint(QPainter::Antialiasing,true);
    painter.setBrush(Qt::yellow);
    painter.setPen(Qt::yellow);

    //算出平均温度,以平均值为中线进行偏移
    int ave;
    int sum = 0;
    int offset;
    int middle = ui->widget0404->height()/2;
    for(int i=0 ; i < 6 ;i++){
        sum += days[i].mTempHigh.toInt();
        qDebug() << days[i].mTempHigh;
    }
    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 = days[i].mTempHigh.toInt() - ave;
        points[i].setY(middle - offset*3);

        painter.drawEllipse(QPoint(points[i]),3,3); //画点
        painter.drawText(points[i].x()-15,points[i].y()-15,days[i].mTempHigh + "℃");
    }
    painter.setBrush(Qt::NoBrush);
    for(int i=0;i<5;i++){
        painter.drawLine(points[i],points[i+1]);    //画线

    }
}

void Widget::drawTempLineLow()
{
    QPainter painter(ui->widget0405);   //在0404子控件上画画
    painter.setRenderHint(QPainter::Antialiasing,true);
    painter.setBrush(Qt::blue);
    painter.setPen(Qt::blue);

    //算出平均温度,以平均值为中线进行偏移
    int ave;
    int sum = 0;
    int offset;
    int middle = ui->widget0405->height()/2;
    for(int i=0 ; i < 6 ;i++){
        sum += days[i].mTempLow.toInt();
        qDebug() << days[i].mTempLow;
    }
    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 = days[i].mTempLow.toInt() - ave;
        points[i].setY(middle - offset*3);

        painter.drawEllipse(QPoint(points[i]),3,3); //画点
        painter.drawText(points[i].x()-15,points[i].y()-15,days[i].mTempLow + "℃");
    }
    for(int i=0;i<5;i++){
        painter.drawLine(points[i],points[i+1]);    //画线
    }
}

  2.10 LineEdit的returnPressed()

//相当于添加enter快捷键enter按下后进行搜索
void Widget::on_lineEditCity_returnPressed()
{
    on_pushButton_clicked();
}

 3.最终效果

在这里插入图片描述

链接:https://pan.baidu.com/s/1m9eJfvXX7RXK3_ksb7U4hA 
提取码:sw2n 
--来自百度网盘超级会员V5的分享

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

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

相关文章

[lesson22]对象的销毁

对象的销毁 对象的销毁 生活中的对象都是被初始化后才上市的 生活中的对象被销毁前会做一些清理工作 一般而言&#xff0c;需要销毁的对象都应该做清理 解决方案 为每个类都提供一个public的free函数对象不在需要时立即调用free函数进行清理 存在的问题 free只是一个普通…

wife_wife-攻防世界

题目 注册发现可以注册管理员,但是好像有条件 抓包试试 没思路了 看看其他师傅的wp&#xff0c;用到 js 原型链污染攻击 Nodejs原型链污染攻击基础知识 | Savants Blog (lxscloud.top) 网站后端是Node.js搭建的 原型链污染 简单来讲&#xff0c;通过 newUser.__proto__ …

使用 HBuilderX自动上传Uniapp 微信小程序代码

HBuilderX内置相关环境&#xff0c;开箱即用&#xff0c;无需配置nodejs。本文只介绍发布微信小程序的步骤。 1.下载和安装 HBuilderX hbuilder首页&#xff1a;https://www.dcloud.io/hbuilderx.html 下载hbuilder编辑器,选择对应的系统,Windows和mac正式版即可,下载后免安…

mysql8.0高可用集群架构实战

MySQL :: MySQL Shell 8.0 :: 7 MySQL InnoDB Cluster 基本概述 InnoDB Cluster是MySQL官方实现高可用读写分离的架构方案,其中包含以下组件 MySQL Group Replication,简称MGR,是MySQL的主从同步高可用方案,包括数据同步及角色选举Mysql Shell 是InnoDB Cluster的管理工具,用…

基于SpringBoot+Vue的健身器材用品网站(源码+文档+部署+讲解)

一.系统概述 随着我国经济的高速发展与人们生活水平的日益提高&#xff0c;人们对生活质量的追求也多种多样。尤其在人们生活节奏不断加快的当下&#xff0c;人们更趋向于足不出户解决各种问题&#xff0c;必录德健身器材用品网展现了其蓬勃生命力和广阔的前景。与此同时&#…

AugmentedReality之路-平面检测(5)

本文介绍通过AR检测水平平面和垂直平面&#xff0c;并将检测到的平面转化为Mesh 1、在首页添加功能入口 在首页添加一个按钮&#xff0c;命名为Start World Track 2、自定义ExecStartAREvent 创建ARSessionConfig并取名为ARSessionConfig_World 自定义ExecStartAREvent&…

2024年你应该防范的11个WordPress安全漏洞问题:由资深程序员撰写

微软创始人比尔盖茨曾说过&#xff0c;“安全对每个人都有同样的影响。在网站安全方面&#xff0c;没有特定的主题、目标或受众。” 但WordPress是互联网上最受欢迎的CMS。它也是被黑客攻击次数最多的。针对WordPress的攻击次数超过了每秒2800次。网络攻击会浪费时间、精力和金…

camera驱动学习总结记录

https://www.yuque.com/u2132176/yfiyal/ch1zsrgzevcwf1rw 视频教程里面对应的gc2053c驱动源码注解&#xff1a; gc2053.c(60 KB) 对应的驱动文档&#xff1a; Rockchip_Driver_Guide_VI_CN_v1.1.1(2).pdf(2.3 MB) 视频里面对应的mipi协议文档汇总&#xff1a; MIPI标准文档大…

MoCo v1(CVPR 2020)原理与代码解读

paper&#xff1a;Momentum Contrast for Unsupervised Visual Representation Learning official implementation&#xff1a;https://github.com/facebookresearch/moco 背景 最近的一些研究提出使用对比损失相关的方法进行无监督视觉表征学习并取得了不错的结果。尽管是受…

springcloud第4季 springcloud-alibaba之nacos篇

一 nacos 1.1 nacos作用介绍 nacos是一个分布式的配置中心和注册发现中心。 nacos是 dynamic naming configuration service nacosconfigbus 实现动态刷新&#xff1b;nacosconsul 1.2 各个注册中心对比 注册中心CAP模型控制台管理社区活跃度EureakaAp支持低zkcp不支持中…

leetcode73 矩阵置零

题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用原地算法。 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 输入&#xff1a;matrix [[0,1,2,0],[3,4…

使用 Python 标记具有相同名称的条目

如果大家想在 Python 中标记具有相同名称的条目&#xff0c;可以使用字典&#xff08;Dictionary&#xff09;或集合&#xff08;Set&#xff09;来实现。这取决于你们希望如何存储和使用这些条目。下面我将提供两种常见的方法来实现这个目标。 1、问题背景 在处理数据时&…

PE文件的分析和构造超详细过程

本文详细讲述如何从0构造一个PE文件&#xff0c;运行该文件会弹出一个HelloPE的窗口 目录 预备知识 1. 构造DOS头IMAGE_DOS_HEADER 1.1 构造DOS_MZ头 1.2 构造DOS_STUB 2、构造PE头IMAGE_NT_HEADERS 248字节 2.1 signature 2.2 IMAGE_FILE_HEADER 2.3 IMAGE_OPTI…

Python爬虫:蝉妈妈返回参数data解密

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ 🐴作者:秋无之地 🐴简介:CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作,主要擅长领域有:爬虫、后端、大数据开发、数据分析等。 🐴欢迎小伙伴们点赞👍🏻、收藏⭐️、…

Spring Boot | Spring Boot 整合 “Servlet三大组件“ ( Servlet / Filter / Listene )

目录: Spring Boot 整合 "Servlet三大组件" &#xff1a;1. 使用 "组件注册" 的方式 "整合Servlet三大组件" ( 实际操作为 : 创建自定义的"三大组件"对象 结合刚创建"的自定义组件对象"来 将 XxxRegistrationBean对象 通过…

sparkSql join 关联机制

&#x1f490;&#x1f490;扫码关注公众号&#xff0c;回复 spark 关键字下载geekbang 原价 90 元 零基础入门 Spark 学习资料&#x1f490;&#x1f490; join 实现机制 Join 有 3 种实现机制&#xff0c;分别是 NLJ&#xff08;Nested Loop Join&#xff09;、SMJ&#xf…

【VUE】使用Vue和CSS动画创建滚动列表

使用Vue和CSS动画创建滚动列表 在这篇文章中&#xff0c;我们将探讨如何使用Vue.js和CSS动画创建一个动态且视觉上吸引人的滚动列表。这个列表将自动滚动显示项目&#xff0c;类似于轮播图的方式&#xff0c;非常适合用于仪表盘、排行榜或任何需要在有限空间内展示项目列表的应…

【Altium Designer 20 笔记】隐藏PCB上的信号线(连接线)

使用网络类隐藏特定类型的信号线 如果你想要隐藏特定类型的信号线&#xff08;例如电源类&#xff09;&#xff0c;你可以首先创建一个网络类。使用快捷键DC调出对象类浏览器&#xff0c;在Net Classes中右击添加类&#xff0c;并重命名&#xff08;例如为“Power”&#xff0…

【Qt 学习笔记】QWidget的geometry属性及window frame的影响

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ QWidget的geometry属性 文章编号&#xff1a;Qt 学习笔记 / 16 文章目…

spring boot学习第十七篇:OAuth2概述及使用GitHub登录第三方网站

0. 导言 我们在浏览器上可以访问成百上千个网站&#xff0c;使用每个网站的服务一般都要先注册账号&#xff0c;那么我们为了更好地记忆&#xff0c;一般都会在多个网站使用相同的账号和密码进行注册。那么问题就来了&#xff0c;如果在你注册的网站中有某些个网站的系统设计不…