QT汽车智能仪表盘

QT汽车智能仪表盘

前言:这是一个QT框架制作的汽车智能仪表盘项目,具有导航提示与路线规划、天气预报展示、音乐播放器、用户自定义背景仪表盘颜色、智能语音助手,五大功能。
读取数据库模拟的汽车行驶数据例如车速、油耗、水温等,展示在仪表盘及主界面。调用高德及百度API获取真实天气、实时导航路线数据。

一、项目界面展示

car1

car2

car3

car4

car5

二、项目设计

主界面widget
ui绘制界面样式布局,初始化仪表盘,连接数据库进行车辆数据、导航路线的展示与实时更新,连接按钮信号,进行语音助手的操作逻辑判断。

导航界面gps
ui绘制界面样式布局,调用高德地图导航路线规划API获取实时导航路线规划数据,展示在文字显示框中。同时间隔一定时间,分条展示在主界面上。
用户在输入栏输入出发地与目的地即可查询路径规划。

天气界面weather
ui绘制界面样式布局,调用高德地图天气数据API获取实时天气数据,并解析JSON数据,判断展示不同天气图标。
用户在输入栏输入想要查询的城市名称并点击搜索图标,即可将实时天气数据展示在界面上。

音乐播放器界面music
ui绘制界面样式布局,调用qt多媒体模块工具进行操作,具有音乐播放、暂停、选择歌曲、切换上一首下一首等功能。

智能语音助手“小亦”
此功能没有独立界面,耦合在主界面中,通过语音助手不同状态的切换来识别不同层级的简单指令。
语音助手内部逻辑有两个层级的指令,第一层级是进行页面的切换与天气/导航数据查询等,页面切换后则进入第二层级状态,进行不同功能页面更细致的操作,两个层级的关键词指令识别略有不同。
用户点击呼叫按钮即可启动语音助手状态,用户可在几秒内说出简单指令,与语音助手进行交互,当用户回答退出、返回等字眼,即可退出指令模式。

三、部分代码展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
//主界面widget
#include "widget.h"//...省略
#include <QTimer>//...省略

//语音助手当前状态
enum State {
MAIN_STATE,
WEATHER_STATE,
MUSIC_STATE,
GPS_STATE,
SETTINGS_STATE
};

Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
, weather(nullptr) //初始化为nullptr
, music(nullptr)
, gps(new GPS(this))
,setting(new Setting(this))//创建子界面示例 不然信号连接空指针
//,xiaoYi(new XiaoYi(this))
,timer4(new QTimer(this))//数据库行号
,currentState(MAIN_STATE)
,currentRow(0) //初始化导航标志
,currentIndex(0)
,isNavigating(false)//注意此处
{
this->setWindowTitle("汽车中控3D仪表盘");
this->resize(1550, 700);

//记得设置无边框只有右上角的x
//设置背景图片
QPixmap bkgnd(":/assets/picture/theme1.jpg"); //替换路径和文件名为你的背景图片
bkgnd = bkgnd.scaled(2000, 1000); //指定图片的宽度和高度
QPalette palette;
palette.setBrush(QPalette::Window, bkgnd);
this->setPalette(palette);

ui->setupUi(this);

//语音助手按钮
canStart = true;
canEnd = false;

//初始化仪表盘
initGauge();

//按钮信号连接
connect(ui->Weather,&QPushButton::clicked,this,&Widget::on_Weather_clicked);
connect(ui->Music,&QPushButton::clicked,this,&Widget::on_Music_clicked);
connect(ui->GPS,&QPushButton::clicked,this,&Widget::on_GPS_clicked);
connect(ui->Setting,&QPushButton::clicked,this,&Widget::on_Setting_clicked);

//连接与setting界面的信号
connect(setting,&Setting::changeMainBackground,this,&Widget::changeBackground);
connect(setting,&Setting::changeMainGaugeCrown,this,&Widget::changeGaugeCrown);
connect(setting,&Setting::changeMainGaugeBack,this,&Widget::changeGaugeBack);
connect(setting,&Setting::changeMainGaugeScale,this,&Widget::changeGaugeScale);

//连接与导航界面的信号
connect(gps,&GPS::dataUpdated, this, &Widget::onGpsDataUpdated);
connect(gps, &GPS::navigationStarted, this, &Widget::onNavigationStarted);

//连接与语音助手的信号
//connect(xiaoYi,&XiaoYi::changeMainBackground,this,&Widget::changeBackground);
// connect(xiaoYi,&XiaoYi::open_mainWeather,this,&Widget::on_Weather_clicked);
// connect(xiaoYi,&XiaoYi::open_mainMusic,this,&Widget::on_Music_clicked);
// connect(xiaoYi,&XiaoYi::open_mainGps,this,&Widget::on_GPS_clicked);
// connect(xiaoYi,&XiaoYi::open_mainSetting,this,&Widget::on_Setting_clicked);

//语音助手的计时器信号
connect(timer4, &QTimer::timeout, this, &Widget::onTimerTimeout);

//连接数据库
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("D:\\ALL\\Cardatabase\\Cardatabase.db");
//打开数据库
if(!db.open())
qDebug()<<"Error falied to open"<<db.lastError();
else
qDebug()<<"open success";
//访问数据库的操作
QSqlQuery testQuery;//创建该对象时 系统会自动完成跟数据库的关联
//访问已经创建好的Cardata表并获取数据
QString sqlSelect = QString("SELECT * FROM Cardata");
if(!testQuery.exec(sqlSelect))
qDebug()<<"Error: Failed to execute query" << testQuery.lastError();

//定时器1用于更新QLabel
QTimer * timer1 = new QTimer(this);
connect(timer1,&QTimer::timeout,this,&Widget::updateLabels);
timer1->start(1000);//每秒更新一次

//定时器2用于更新仪表盘指针(车速)
QTimer * timer2 = new QTimer(this);
connect(timer2,&QTimer::timeout,this,&Widget::updateSpeed);
timer2->start(1000);//每1秒更新一次

//定时器3用于更新导航语句
timer3 = new QTimer(this);
connect(timer3, &QTimer::timeout, this, &Widget::updateGps);

//网络请求车辆数据
mNetAccessManager = new QNetworkAccessManager(this);
//请求数据后自动触发onReply函数
connect(mNetAccessManager,&QNetworkAccessManager::finished,this,&Widget::onReplied);
//直接在构造中请求车辆数据
getCarInfo("101010100");

ui->gpsText->setStyleSheet("color: white;background-color: rgba(12, 47, 123,90);border: none;border-radius: 20px;");

//初始化文字转语音设置
textToSpeech = new QTextToSpeech;
textToSpeech->setLocale(QLocale::Chinese);//中文语言环境
textToSpeech->setRate(0.2);//语速
textToSpeech->setPitch(0.7);//音高
textToSpeech->setVolume(1.0);//音量
}

Widget::~Widget()
{
db.close();//关闭数据库
delete ui;
}

//初始化仪表盘
void Widget::initGauge()
{
leftGauge = new Gauge(this);
leftGauge->setCrownColor(0);
leftGauge->setScaleColor(0);

rightGauge = new Gauge(this);
rightGauge->setGauge2();
rightGauge->setCrownColor(0);
rightGauge->setScaleColor(0);

//加入布局
ui->gauge1Layout->addWidget(leftGauge);
ui->gauge2Layout->addWidget(rightGauge);
}

void Widget::onReplied(QNetworkReply *reply)
{
int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();//响应码
if(reply->error() != QNetworkReply::NoError || status_code != 200){
qDebug() << reply->errorString().toLatin1().data();
QMessageBox::warning(this,"车辆","请求数据失败",QMessageBox::Ok);
}else{
//获取响应信息
QByteArray byteArr = reply->readAll();
qDebug()<<"read all: "<<byteArr.data();
parseJson(byteArr);
}
reply->deleteLater();//内存释放
}

void Widget::getCarInfo(QString url)
{
//需要用到OpenSSL!可恶可恶
QUrl ur("https://restapi.amap.com/v3/weather/weatherInfo?city=110101&key=ac3532f443810764e162082a7d35a2ea");
mNetAccessManager->get(QNetworkRequest(ur));
}

void Widget::parseJson(QByteArray &byteArray)
{
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(byteArray,&err);
if(err.error != QJsonParseError::NoError){
return;
}
QJsonObject rootObj = doc.object();
qDebug()<<rootObj;
//
}

//更新标签文本
void Widget::updateLabels()
{
//模拟数据更新(车速转速导入真实数据源)
QTime currentTime = QTime::currentTime();
ui->NowTime->setText(QString("%1").arg(currentTime.toString("hh : mm : ss")));//要获取年月日
ui->Fuel->setText(QString("耗油量: %1 L/100km").arg(QRandomGenerator::global()->bounded(3)+8));
ui->Water->setText(QString("水温: %1 °C").arg(32));
}

//更新导航数据
void Widget::updateGps()
{
if (GPS::instructionsMap && currentRow < GPS::instructionsMap->size()) {
QString instruction = GPS::instructionsMap->value(currentRow);
if (!instruction.isEmpty()) {
//清空文本框并设置新的导航指令
ui->gpsText->clear();
ui->gpsText->setPlainText(instruction);
++currentRow;
}
} else {
timer3->stop();
}
}


//更新车速数据
void Widget::updateSpeed()
{
QSqlQuery query;
//访问已经创建好的Cardata表并获取数据
query.prepare("SELECT * FROM Cardata LIMIT 1 OFFSET :offset");
query.bindValue(":offset", currentRow);
if(!query.exec())
qDebug()<<"Error: Failed to execute query" << query.lastError();
else{
if(query.next()){
//获取数据
double speed = query.value("speed").toDouble();
double rpm = query.value("rpm").toDouble();

//监测车速与油耗
//warning(speed,11);

//更新仪表盘指针
leftGauge->setValue(speed);
rightGauge->setValue(rpm);

//更新行号
currentRow++;
if(currentRow >= 50)
currentRow = 0;
}
}
}

void Widget::warning(double speed, double fuel)
{
//exec() 方法会阻塞主线程
if(speed < 60 && !highSpeedMes.isVisible()){
highSpeedMes.setText("车速低于60km/h 请加速!");
highSpeedMes.show();
// 过三秒自行关闭
QTimer::singleShot(3000, [this](){
highSpeedMes.close();
});
} else if(speed > 100 && !lowSpeedMes.isVisible()){
lowSpeedMes.setText("车速高于100km/h 请减速!");
lowSpeedMes.show();
// 过3秒自行关闭
QTimer::singleShot(3000, [this](){
lowSpeedMes.close();
});
}
if(fuel < 10 && !lowFuelMes.isVisible()){
lowFuelMes.setText("油量低于10% 请加油!");
lowFuelMes.show();
// 过3秒自行关闭
QTimer::singleShot(3000, [this](){
lowFuelMes.close();
});
}
}

//更改主题
void Widget::changeBackground(int code)
{
qDebug()<<"11111111111111111111111111111111111111111";
QPixmap bkgnd(":/assets/picture/theme"+QString::number(code)+".jpg");
bkgnd = bkgnd.scaled(2000, 1000); //指定图片的宽度和高度
QPalette palette;
palette.setBrush(QPalette::Window, bkgnd);
this->setPalette(palette);
if(code == 2){
ui->Fuel->setStyleSheet("color: black;");
ui->Water->setStyleSheet("color: black;");
ui->NowTime->setStyleSheet("color: black;");
ui->gpsText->setStyleSheet("color: black;");
ui->gpsText->setStyleSheet("color: black;background-color: rgba(12, 47, 123,90);border: none;border-radius: 20px;");
}else{
ui->Fuel->setStyleSheet("color: white;");
ui->Water->setStyleSheet("color: white;");
ui->NowTime->setStyleSheet("color: white;");
ui->gpsText->setStyleSheet("color: white;background-color: rgba(12, 47, 123,90);border: none;border-radius: 20px;");
}
//确保gpsText保持多行文本设置
ui->gpsText->setWordWrapMode(QTextOption::WordWrap); //启用自动换行
ui->gpsText->setReadOnly(true); //设置为只读模式,防止用户编辑
qDebug()<<"22222222222222222222222222222222222222222222";
}

void Widget::changeGaugeCrown(int code)
{
leftGauge->setCrownColor(code);
rightGauge->setCrownColor(code);
}

void Widget::changeGaugeBack(int code)
{
leftGauge->setBackgroundColor(code);
rightGauge->setBackgroundColor(code);
}

void Widget::changeGaugeScale(int code)
{
leftGauge->setScaleColor(code);
rightGauge->setScaleColor(code);
}

//更新导航数据
void Widget::onGpsDataUpdated()
{
currentIndex = 0;
timer3->start(5000);//5秒更新一条
}

//监测导航开始信号
void Widget::onNavigationStarted()
{
isNavigating = true;
timer3->stop();
}

//开始录音(连续点击多次开始按钮就会出bug怎么办)->(两个按钮只能轮着点)
void Widget::on_startButton_clicked()
{
if(!canStart)
return;

//禁用开始按钮 启用结束按钮
canStart = false;
canEnd = true;

//初始化倒计时
time = 10;//(怎么实现自动识别用户“停止说话”? 先强制每句话5s以内 用户不点击就强制结束)
ui->timeLabel->setText("还有 "+QString::number(time) + " 秒");
timer4->start(1000);//启动倒计时

//开始录音
audio = new Audio;
audio->startAudio("D:\\learn\\Car\\1.pcm");//记得创建新文件
}

//结束录音
void Widget::on_endButton_clicked()
{
ui->textEdit->clear();//自动清理之前内容

if(!canEnd)
return;

//禁用结束按钮 启用开始按钮
canStart = true;
canEnd = false;

//停止计时器
timer4->stop();

//停止录音
audio->stopAudio();
delete audio;//释放对象
audio = nullptr;

//1、开始语音识别
Speech mSpeech;
QString text = mSpeech.speechIdentify("D:\\learn\\Car\\1.pcm");
//QString text = "返回主界面";
//qDebug()<<"hhhhhhhhhhhhhhhhhhhhhhhhhhh"<<text;

//文字框显示
ui->textEdit->setText(text);

//2、开始自然语言处理
if(currentState == MAIN_STATE){
//进行第一层指令的分析处理

//进行自然语言处理-关键词提取
BaiduKeyword mKeyword;
mKeyword.keywordIdentify(text);

//qDebug()<<"1111111111"<<BaiduKeyword::keyWords.join(", ");//调试

processNpl(BaiduKeyword::keyWords,BaiduSmallword::smallwords);

} else {
//进行第二层指令的分析处理

//进行自然语言处理-词法分析
BaiduSmallword mSmallword;
mSmallword.smallwordIdentify(text);

//调试
// for (auto it = BaiduSmallword::smallwords.begin(); it != BaiduSmallword::smallwords.end(); ++it) {
// qDebug() << it.key() << ": " << it.value();
// }

processNpl(BaiduKeyword::keyWords,BaiduSmallword::smallwords);
}
}

//处理意图提取结果 并发射信号转换状态
void Widget::processNpl(const QStringList &keywords,const QMap<QString, QString> &smallwords)
{
if(currentState == MAIN_STATE){
for(const QString &keyword : keywords){
if(keyword == "指令"){
textToSpeech->say("指令结束,期待与您再次见面");
ui->endButton->click();//结束指令 即强制结束录音
break;
}
else if(keyword == "天气" || keyword == "天气预报"){
currentState = WEATHER_STATE;
qDebug()<<"小亦:已为您打开天气预报界面,还有什么指令?";

ui->Weather->click();

textToSpeech->say("已为您打开天气预报界面,还有什么指令?");
ui->startButton->click();//自动开启开始按钮
//打开天气预报界面逻辑
break;
} else if (keyword == "音乐") {
currentState = MUSIC_STATE;
qDebug() << "小亦:已为您打开音乐播放器界面,还有什么指令?";

ui->Music->click();

textToSpeech->say("已为您打开音乐播放器界面,还有什么指令?");
ui->startButton->click();//自动开启开始按钮
//打开音乐播放器界面逻辑
break;
} else if (keyword == "导航") {
currentState = GPS_STATE;
qDebug() << "小亦:已为您打开gps界面,还有什么指令?";

ui->GPS->click();

textToSpeech->say("已为您打开导航界面,还有什么指令?");
ui->startButton->click();//自动开启开始按钮
//打开gps界面逻辑
break;
} else if (keyword == "设置" || keyword == "主题") {
currentState = SETTINGS_STATE;
qDebug() << "小亦:已为您打开设置界面,还有什么指令?";

ui->Setting->click();

textToSpeech->say("已为您打开设置界面,还有什么指令?");
ui->startButton->click();//自动开启开始按钮
//打开设置界面逻辑
break;
}
}
} else {
if (currentState == WEATHER_STATE) {
//处理天气子命令
handleWeather(smallwords);
} else if (currentState == MUSIC_STATE) {
//处理音乐子命令
handleMusic(smallwords);
} else if (currentState == GPS_STATE) {
//处理GPS子命令
handleGps(smallwords);
} else if (currentState == SETTINGS_STATE) {
//处理设置子命令
handleSettings(smallwords);
}
}
}

void Widget::handleWeather(const QMap<QString, QString> &smallwords)
{
//结束指令 退出子界面 返回主界面 查询深圳市天气

//判断是否要结束指令或退出页面(动词)
if (smallwords.contains("LOC")) {
QString loc = smallwords.value("LOC");

//执行查询“loc”市的逻辑
weather->getWeatherInfo(loc);//不担心空指针 因为二级指令界面已打开

qDebug()<<"小亦:已为您查询loc市天气,还有什么指令?";
textToSpeech->say("已为您查询"+loc+"市天气,还有什么指令");
ui->startButton->click();//自动开启开始按钮
}
else if(smallwords.contains("v")){
QString action = smallwords.value("v");
if(action =="结束"){
textToSpeech->say("指令结束,期待与您再次见面");
ui->endButton->click();//停留在当前界面且结束录音
}else if (action=="返回"||action == "退出") {
currentState = MAIN_STATE;

weather->close();

qDebug()<<"小亦:已关闭天气预报窗口返回主页面,还有什么指令?";
textToSpeech->say("已为您关闭天气预报窗口返回主页面,还有什么指令?");
ui->startButton->click();//自动开启开始按钮
}else{
qDebug()<<"小亦:没听清楚,请再说一遍指令?";
textToSpeech->say("不好意思,我没听清楚,请再说一遍指令");
ui->startButton->click();//自动开启开始按钮
}
}else {
qDebug() << "小亦:您没有说出想要查询天气的城市,请再说一遍,或者选择退出子界面";
textToSpeech->say("您没有说出想要查询天气的城市,请再说一遍,或者选择退出子界面");
ui->startButton->click();//自动开启开始按钮
}
}

void Widget::handleMusic(const QMap<QString, QString> &smallwords)
{
//结束指令 退出子界面 返回主界面 播放音乐 暂停播放 停止播放 下一首歌 上一首歌(不能加上"播放")

//判断是否要结束指令或退出页面(动词)
if (smallwords.contains("else")) {
QString elsething = smallwords.value("else");
if(elsething == "下" || elsething == "下面"){
qDebug()<<"小亦:已为您播放下一首歌,还有什么指令?";

music->playNext();

textToSpeech->say("已为您播放下一首歌,还有什么指令");
ui->startButton->click();//自动开启开始按钮
}else if(elsething == "上" || elsething == "上面"){
qDebug()<<"小亦:已为您播放上一首歌,还有什么指令?";

music->playPrev();

textToSpeech->say("已为您播放上一首歌,还有什么指令");
ui->startButton->click();//自动开启开始按钮
}
}
else if(smallwords.contains("v")){
QString action = smallwords.value("v");
if(action =="结束"){
textToSpeech->say("指令结束,期待与您再次见面");
ui->endButton->click();//停留在当前界面且结束录音
}else if (action=="返回"||action == "退出") {
currentState = MAIN_STATE;
//关闭子页面逻辑
qDebug()<<"小亦:已关闭音乐播放器窗口返回主页面,还有什么指令?";

music->close();

textToSpeech->say("已关闭音乐播放器窗口返回主页面,还有什么指令");
ui->startButton->click();//自动开启开始按钮
}else if (action == "播放" || action == "放"){
qDebug()<<"小亦:已为您默认播放第一首歌,还有什么指令?";

textToSpeech->say("好的,请您先选择文件夹");
music->openFolder();
music->playMusic();

textToSpeech->say("已为您默认播放第一首歌,还有什么指令");
ui->startButton->click();//自动开启开始按钮
}else if(action == "暂停" || action == "停止" || action == "停"){
qDebug()<<"小亦:已为您暂停播放,还有什么指令?";

music->playMusic();

textToSpeech->say("已为您暂停播放,还有什么指令");
ui->startButton->click();//自动开启开始按钮
}else{
qDebug()<<"小亦:没听清楚,请再说一遍指令?";
textToSpeech->say("不好意思,我没听清楚,请再说一遍指令");
ui->startButton->click();//自动开启开始按钮
}
} else {
qDebug() << "小亦:您没有说出想要执行的操作,请再说一遍,或者退出音乐播放器界面";
textToSpeech->say("您没有说出想要执行的操作,请再说一遍,或者退出音乐播放器界面");
ui->startButton->click();//自动开启开始按钮
}
}

void Widget::handleGps(const QMap<QString, QString> &smallwords)
{
//结束指令 退出子界面 返回主界面 导航到东莞市的路线

//判断是否要结束指令或退出页面(动词)
if (smallwords.contains("LOC")) {
QString loc = smallwords.value("LOC");
//执行查询到“loc”市路线的逻辑(出发默认广东省深圳市)
qDebug()<<"小亦:当前位置为广东省东莞市松山湖园区,已为您查询去往"+loc+"市的路线,还有什么指令?";

gps->startNowPlace(loc);

textToSpeech->say("当前位置为广东省东莞市松山湖园区,已为您查询去往"+loc+"市的路线,还有什么指令?");
ui->startButton->click();//自动开启开始按钮
}
else if(smallwords.contains("v")){
QString action = smallwords.value("v");
if(action =="结束"){
textToSpeech->say("指令结束,期待与您再次见面");
ui->endButton->click();//停留在当前界面且结束录音
}else if (action=="返回"||action == "退出") {
currentState = MAIN_STATE;

gps->close();

qDebug()<<"小亦:已关闭导航窗口返回主页面,还有什么指令?";
textToSpeech->say("已为您关闭导航窗口返回主页面,还有什么指令?");
ui->startButton->click();//自动开启开始按钮
}else{
qDebug()<<"小亦:没听清楚,请再说一遍指令?";
textToSpeech->say("不好意思,我没听清楚,请再说一遍指令");
ui->startButton->click();//自动开启开始按钮
}
}else {
qDebug() << "小亦:您没有说出想要导航的目的地,请再说一遍,或者选择退出子界面";
textToSpeech->say("您没有说出想要导航的目的地,请再说一遍,或者选择退出子界面");
ui->startButton->click();//自动开启开始按钮
}
}

void Widget::handleSettings(const QMap<QString, QString> &smallwords)
{
//结束指令 退出子界面 返回主界面 主题

//判断是否要结束指令或退出页面(动词)
if (smallwords.contains("else")) {
QString elsething = smallwords.value("else");
if(elsething == "白天"){
//更换主题为白天
qDebug()<<"小亦:已更换主题为白天,还有什么指令?";

//emit changeThemeSignal(2);
//changeBackground(2);//主线程阻塞了?

textToSpeech->say("已为您更换白天主题,还有什么指令?");
ui->startButton->click();//自动开启开始按钮
}else if(elsething == "夜晚"){
//更换主题为夜晚
qDebug()<<"小亦:已更换主题为夜晚,还有什么指令?";

//emit changeThemeSignal(1);
//setting->changeMainBackground(1);

textToSpeech->say("已为您更换夜晚主题,还有什么指令?");
ui->startButton->click();//自动开启开始按钮
}
}
else if(smallwords.contains("v")){
QString action = smallwords.value("v");
if(action =="结束"){
textToSpeech->say("指令结束,期待与您再次见面");
ui->endButton->click();//停留在当前界面且结束录音
}else if (action=="返回"||action == "退出") {
currentState = MAIN_STATE;

gps->close();

qDebug()<<"小亦:已关闭设置窗口返回主页面,还有什么指令?";
textToSpeech->say("已为您关闭设置窗口返回主页面,还有什么指令?");
ui->startButton->click();//自动开启开始按钮
}else{
qDebug()<<"小亦:没听清楚,请再说一遍指令?";
textToSpeech->say("不好意思,我没听清楚,请再说一遍指令");
ui->startButton->click();//自动开启开始按钮
}
}else {
qDebug() << "小亦:您没有说出想要更换的主题,请再说一遍,或者选择退出子界面";
textToSpeech->say("您没有说出想要更换的主题,请再说一遍,或者选择退出子界面");
ui->startButton->click();//自动开启开始按钮
}
}

//倒计时
void Widget::onTimerTimeout()
{
if (time <= 0) {
timer4->stop();
if (canEnd) {
ui->endButton->click(); //强制结束录音
}
} else {
ui->timeLabel->setText("还有 " + QString::number(time) + " 秒");
time--;
}
}

void Widget::on_Weather_clicked()
{
if (!weather)//防止创建多个窗口
weather = new Weather(this);
weather->show();
}

void Widget::on_Music_clicked()
{
if (!music)
music = new Music(this);
music->show();
}

void Widget::on_GPS_clicked()
{
if (!gps)
gps = new GPS(this);
gps->show();
}

void Widget::on_Setting_clicked()
{
if (!setting)
setting = new Setting(this);
setting->show();
}