布局:
IP查询API:
因为天气预报对定位的要求不是很高,我们就可以使用IP地址归属地来查询当前位置,而且位置信息我们在查询天气的时候也要用到。这里给大家提供一个IP地址归属地数据查询的API,使用方法非常简单。
API:http://whois.pconline.com.cn/ipJson.jsp?ip
使用说明:http://whois.pconline.com.cn/
天气API:
获得本地的天气信息,可以调用跟天气相关的API。这里给大家提供一个中华万年历API。天气的API有很多,为什么给大家推荐使用这个API,第一,数据和中国天气网(www.weather.com.cn)一致,第二,返回的数据是json格式,方便解析,第三,查询方便,使用城市名称或者城市id即可查询。(如何网页打开是乱码,没事,可以在QT中修改编码问题)
通过城市名字获得天气数据,json数据
http://wthrcdn.etouch.cn/weather_mini?city=龙岩
通过城市id获得天气数据,json数据,需要城市ID
http://wthrcdn.etouch.cn/weather_mini?citykey=101010100
网络需要用到的类:首先工程加入:QT += network
QNetworkAccessManager //这个类是网络的大管家,所有和网络相关的接口都要围绕他
QNetworkRequest //发送网络请求,创建网络响应,例如GET - 从指定的服务器中获取数据,POST - 提交数据给指定的服务器处理
QTextCodec //转换编码的,因为Qt使用Unicode来存储、绘制和操作字符串
IP定位模块代码:
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
natManager = new QNetworkAccessManager(this);//natManager在头文件定义,并且一个项目实例化一个就可以了
QNetworkRequest ipRequest;
ipRequest.setUrl(QUrl("http://whois.pconline.com.cn/ipJson.jsp?ip"));
QNetworkReply *natReply = natManager->get(ipRequest);
connect(natReply,&QNetworkReply::finished,this,&Widget::slotGetRepalyFinished);//应答处理完成后,会发出finished信号
//connect(natReply,SIGNAL(finished()),this,SLOT(slotGetRepalyFinished()));高版本的QT这种写法不会自动提示信号,上面的写法可用
}
void Widget::slotGetRepalyFinished()
{
QNetworkReply *reply = (QNetworkReply *)sender();
QTextCodec *codec = QTextCodec::codecForName("gbk");
QString data = codec->toUnicode(reply->readAll());//上述操作完成后,data里存储的就是Unicode编码的字符串了
qDebug("%s",data.toStdString().data());
reply->deleteLater();//用完要删除
int cityLocation = data.indexOf("city")+7;
int cityCodeLocation = data.indexOf("cityCode")-4;
QString cityName = data.mid(cityLocation,cityCodeLocation-cityLocation);//mid是字符串切割函数
ui->location->setText(cityName);
}
打印天气模块代码(基于上面的代码):
void Widget::slotGetRepalyFinished()
{
QNetworkReply *reply = (QNetworkReply *)sender();
QTextCodec *codec = QTextCodec::codecForName("gbk");
QString data = codec->toUnicode(reply->readAll());//上述操作完成后,data里存储的就是Unicode编码的字符串了
qDebug("%s",data.toStdString().data());
reply->deleteLater();//删除reply,不能在 repyfinished 里直接 delete,要调用 deletelater;
int cityLocation = data.indexOf("city")+7;
int cityCodeLocation = data.indexOf("cityCode")-4;
QString cityName = data.mid(cityLocation,cityCodeLocation-cityLocation);//mid是字符串切割函数
ui->location->setText(cityName);
QNetworkRequest weatherRequest;
weatherRequest.setUrl(QUrl("http://wthrcdn.etouch.cn/weather_mini?city="+cityName));
QNetworkReply *weatherReply = natManager->get(weatherRequest);
connect(weatherReply,SIGNAL(finished()),this,SLOT(slotGetWeatherFinished()));
}
void Widget::slotGetWeatherFinished()
{
//可以用槽函数传入参数QNetworkReply *network代替reply,这样可以不用sender
QNetworkReply *reply = (QNetworkReply *)sender();//sender函数是返回发出信号的对象
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QString data = codec->toUnicode(reply->readAll());//上述操作完成后,data里存储的就是Unicode编码的字符串了
qDebug("%s",data.toStdString().data());//打印json类型的天气数据
reply->deleteLater();//删除reply
}
json数据解析需要的类:
QJsonParseError jsonEeeor; //解析JSON时的错误
QJsonObject jsonObject; //封装JSON对象
QJsonDocument jsonDocument; //封装JSON文本,The QJsonDocument class provides a way to read and write JSON documents
QJsonValue jsonData; //封装JSON值
QJsonArray iconPic; //封装JSON数组
json数据解析:
要点:json数据格式里,每一个大括号 { 或者中括号【 看成一个对象obj,多级obj,只要遵循一点,就是在每一级上,将Obj作为一个独立的Obj,使用一样的方式再向其所包含的下一级Obj获取信息。
{//一级大括号
"data":
{//二级大括号
"yesterday":
{//三级大括号
"date":"13日星期二", //string类型
"high":"高温 15℃","fx":"西风",
"low":"低温 4℃","fl":"<![CDATA[2级]]>",
"type":"多云"
},
"city":"保定",
"forecast": //数组类型
[//三级中括号
{
"date":"14日星期三",
"high":"高温 22℃",
"fengli":"<![CDATA[3级]]>",
"low":"低温 8℃",
"fengxiang":"西南风","type":"晴"
},
{
"date":"15日星期四",
"high":"高温 25℃",
"fengli":"<![CDATA[4级]]>",
"low":"低温 6℃",
"fengxiang":"西风"
"type":"多云",
},
{
"date":"16日星期五",
"high":"高温 20℃",
"fengli":"<![CDATA[4级]]>",
"low":"低温 6℃",
"fengxiang":"西北风","type":"多云"
},
{
"date":"17日星期六",
"high":"高温 19℃",
"fengli":"<![CDATA[3级]]>",
"low":"低温 6℃",
"fengxiang":"西北风",
"type":"晴"
},
{
"date":"18日星期天",
"high":"高温 25℃",
"fengli":"<![CDATA[2级]]>",
"low":"低温 10℃",
"fengxiang":"西南风",
"type":"晴"
}
],
"ganmao":"感冒易发期,外出请适当调整衣物,注意补充水分。",
"wendu":"19"//数值类型
},
"status":1000,
"desc":"OK"
}
解析天气json模块代码(基于上面的代码):
void Widget::slotGetWeatherFinished()
{
QNetworkReply *reply = (QNetworkReply *)sender();
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QString data = codec->toUnicode(reply->readAll());//上述操作完成后,data里存储的就是Unicode编码的字符串了
qDebug("%s",data.toStdString().data());
reply->deleteLater();
QJsonParseError jsonEeeor; //解析JSON时的错误
QJsonObject jsonObject; //封装JSON对象
QJsonDocument jsonDocument; //封装JSON文本
QString jsonData; //封装JSON值
QString iconPic; //封装JSON数组
jsonDocument = QJsonDocument::fromJson(data.toUtf8());//数据来源转换成jsonDocument
if(!jsonDocument.isNull() && jsonEeeor.error == QJsonParseError::NoError){
qDebug("转换成功!!!");//判断下是否转换成功
if(jsonDocument.isObject()){
jsonObject = jsonDocument.object();//把jsonDocument转换成具体的对象jsonObject,就是最外围即第一级的大括号
jsonObject = jsonObject.value("data").toObject();//第二级大括号“data”看成obj对象
//解析温度
jsonData = jsonObject.value("wendu").toString();//jsonData定义了QString类型了,所以toString,wendu里面没有下一级了
qDebug("%s",jsonData.toStdString().data());
ui->label_2->setText(jsonData);
//解析感冒
jsonData = jsonObject.value("ganmao").toString();
qDebug("%s",jsonData.toStdString().data());
ui->text->setText(jsonData);
//昨天
jsonObject = jsonObject.value("yesterday").toObject();
jsonData = jsonObject.value("type").toString();
ui->weather4->setText(jsonData);
//设置昨天的高低温
jsonData = jsonObject.value("low").toString().mid(3,2)+"/";
jsonData = jsonData+jsonObject.value("high").toString().mid(3,2);
ui->temperature->setText(jsonData);
}
}
}
图片的显示需要用到的类:
QStringList //QStringList类提供字符串列表
QPixmap //QPixmap类是一种屏幕外图像表示,可以用作绘制设备
显示图片的模块代码:
//如果12张照片都没有天气文字与之对应的,则可以完善图片,或者统一弄一张图片用来显示没有对应的,我统一设置为第13张图片
for (int i=0;i<12;++i) {
if(jsonData == iconList[i]){
iconPic = ":/"+QString::number(i+1)+".png";//QString::number是将数数字(整数、浮点数、有符号、无符号等)转换为QString类型
qDebug("%s",iconPic.toStdString().data());//打印图片所在路径
break;
}
if(i == 11){
qDebug("未找到对应的图片");
iconPic = ":/"+QString::number(13)+".png";//若找不到就显示第13张设置好的图片
}
}
QPixmap iconPix(iconPic);
iconPix = iconPix.scaled(ui->weater1->width(),ui->weater1->height(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
ui->weater1->clear();
ui->weater1->setPixmap(iconPix);//setPixmap加载10几K图片会放大图片,所以要用到QPixmap类
void Widget::iconPath() //头文件定义函数
{
//和图片的顺序一一对应
iconList << "中雨"
<< "冰雹"
<< "多云"
<< "大雨"
<< "大雪"
<< "小雨"
<< "晴"
<< "暴雨"
<< "沙尘"
<< "雷雨"
<< "小雨转多云"
<< "雾霾";
}
设置背景用到的类:
QPalette //Qpalete类包含每个小部件状态的颜色组
背景设置代码:
//第一种:
QPalette Pic;
Pic.setBrush(QPalette::Background,QBrush(QPixmap(":/beijing.png").scaled(this->size())));//路径看自己的
this->setPalette(Pic);
//第二种
this->setStyleSheet("MainWindow{border-image: url(:/beijing.png);}");
最后还需要每隔1小时更新一次数据即可,下面是全部代码:
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QNetworkAccessManager>
#include <QStringList>
#include <QTimer>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
QNetworkAccessManager *natManager;
QStringList iconList;
QTimer m_timer;
void iconPath();
private:
Ui::Widget *ui;
public slots:
void slotGetRepalyFinished();
void slotGetWeatherFinished();
void onTimeOut();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QTextCodec>
#include <QString>
#include <QDebug>
#include <QJsonParseError>
#include <QJsonObject>
#include <QJsonArray>
#include <QPixmap>
#include <QPalette>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//设置定时器每一小时更新一次
m_timer.start(3600000);//单位ms,一小时3600000ms
connect(&m_timer,SIGNAL(timeout()),this,SLOT(onTimerout()));
//设置背景
QPalette Pic;
Pic.setBrush(QPalette::Background,QBrush(QPixmap(":/beijing.png").scaled(this->size())));
this->setPalette(Pic);
natManager = new QNetworkAccessManager(this);//一个项目实例化一个即可
QNetworkRequest ipRequest;
ipRequest.setUrl(QUrl("http://whois.pconline.com.cn/ipJson.jsp?ip"));
QNetworkReply *natReply = natManager->get(ipRequest);
connect(natReply,&QNetworkReply::finished,this,&Widget::slotGetRepalyFinished);//应答处理完成后,会发出finished信号
//connect(natReply,SIGNAL(finished()),this,SLOT(slotGetRepalyFinished()));高版本的QT这种写法不会自动提示信号,上面的写法可用
}
Widget::~Widget()
{
delete ui;
}
void Widget::onTimeOut()
{
QNetworkRequest ipRequest;
ipRequest.setUrl(QUrl("http://whois.pconline.com.cn/ipJson.jsp?ip"));
QNetworkReply *natReply = natManager->get(ipRequest);
connect(natReply,&QNetworkReply::finished,this,&Widget::slotGetRepalyFinished);
}
void Widget::slotGetRepalyFinished()
{
//可以用槽函数传入参数QNetworkReply *network代替reply,这样可以不用sender
QNetworkReply *reply = (QNetworkReply *)sender();//返回发出信号的对象
QTextCodec *codec = QTextCodec::codecForName("gbk");
QString data = codec->toUnicode(reply->readAll());//上述操作完成后,data里存储的就是Unicode编码的字符串了
qDebug("%s",data.toStdString().data());
reply->deleteLater();//用完要删除
int cityLocation = data.indexOf("city")+7;
int cityCodeLocation = data.indexOf("cityCode")-4;
QString cityName = data.mid(cityLocation,cityCodeLocation-cityLocation);//mid是字符串切割函数
ui->location->setText(cityName);
QNetworkRequest weatherRequest;
weatherRequest.setUrl(QUrl("http://wthrcdn.etouch.cn/weather_mini?city="+cityName));
QNetworkReply *weatherReply = natManager->get(weatherRequest);
connect(weatherReply,SIGNAL(finished()),this,SLOT(slotGetWeatherFinished()));
}
void Widget::slotGetWeatherFinished()
{
QNetworkReply *reply = (QNetworkReply *)sender();
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QString data = codec->toUnicode(reply->readAll());//上述操作完成后,data里存储的就是Unicode编码的字符串了
qDebug("%s",data.toStdString().data());
reply->deleteLater();//删除reply,不能在 repyfinished 里直接 delete,要调用 deletelater;
QJsonParseError jsonEeeor; //解析JSON时的错误
QJsonObject jsonObject; //封装JSON对象
QJsonDocument jsonDocument; //封装JSON文本
QString jsonData; //封装JSON值
QString iconPic; //封装JSON数组
iconPath();
jsonDocument = QJsonDocument::fromJson(data.toUtf8());//数据来源转换成jsonDocument
if(!jsonDocument.isNull() && jsonEeeor.error == QJsonParseError::NoError){
qDebug("转换成功!!!");//判断下是否转换成功
if(jsonDocument.isObject()){
jsonObject = jsonDocument.object();//把jsonDocument转换成具体的对象jsonObject,就是最外围即第一级的大括号
jsonObject = jsonObject.value("data").toObject();//第二级大括号“data”看成obj对象
//解析温度
jsonData = jsonObject.value("wendu").toString();//jsonData定义了QString类型了,所以toString,wendu里面没有下一级了
qDebug("%s",jsonData.toStdString().data());
ui->label_2->setText(jsonData);
//解析感冒
jsonData = jsonObject.value("ganmao").toString();
qDebug("%s",jsonData.toStdString().data());
ui->text->setText(jsonData);
jsonObject = jsonObject.value("yesterday").toObject();
jsonData = jsonObject.value("type").toString();
ui->weather4->setText(jsonData);
for (int i=0;i<12;++i) {
if(jsonData == iconList[i]){
iconPic = ":/"+QString::number(i+1)+".png";//QString::number是将数数字(整数、浮点数、有符号、无符号等)转换为QString类型
qDebug("%s",iconPic.toStdString().data());//打印图片所在路径
break;
}
if(i == 11){
qDebug("未找到对应的图片");
iconPic = ":/"+QString::number(13)+".png";//若找不到就显示第13张设置好的图片
}
}
QPixmap iconPix(iconPic);
iconPix = iconPix.scaled(ui->weater1->width(),ui->weater1->height(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
ui->weater1->setPixmap(iconPix);//setPixmap加载10几K图片会放大图片,所以要用到QPixmap绘图类
//设置高低温
jsonData = jsonObject.value("low").toString().mid(3,2)+"/";
jsonData = jsonData+jsonObject.value("high").toString().mid(3,2);
ui->temperature->setText(jsonData);
//解析今天和明天的天气
jsonObject = jsonDocument.object();//把jsonDocument转换成具体的对象jsonObject,就是最外围即第一级的大括号
jsonObject = jsonObject.value("data").toObject();//重新让jsonObject先变成第一级data的obj对象
QJsonArray forecast = jsonObject.value("forecast").toArray();//forecast是一个数组,里面有今天和之后的几天的数据
//今天的
jsonObject = forecast.at(0).toObject();//数组第0个看成一个obj对象,第0个就是今天
jsonData = jsonObject.value("low").toString().mid(3,2)+"/";
jsonData = jsonData+jsonObject.value("high").toString().mid(3,2);
ui->temperature2->setText(jsonData);
jsonData = jsonObject.value("type").toString();
ui->weather5->setText(jsonData);
for (int i=0;i<12;++i) {
if(jsonData == iconList[i]){
iconPic = ":/"+QString::number(i+1)+".png";
qDebug("%s",iconPic.toStdString().data());
break;
}
if(i == 11){
qDebug("未找到对应的图片");
iconPic = ":/"+QString::number(13)+".png";//若找不到就显示第13张设置好的图片
}
}
QPixmap iconPix2(iconPic);
iconPix2 = iconPix2.scaled(ui->weather2->width(),ui->weather2->height(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
ui->weather2->setPixmap(iconPix2);
//明天的
jsonObject = forecast.at(1).toObject();//数组第0个看成一个obj对象,第0个就是今天
jsonData = jsonObject.value("low").toString().mid(3,2)+"/";
jsonData = jsonData+jsonObject.value("high").toString().mid(3,2);
ui->temperature3->setText(jsonData);
jsonData = jsonObject.value("type").toString();
ui->weather6->setText(jsonData);
for (int i=0;i<12;++i) {
if(jsonData == iconList[i]){
iconPic = ":/"+QString::number(i+1)+".png";
qDebug("%s",iconPic.toStdString().data());
break;
}
if(i == 11){
qDebug("未找到对应的图片");
iconPic = ":/"+QString::number(13)+".png";//若找不到就显示第13张设置好的图片
}
}
QPixmap iconPix3(iconPic);
iconPix3 = iconPix3.scaled(ui->weather3->width(),ui->weather3->height(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
ui->weather3->setPixmap(iconPix3);
}
}
}
void Widget::iconPath()
{
//和图片的顺序一一对应
iconList << "中雨"
<< "冰雹"
<< "多云"
<< "大雨"
<< "大雪"
<< "小雨"
<< "晴"
<< "暴雨"
<< "沙尘"
<< "雷雨"
<< "小雨转多云"
<< "雾霾";
}
运行到开发板结果:
开发板要先有网络