1、 嵌入式图形界面设计报告 班级:计算机科学与技术15-2班 小组成员:刘航征、安宝、曲晗羽 杨祎涵、张振、李雪辰 2017年12月 一、前言 天气预报(测)或气象预报(测)是使用现代科学技术对未来某一地点地球大气层的状态进行预测。从史前人类就已经开始对天气进行预测来相应地安排其工作与生活(比如农业生产、军事行动等等)。今天的天气预报主要是使用收集大量的数据(气温、湿度、风向和风速、气压等等),然后使用目前对大气过程的认识(气象学)来确定未来空气变化。
2、由于大气过程的混乱以及今天科学并没有最终透彻地了解大气过程,因此天气预报总是有一定误差的。 最传统的数据是在地面或海面上通过专业人员、爱好者、自动气象站或者浮标收集的气压、气温、风速、风向、湿度等数据。世界气象组织协调这些数据采集的时间,并制定标准。这些测量分每小时一次(METAR)或者每六小时一次(SYNOP)。 该项目为一款天气预报软件,基于Qt5开发,具有查询指定城市天气、显示当天天气状况以及未来四天天气大致状况的主要功能,次要功能为更换软件皮肤,显示当天感冒指数等功能。 软件预览图: 日期显示栏 搜索栏 湿度、风向栏 实时气温栏 日出、日落时间显示栏 感
3、冒指数信息栏 换肤按钮、最小化、关闭按钮 今日以及未来四日天气 二、选用的技术基本说明 1、Qt JSON操作 QJsonDocument QJsonDocument 类用于读和写 JSON 文档。 一个 JSON 文档可以使用 QJsonDocument::fromJson() 从基于文本的表示转化为 QJsonDocument, toJson() 则可以反向转化为文本。解析器非常快且高效,并将 JSON 转换为 Qt 使用的二进制表示。 已解析文档的有效性,可以使用 !isNull() 进行查询。 如果要查询一个 JSON 文档是否包含一个数组或一个对象,使用 i
4、sArray() 和 isObject()。包含在文档中的数组或对象可以使用 array() 或 object() 检索,然后读取或操作。 也可以使用 fromBinaryData() 或 fromRawData() 从存储的二进制表示创建来 JSON 文档。 QJsonArray QJsonArray 类封装了一个 JSON 数组。 JSON 数组是值的列表。列表可以被操作,通过从数组中插入和删除 QJsonValue 。 一个 QJsonArray 可以和一个 QVariantList 相互转换。可以使用 size() 来查询条目的数量,通过 insert() 在指定索引处插
5、入值,removeAt() 来删除指定索引的值。 QJsonObject QJsonObject 类封装了一个 JSON 对象。 一个 JSON 对象是一个“key/value 对”列表,key 是独一无二的字符串,value 由一个 QJsonValue 表示。 一个 QJsonObject 可以和一个 QVariantMap 相互转换。可以使用 size() 来查询“key/value 对”的数量,通过 insert() 插入“key/value 对”, remove() 删除指定的 key。 QJsonValue QJsonValue 类封装了一个值。 JSON 中
6、的值有 6 种基本数据类型: · bool(QJsonValue::Bool) · double(QJsonValue::Double) · string(QJsonValue::String) · array(QJsonValue::Array) · object(QJsonValue::Object) · null(QJsonValue::Null) 一个值可以由任何上述数据类型表示。此外,QJsonValue 有一个特殊的标记来表示未定义的值,可以使用 isUndefined() 查询。 值的类型可以通过 type() 或 isBool()、isString() 等访问函
7、数查询。同样地,值可以通过 toBool()、toString() 等函数转化成相应的存储类型。 QJsonParseError QJsonParseError 类用于在 JSON 解析中报告错误。 枚举 QJsonParseError::ParseError: 该枚举描述 JSON 文档在解析过程中所发生的错误类型。 2、Qt XML 操作 QXmlStreamReader 用于读取格式良好的XML文档的快速解析器,该类最快且最易于使用,并提供了与其他Qt兼容的应用程序编程接口,很适用于编写单通道解析器; 3、QNetworkAccessManager
8、QNetworkAccessManager类允许应用程序发送网络请求和接收网络应答。 三、方案设计 1、初始化UI界面 2、获取当前地区时间 3、从文件中读取每个城市名称以及其代码,将其组合分别存入QMap类对象citykeys中 4、用预设的url发送http请求,获取本地城市名称 5,、用获取的本地城市名称获取citykeys中对应的城市代码发出查询未来五天天气的http请求 6、收到的回复为JSON文档,用QJsonDocument类解析JSON文档,将得到的未来五天的天气信息分别存入Forecast结构体数组forecast的每一个元素中,将这些信息显示在主窗口中对应
9、的控件上,然后发出查询今天天气的http请求 7、收到的回复为XML格式文档,用QXmlStreamReader类读取其信息,将当天的天气信息存入Today结构体today中,将这些信息显示在主窗口中对应的控件上。 8、设置搜索按钮以及换肤按钮的信号与槽的关联。 流程图 程序启动 初始化UI界面 获取当前本地时间 读取城市及其代码 Y 获取本地城市名称 点击搜索城市天气 点击换肤按钮 查询未来五天天气信息 重绘UI界面 查询当天天气信息 点击关闭按钮 Y 退出程序 四、详细代
10、码解析
ui设计界面:
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
11、QLabel> namespace Ui { class MainWindow; } struct Forecast { QString fengxiang; QString fengli; QString high; QString type; QString low; QString date; }; struct Today { QString ganmao; QString city; QString updatetime; QString wendu;
12、 QString fengli; QString fengxiang; QString sunrise; QString sunset; QString shidu; }; class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); protected: void paintEvent(QPaintEvent *);
13、 void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *); protected slots: void replayFinished(QNetworkReply *reply); private slots: void on_getButton_clicked(); void on_updateButton_clicked(); private:
14、 Ui::MainWindow *ui; QNetworkAccessManager *manager; QString URL_1; QString URL_2; Forecast forecast[5]; Today today; void parseJson(QString Json); void parseXml(QString Xml); void parseCity(QString City); void loadCitykeys();//加载城市代码文件 QMap
15、
16、 int uid;
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include 17、r>
#include 18、);
resize(pixmap.size());
uid = 0;
mouse_press = false;
forecast_date_list< 19、ast_3_temp< 20、hed(QNetworkReply*)),this,SLOT(replayFinished(QNetworkReply*)));
//设置组件样式
ui->cityEdit->setTextMargins(0, 0, ui->getButton->width(), 0);
ui->cityEdit->setStyleSheet("QLineEdit{border: 1px solid gray;border-radius: 3px;background:rgb(200, 231, 232);} QLineEdit:hover{border-color:tran 21、sparent; }");
ui->getButton ->setStyleSheet("background:transparent;");
ui->closeButton->setStyleSheet("QPushButton {border-image:url(:/images/close);}QPushButton:hover{border-image:url(:/images/close_on);}QPushButton:hover:pressed{border-image:url(:/images/close);}");
ui->minButton-> 22、setStyleSheet("QPushButton {border-image:url(:/images/min);}QPushButton:hover{border-image:url(:/images/min_on);}QPushButton:hover:pressed{border-image:url(:/images/min);}");
ui->updateButton->setStyleSheet("QPushButton {border-image:url(:/images/update);}QPushButton:hover{border-image:url(:/im 23、ages/update_on);}QPushButton:hover:pressed{border-image:url(:/images/update);}");
QDateTime time = QDateTime::currentDateTime();
ui->date->setText(tr("%1").arg(time.toString("yyyy-MM-dd")));
//加载城市代码
loadCitykeys();
//启动程序后先查询ip定位默认城市
choose = 0;
manager->ge 24、t(QNetworkRequest(QUrl("")));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawPixmap(0, 0, pixmap);//绘制UI
}
void MainWindow::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt:: 25、LeftButton)
{
//鼠标相对于窗体的位置)
move_point = event->pos();
mouse_press = true;
}
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
if(mouse_press)
{
//鼠标相对于屏幕的位置
QPoint move_pos = event->globalPos();
//移动主窗体
th 26、is->move(move_pos - move_point);
}
}
void MainWindow::mouseReleaseEvent(QMouseEvent *)
{
mouse_press = false;
}
void MainWindow::loadCitykeys() {
QFile file(":/citykeys/citykeys");
if ( !file.open(QIODevice::ReadOnly | QIODevice::Text) )
return ;
QStrin 27、g tmp;
while (file.atEnd() == 0) {
tmp = file.readAll();
}
QStringList list = tmp.split(",");
for(int i = 0; i < list.length(); i++) {
QString s = list.at(i);
QString citys = s.split(":").at(1);
QString city = citys.replace("\"", "");
28、 QString codes = s.split(":").at(0);
QString code = codes.replace("\"", "");
citykeys.insert(city, code);
}
}
void MainWindow::replayFinished(QNetworkReply *reply)
{
QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if(reply-> 29、error() == QNetworkReply::NoError)
{
QByteArray bytes = reply->readAll();
if(choose == 0)//查询IP
{
QString result = QString::fromLocal8Bit(bytes);
parseCity(result);
}
else if(choose == 1)//今天天气+指数
{
QS 30、tring result(bytes);
parseXml(result);
}
else if(choose == 2)//未来5天天气
{
QString result(bytes);
parseJson(result);
}
}
else
QMessageBox::information(this,tr("出错啦"),tr("网络错误,请检查网络连接"),QMessageBox::Ok,QMessage 31、Box::Ok);
}
//解析城市信息
void MainWindow::parseCity(QString City)
{
city = City.split(tr(" ")).at(5);
if(city == "" || citykeys[city]=="")
{
QMessageBox::information(this,tr("提示"),tr("无法定位城市,请手动查询"),QMessageBox::Ok,QMessageBox::Ok);
return;
}
QString ur 32、l = URL_1 + citykeys[city];
choose = 2;
manager->get(QNetworkRequest(QUrl(url)));
}
//解析json格式的未来天气
void MainWindow::parseJson(QString Json)
{
QByteArray byte_array;
QJsonParseError json_error;
QJsonDocument parse_doucment = QJsonDocument::fromJson(byte_array.append( 33、Json),&json_error);
if(json_error.error == QJsonParseError::NoError)
{
QJsonObject obj = parse_doucment.object();
QJsonValue desc = obj.take("desc");
if(desc.toString() != "OK")
{
QMessageBox::information(this,tr("抱歉"),tr("暂无此城市的天气情况"),Q 34、MessageBox::Ok,QMessageBox::Ok);
return;
}
QJsonValue data = obj.take("data");
today.ganmao = data.toObject().take("ganmao").toString();
QJsonValue forecast1 = data.toObject().take("forecast");
QJsonArray forecast2 = forecast1.toArray();
35、 for(int i=0; i<5; i++)
{
QJsonValue value = forecast2.at(i);
QJsonObject object = value.toObject();
forecast[i].fengxiang = object.take("fengxiang").toString();
forecast[i].date = object.take("date").toString();
forecas 36、t[i].fengli = object.take("fengli").toString();
forecast[i].high = object.take("high").toString();
forecast[i].low = object.take("low").toString();
forecast[i].type = object.take("type").toString();
}
for(int i=0;i<5;i++)
{
37、 forecast_date_list[i]->setText(tr("%1").arg(forecast[i].date));
forecast_temp_list[i]->setText(tr("%1 - %2").arg(forecast[i].low.split(" ").at(1)).arg(forecast[i].high.split(" ").at(1)));
forecast_type_list[i]->setPixmap(QPixmap(tr(":/images/%1").arg(forecast[i].type)) 38、);
forecast_type_list[i]->setToolTip(tr("%1 : %2 - %3").arg(forecast[i].type).arg(forecast[i].fengli).arg(forecast[i].fengxiang));
}
ui->forecast_0_date->setText(tr("今天"));
QString url = URL_2 + citykeys[city];
choose = 1;
manager->get(QNet 39、workRequest(QUrl(url)));
}
else
{
QMessageBox::information(this,tr("出错啦"),tr("数据出错,请重试 "),QMessageBox::Ok,QMessageBox::Ok);
return;
}
}
//解析XML格式的今天天气
void MainWindow::parseXml(QString Xml)
{
QXmlStreamReader xml(Xml);
while(!xml.atEnd())
40、 {
if(xml.hasError())
{
QMessageBox::information(this,tr("出错啦"),tr("数据出错,请重试"),QMessageBox::Ok,QMessageBox::Ok);
return;
}
else if(xml.isStartElement())
{
if(xml.name()=="city")
{
toda 41、y.city = xml.readElementText();
}
else if(xml.name()=="updatetime")
{
today.updatetime = xml.readElementText();
}
else if(xml.name()=="wendu")
{
today.wendu = xml.readElementText();
42、 }
else if(xml.name()=="fengli")
{
today.fengli = xml.readElementText();
}
else if(xml.name()=="shidu")
{
today.shidu = xml.readElementText();
}
else if(xml.name()=="fen 43、gxiang")
{
today.fengxiang = xml.readElementText();
}
else if(xml.name()=="sunrise_1")
{
today.sunrise = xml.readElementText();
}
else if(xml.name()=="sunset_1")
{
44、 today.sunset = xml.readElementText();
xml.clear();
ui->city->setText(tr("%1").arg(today.city));
ui->temp->setText(tr("%1℃").arg(today.wendu));
ui->sunrise->setText(tr("%1").arg(today.sunrise));
ui->sunset->s 45、etText(tr("%1").arg(today.sunset));
ui->label->setText(tr("日出"));
ui->label_2->setText(tr("日落"));
ui->label_3->setText(tr("湿度"));
ui->shidu->setText(tr("%1").arg(today.shidu));
ui->fengli->setText(tr("%1").arg(today 46、fengli));
ui->fengxiang->setText(tr("%1").arg(today.fengxiang));
ui->label_4->setText(tr("感\n冒\n指\n数"));
ui->ganmao->setText(tr("%1").arg(today.ganmao));
return;
}
else
xml.readNext();
47、 }
else
xml.readNext();
}
xml.clear();
}
//搜索框查询天气
void MainWindow::on_getButton_clicked()
{
if(ui->cityEdit->text().isEmpty())
return;
city = ui->cityEdit->text();
if(citykeys[city] == "") {
QMessageBox::information(thi 48、s,tr("抱歉"),tr("暂无此城市的天气情况"),QMessageBox::Ok,QMessageBox::Ok);
return;
}
QString url = URL_1 + citykeys[city];
choose = 2;
manager->get(QNetworkRequest(QUrl(url)));
}
//简单换肤
void MainWindow::on_updateButton_clicked()
{
//选择UI的id
if(uid == 3)
uid 49、 = 0;
else
uid = uid + 1;
//拼凑成UI路径
QString UIpath = tr(":/images/UI%1").arg(uid);
//qDebug()< 50、r *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
五、测试数据及分析
打开程序:
换肤:
搜索指定城市天气信息:
六、结论:
本次我们小组对设计实验所涉及到知识进行讨论,共同研究,查证资料,掌握将要用到的Qt知识并且对我们小组的实验进行主要设计,对小组实验进行分工,本次设计实验结束后我们脑海里已经对QT的知识面得到了延伸!
七、参考文献
[Qt之JSON生成与解析]






