前言
经过之前一段时间的QT学习,做出一个小软件来总结自己掌握关于qt的知识点。网络上有许多免费的天气接口(api),有xml格式的,也有json格式的。具体xml和json有什么区别,这里我就不去深究了,我们这里用的是一个json格式的数据,所以重点是对json格式的数据进行处理。
效果的展示
颜面是很重要的,首先介绍我的ui
然后介绍ui上各个按键的功能
“1”:这是小狗按钮,点击此键,跳转出一个小狗界面
tips:点击小狗即可实现播报出今天的天气内容,以及温馨提醒。
“2”:实时温度
“3”:现在的天气图片状态
“4”:现在的天气文字状态
“5”:具体今天的温度范围
“6”:刷新界面,然后访问api接口
“7”:定位选择的城市
构造实现
把 ui 和 网络请求解析 分开,ui 是主线程,网络的请求解析是一个单独的线程,net_thread.cpp是线程的文件,将weather.cpp类移入到线程中运行,这样在解析数据的时候,如果数据过大,不至于会影响到 ui 的响应。
把所有的图片都加到了资源里,资源里还有一个包含了所有城市ID的.json文件(这是在网上不知道哪个不知名大佬总结的),在获取天气信息之前,需要先将 .json 里的城市ID读取出来,在拼凑成一个完整的 url 。#ifndef NET_THREAD_H #define NET_THREAD_H #include <QObject> #include <QThread> #include <class_weather/weather.h> class NET_THREAD : public QObject { Q_OBJECT signals: void thread(QString); public: explicit NET_THREAD(QObject *parent = nullptr); ~NET_THREAD(); QThread * qThread = nullptr; WEATHER * weather = nullptr; void startThread(); void stopThread(); signals: }; #endif // NET_THREAD_H
api接口函数,json数据的分段
http://t.weather.sojson.com/api/weather/city/城市ID
连接api之后,返回的数值如图所示:
那我们该如何对返回的数据进行分段处理呢?
这里借鉴了csdn上大佬的处理方法:
数据的分段:
JSON返回示例 : { errNum: 0, errMsg: "success", retData: { city: "北京", //城市 pinyin: "beijing", //城市拼音 citycode: "101010100", //城市编码 date: "15-02-11", //日期 time: "11:00", //发布时间 postCode: "100000", //邮编 longitude: 116.391, //经度 latitude: 39.904, //维度 altitude: "33", //海拔 weather: "晴", //天气情况 temp: "10", //气温 l_tmp: "-4", //最低气温 h_tmp: "10", //最高气温 WD: "无持续风向", //风向 WS: "微风(<10m/h)", //风力 sunrise: "07:12", //日出时间 sunset: "17:44" //日落时间 } } 备注 : 请将apikey作为参数添加到header中; 当返回{"errNum":300003,"errMsg":"url is not parse"} 时,请校验是否传入apikey;
为了取到其中的各条信息需要用到JSON数据的解析
$cityname = urlencode($_POST['cityname']); //设置天气API的url地址,初始化cURL 根据城市名称查询 $url = 'http://apis.baidu.com/apistore/weatherservice/cityname?cityname='.$cityname; //天气API //$this->display(); $ch = curl_init(); $header = array( 'apikey: e858d877f6febd23d6623e14a3dbf220', ); //设置cURL的相关参数,执行HTTP请求 curl_setopt($ch,CURLOPT_URL,$url); // 添加apikey到header curl_setopt($ch, CURLOPT_HTTPHEADER , $header); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); //采集数据 $output = curl_exec($ch); //关闭 curl_close($ch); $res = json_decode($output,true); //将生成的结果转化为json数据 $this->assign('city',$res["retData"]['city']); $this->assign('date',$res["retData"]['date']); $this->assign('time',$res["retData"]['time']); $this->assign('temp',$res["retData"]['temp']); $this->assign('l_tmp',$res["retData"]['l_tmp']); $this->assign('h_tmp',$res["retData"]['h_tmp']); $this->assign('weather',$res["retData"]['weather']); $this->assign('WS',$res["retData"]['WS']); $this->display();
通过这种方式就可以获取其中的每条信息。这种方式基本可以处理所有API返回数据。
$city = $res["resData"]["city"];
分段之后我们用文本的方式记录下来:
关于界面跳转问题
当我们点击地点查询,和小狗这两个按钮,我们的主界面会消失然后分别出现
:
小狗:
地点查询:
关于界面的跳转,我都是运用信号与槽的方式来实现的。
具体代码:
思路:
拿小狗界面举例,首先我用hide隐藏小狗这个界面,当我点击小狗这个按钮的时候,实现小狗显示,然后在小狗的类里实现主界面的消失隐藏,形成一种交互过程,实现了点击按钮,一个消失一个出现。
天气图标实现
在网上找到了很多关于天气打包好的图片:
然后把这些图片添加到资源,例如:
然后每个图片通过比较字符串判断是什么天气,例如:
如果是小雨,则会去找到小雨天气的图片的路径并且显示出来:
代码实现
if(info->forecast[0].weatherType.contains("多云")) { pixmap = ":/icons/weather_icons/duoyun.png"; } else if(info->forecast[0].weatherType.contains("晴")) { pixmap = ":/icons/weather_icons/qing.png"; } else if(info->forecast[0].weatherType.contains("小雨")) { pixmap = ":/icons/weather_icons/xiaoyu.png"; } else if(info->forecast[0].weatherType.contains("沙尘")) { pixmap = ":/icons/weather_icons/shachen.png"; } else if(info->forecast[0].weatherType.contains("雾霾")) { pixmap = ":/icons/weather_icons/wumai.png"; } else if(info->forecast[0].weatherType.contains("雪转晴")) { pixmap = ":/icons/weather_icons/xuezhuanqing.png"; } else if(info->forecast[0].weatherType.contains("夜多云")) { pixmap = ":/icons/weather_icons/yeduoyun.png"; } else if(info->forecast[0].weatherType.contains("中雨")) { pixmap = ":/icons/weather_icons/zhongyu.png"; } else if(info->forecast[0].weatherType.contains("暴雨")) { pixmap = ":/icons/weather_icons/baoyu.png"; } else if(info->forecast[0].weatherType.contains("冰雹")) { pixmap = ":/icons/weather_icons/bingbao.png"; } else if(info->forecast[0].weatherType.contains("大雪")) { pixmap = ":/icons/weather_icons/daxue.png"; } else if(info->forecast[0].weatherType.contains("大雨")) { pixmap = ":/icons/weather_icons/dayu.png"; } else if(info->forecast[0].weatherType.contains("雷雨")) { pixmap = ":/icons/weather_icons/leiyu.png"; } ui->label_weather_icon->setPixmap(QPixmap(pixmap)); }
小狗语音播报
当我们点击小狗,小狗就会自动播报处今天的天气情况,以及提醒。我是这样实现的:
因为,天气的数据处理和小狗不是同一个类,所以我决定在天气数据的类里创建一个文本文件,然后经过字符格式的转换写入文件,然后进行文本的换行处理,在狗的类里在根据路径打开文本文件并朗读,使语音有分段。
具体代码
天气类里实现的部分
QFile file("qwer.txt"); char *zxc="\n"; file.open(QIODevice::WriteOnly); file.write(info->cityName.toUtf8()); char* zaxc="今日实时温度"; file.write(zxc); file.write(zaxc); file.write(info->realTime.temp.toUtf8()); file.write(zxc); file.write(info->forecast[0].temp.toUtf8()); file.write(zxc); file.write(info->forecast[0].weatherType.toUtf8()); file.write(zxc); for(int i=0;i<4;i++) { QString str=showMessageList[i]; QByteArray buf =str.toUtf8(); file.write(buf); file.write(zxc); } file.close();
小狗类里实现的部分
QTextToSpeech *s = new QTextToSpeech; QFile file("qwer.txt"); file.open(QIODevice::ReadOnly); QByteArray zbc; zbc=file.readAll(); s->say(zbc);