小伙用QT自定义实况天气控件,竟然具有29般变化

前言

陶渊明《四时》

春水满四泽,

夏云多奇峰。

秋月扬明晖,

冬岭秀寒松。

看了古人的诗,我不禁也诗兴大发,想要吟诗一首:昨日平安夜,今天圣诞节,立冬没多久,马上要降温。额,回归正题啊,最近我的一些微信群里都在发江苏这边马上要迎来寒潮,要降温十几度的消息,突然就让我对天气变得比较敏感。现在想要查一下天气情况真的是太轻松了,打开手机,即可以在各种app上查到,于是我便想我们的组件库中是不是也可以添加一个天气控件,想到便开始做,于是便有了下面的效果。

效果展示

当然上面为了展示效果,除第一张多云的是真实的实况天气,后面几张都是我改过的天气,目前基本支持所有天气类型,我自己又将其分为如下29类:

//天气类型简化为如下分类,实在不想翻译了,就用数字代替了enum WEATHER_TYPE{    WEATHER_1,      //晴    WEATHER_2,      //少云    WEATHER_3,      //晴间多云、多云    WEATHER_4,      //阴    WEATHER_5,      //有风、平静、微风、和风、清风    WEATHER_6,      //强风/劲风、疾风、大风、烈风    WEATHER_7,      //风暴、狂爆风、飓风、热带风暴    WEATHER_8,      //龙卷风    WEATHER_9,      //阵雨、强阵雨    WEATHER_10,     //雷阵雨、雷阵雨伴有冰雹、强雷阵雨    WEATHER_11,     //雨夹雪、雨雪天气、阵雨夹雪    WEATHER_12,     //小雨、小雨-中雨、毛毛雨/细雨    WEATHER_13,     //中雨、中雨-大雨    WEATHER_14,     //大雨、大雨-暴雨    WEATHER_15,     //暴雨、暴雨-大暴雨、大暴雨、特大暴雨、大暴雨-特大暴雨、极端降雨    WEATHER_16,     //阵雪    WEATHER_17,     //雪、小雪、小雪-中雪    WEATHER_18,     //中雪、中雪-大雪    WEATHER_19,     //大雪、大雪-暴雪    WEATHER_20,     //暴雪    WEATHER_21,     //雾、轻雾    WEATHER_22,     //浓雾、强浓雾、大雾、特强浓雾    WEATHER_23,     //霾、中度霾、重度霾、严重霾    WEATHER_24,     //冻雨    WEATHER_25,     //沙尘暴、强沙尘暴、    WEATHER_26,     //浮尘、扬沙    WEATHER_27,     //热    WEATHER_28,     //冷    WEATHER_29,     //未知};

为了使每一类的天气状况更加形象具体,为了使控件更加的大气美观,如上面的动图所示,每一类都有特定的动画,共计29种动画。当然大家如果不喜欢这些默认的动画的话,也可以换成任意自己喜欢的图片或动画,只需要替换相应的资源即可。

天气查询功能如何实现?

要想制作实时天气控件,首先要能获取到实时天气状况,那么怎么获取实时天气状况呢?我们自然而然的想到是从 上获取,从某个 页上获取。因此我们首先要先找到能够为我们提供天气查询功能的 页,我从 上找到很多提供类似功能的 站,最后还是感觉如下两个 站比较靠谱,主要还是免费:

  • 心知天气
  • 高德地图天气查询
  • 这两个 站都需要注册才能使用相关的api,其中高德地图每天查询上限是10万次,即使我们每秒查一次也才86400次,完全够用,请求格式如下,其中key的内容被我用xxxxxxxxx代替:

    https://restapi.amap.com/v3/weather/weatherInfo?key=xxxxxxxxxx&extensions=base&city=南京

    心知天气api好像是每秒限制20次,但是他免费的api返回的数据太少,只有天气类型和温度,其他一概没有,大家酌情自己选择。请求格式如下,其中key的内容被我用xxxxxxxxxx代替:

    https://api.seniverse.com/v3/weather/now.json?key=xxxxxxxxxx&language=zh-Hans&unit=c&location=南京

    有了能够获取数据的地方以后,那么该怎么通过Qt程序向 页请求数据呢?这时候就需要使用QtNetwork模块,其中主要用到如下三个类:

    #include <QtNetwork/QNetworkAccessManager>#include <QtNetwork/QNetworkRequest>#include <QtNetwork/QNetworkReply>

    这三个类的具体作用我不再详解,大家可以自行了解一下,或者下次我再单独的讲解,主要功能就是向 页发送请求并处理回复,具体使用方法如下:

    m_pManager = new QNetworkAccessManager(this);connect(m_pManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));// 查询天气void Weather::requestWeather(){                      QString strCity = m_strCityName; //城市名称    //char szQuest[256] = "https://api.seniverse.com/v3/weather/now.json?key=xxxxxxxxxx&language=zh-Hans&unit=c&location=";//心知天气api,每分钟20次好像,但是免费的接口返回的数据太少    char szQuest[256] = "https://restapi.amap.com/v3/weather/weatherInfo?key=xxxxxxxxxx&extensions=base&city="; //高德地图天气查询api,extensions=base表示实况天气,每日限值调用10万次    sprintf(szQuest, "%s%s", szQuest, strCity.toUtf8().data());    QNetworkRequest quest;    quest.setUrl(QUrl(szQuest));    quest.setHeader(QNetworkRequest::UserAgentHeader, "RT-Thread ART");    m_pManager->get(quest);}

    上面我们向 页发送请求以后, 页会给我返回相关的数据,数据一般都是JSON格式,以高德地图为例,其天气查询api返回的JSON数据格式如下:

    {  "status": "1",  "count": "1",  "info": "OK",  "infocode": "10000",  "lives": [    {      "province": "江苏",      "city": "南京市",      "adcode": "320100",      "weather": "多云",      "temperature": "6",      "winddirection": "东",      "windpower": "≤3",      "humidity": "52",      "reporttime": "2020-12-26 00:26:47"    }  ]}

    Qt也为我们提供了一些很方便的类来解析JSON数据:

    #include <QJsonDocument>#include <QJsonObject>#include <QJsonArray>

    JSON文档可以从它的基于文本的表示使用QJsonDocument::fromJson()转换为QJsonDocument,QJsonObject类用于封装JSON对象,QJsonArray类用于封装JSON数组。同样以解析上面JSON格式的天气数据为例,代码如下:

    void Weather::replyFinished(QNetworkReply *reply){    QString strReply = reply->readAll();    //qDebug() << strReply;    //解析JSON    QJsonParseError error;    //转换为JSON文档    QJsonDocument document = QJsonDocument::fromJson(strReply.toUtf8(), &error);    //未发生错误就解析    if (!document.isNull() && (error.error == QJsonParseError::NoError))    {        //心知天气JSON解析//        if (document.isObject())//        {//            //转换为JSON对象//            QJsonObject object = document.object();//            if (object.contains("results"))//            {//                QJsonArray resultsArray = object["results"].toArray();//                foreach (const QJsonValue & value, resultsArray)//                {//                    QJsonObject tempObj = value.toObject();//                    if (tempObj.contains("now"))//                    {//                        QJsonValue nowValue = tempObj.value("now");//                        QJsonObject nowItem = nowValue.toObject();//                        qDebug()<< ZH_CN("天气 = ") << nowItem["text"].toString();//                        qDebug()<< ZH_CN("温度 = ") << nowItem["temperature"].toString();//                    }//                    else//                        qDebug() << "error 2";//                    qDebug() << "last upadte = " << tempObj["last_update"].toString();//                }//            }//            else//                qDebug() << "error 1";//        }        //高德地图JSON解析        if (document.isObject())        {            //转换为JSON对象            QJsonObject object = document.object();            if (object.contains("lives"))            {                QJsonArray resultsArray = object["lives"].toArray();                foreach (const QJsonValue & value, resultsArray)                {                    QJsonObject tempObj = value.toObject();                    QString str;                    //qDebug()<< ZH_CN("天气 = ") << tempObj["weather"].toString();                    //qDebug()<< ZH_CN("温度 = ") << tempObj["temperature"].toString();                    m_strWeather = tempObj["weather"].toString();                    str = m_strWeather;                    str += "   ";                    str += tempObj["temperature"].toString();                    str += ZH_CN("°");                    m_pWeather_Label->setText(str);                    //qDebug()<< ZH_CN("风向 = ") << tempObj["winddirection"].toString();                    //qDebug()<< ZH_CN("风力 = ") << tempObj["windpower"].toString();                    str = tempObj["winddirection"].toString();                    str += ZH_CN("风");                    str += "   ";                    str += tempObj["windpower"].toString();                    str += ZH_CN("级");                    m_pWind_Label->setText(str);                    //qDebug()<< ZH_CN("湿度 = ") << tempObj["humidity"].toString();                    str = ZH_CN("湿度: ");                    str += tempObj["humidity"].toString();                    str += "%";                    m_pHumidity_Label->setText(str);                    //qDebug()<< ZH_CN("省份 = ") << tempObj["province"].toString();                    //qDebug()<< ZH_CN("城市 = ") << tempObj["city"].toString();                    //qDebug()<< ZH_CN("更新时间 = ") << tempObj["reporttime"].toString();                    str = tempObj["province"].toString();                    str += " ";                    str += tempObj["city"].toString();                    str += "   ";                    str += tempObj["reporttime"].toString();                    m_pTime_Label->setText(str);                    changeBackground(m_strWeather);                }            }            else                qDebug() << ZH_CN("天气数据解析失败!");        }    }    else        qDebug() << ZH_CN("请求天气数据是发生错误!");}

    页面及动态背景如何实现?

    基本控件创建及窗口布局实现:

    void Weather::initUI(){    m_pBackground_Label = new QLabel(this);//背景图片标签    m_pBackground_Label->setScaledContents(true);    m_pWeather_Label = new QLabel(this); //天气和温度标签    m_pWind_Label = new QLabel(this); //风向和风力标签    m_pHumidity_Label = new QLabel(this); //湿度标签    m_pTime_Label = new QLabel(this); //天气更新时间和地名标签    QFont font("Microsoft YaHei", 16, QFont::Bold);    QPalette palette;    palette.setColor(QPalette::WindowText, QColor(255, 255, 255));    setLabelStyle(m_pWeather_Label, font, palette);    setLabelStyle(m_pWind_Label, font, palette);    setLabelStyle(m_pHumidity_Label, font, palette);    setLabelStyle(m_pTime_Label, QFont("Microsoft YaHei", 12, QFont::Bold), palette);    QWidget *bottom_Widget = new QWidget(this);    QVBoxLayout *bottom_VLayout = new QVBoxLayout();    bottom_VLayout->setMargin(0);    bottom_VLayout->addWidget(m_pBackground_Label);    bottom_Widget->setLayout(bottom_VLayout);    QWidget *top_Widget = new QWidget(this);    QVBoxLayout *top_VLayout = new QVBoxLayout();    top_VLayout->addWidget(m_pWeather_Label);    top_VLayout->addWidget(m_pWind_Label);    top_VLayout->addWidget(m_pHumidity_Label);    top_VLayout->addWidget(m_pTime_Label);    top_Widget->setLayout(top_VLayout);    top_Widget->setStyleSheet("QWidget { background: transparent; }");    QGridLayout *main_GLayout = new QGridLayout();    main_GLayout->setMargin(0);    main_GLayout->addWidget(bottom_Widget, 0, 0, 1, 1);    main_GLayout->addWidget(top_Widget, 0, 0, 1, 1);    this->setLayout(main_GLayout);    this->setStyleSheet("QWidget { background-color: QColor(56, 56, 56); }");}

    文字标签样式及文字阴影效果设置,文字阴影效果主要为了增加文字和背景的对比度,使文字更加清晰,易于分辨。

    //设置标签样式void Weather::setLabelStyle(QLabel *label, QFont font, QPalette palette){    label->setFont(font);    label->setPalette(palette);    //添加文字阴影    QGraphicsDropShadowEffect* shadowEffect = new QGraphicsDropShadowEffect(label);    shadowEffect->setOffset(0, 0);    shadowEffect->setColor(Qt::black);    shadowEffect->setBlurRadius(10);    label->setGraphicsEffect(shadowEffect);}

    动态背景播放:

    m_pMovie = new QMovie(strGifPath);m_pBackground_Label->setMovie(m_pMovie);m_pMovie->setSpeed(100);//0.5倍m_pMovie->start();

    声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

    上一篇 2020年11月20日
    下一篇 2020年11月20日

    相关推荐