当前位置: 首页 > news >正文

《基于Qt的车载系统项目》

基于Qt的车载系统项目

项目框架

在这里插入图片描述

本项目将实现五个功能

  1. 时间显示
  2. 音乐播放
  3. 视频播放
  4. 天气显示
  5. 地图显示

第一类就是定时器

第二类就是多媒体模块

第三类就是api的调用

接下来我将介绍功能实现方法,本博客仅介绍核心功能实现方法,涉及ui美化以及头文件包含将不多介绍,大家可以让ai辅助优化

1.跳转功能

这个应该是本项目最基本的一个功能,我们通过pushbutton通过点击跳转到对应界面,这里ui设计就不多介绍了,效果如下

在这里插入图片描述

同时我们还需要添加四个ui和h文件,分别对应四个模块,时间模块可以直接在widget下面显示,就不需要创建了

//初始化ui对象
misc=new music();
mp=new map();
vdo=new video();
wea=new weather();

这里以video模块为例,假设我们点击这个按钮进入界面,那我们这个槽函数就应该这么写

void Widget::on_video_button_clicked()
{this->hide();//隐藏widget界面vdo->show();//显示video模块ui
}

在后面我们还要对每个界面增加一个返回按钮,以至我们可以返回我们的主页面,同样以video模块为例,我们需要定义一个信号(发出信号,让widget显示 ui

void video::on_back_button_clicked()
{emit backToMain();//需要在h文件signal:定义this->hide();
}

widget需要接受信号并处理

connect(vdo,&video::backToMain,this,&Widget::show);

这样就实现了对应的功能

2.时间显示

实现显示就是通过定时器的中断函数更新并显示一次时间(跟stm32的中断有点像…)

//日期
connect(clockTimer, &QTimer::timeout, this, [=]() {QDateTime now = QDateTime::currentDateTime();ui->date_lable->setText(now.toString("yyyy-MM-dd ddd")); // 例:2025-08-13 Wedui->time_lable->setText(now.toString("HH:mm:ss"));       // 例:14:35:28
});
// 启动前先手动刷新一次(避免等 1 秒才出现)
QDateTime now = QDateTime::currentDateTime();
ui->date_lable->setText(now.toString("yyyy-MM-dd ddd"));
ui->time_lable->setText(now.toString("HH:mm:ss"));
//启动时钟
clockTimer->start(1000);

3.视频播放

先看看ui
在这里插入图片描述

定义一些对象

private:Ui::video *ui;                QMediaPlayer *qmp;            // 媒体播放器对象,用于播放音视频QMediaPlaylist *qmpl;         // 播放列表对象,用于管理多个媒体文件的播放顺序QVideoWidget *videoWidget;    // 视频显示控件,用于在界面上显示视频内容
qmp=new QMediaPlayer(this);
qmpl=new QMediaPlaylist(this);
videoWidget=new QVideoWidget(this);
qmp->setVideoOutput(videoWidget);//播放器对象需要配置
qmp->setPlaylist(qmpl);//同上

由于视频比较大,我们需要放在debug文件夹下面

1.音量调节

我们通过verticalSlider调节音量大小

connect(ui->verticalSlider, &QSlider::valueChanged, this, [=](int value){qmp->setVolume(value);  // QMediaPlayer 的音量 0~100});

2.列表加载

void video::loadVideoList()
{// 获取程序所在目录并拼接 music 文件夹QDir dir(QCoreApplication::applicationDirPath() + "/video");QStringList filters;filters << "*.mp4" ;//过滤QStringList files = dir.entryList(filters, QDir::Files);//只筛选文件,不包含文件夹for (const QString &file : files) {// listWidget 显示文件名ui->mp4listWidget->addItem(QFileInfo(file).baseName());// playlist 添加文件qmpl->addMedia(QUrl::fromLocalFile(dir.filePath(file)));}
}

3.播放与点击列表播放

//点击更换播放建图标
connect(ui->on_button, &QPushButton::clicked, this, [=](){if(qmp->state() == QMediaPlayer::PlayingState){qmp->pause();ui->on_button->setIcon(QIcon(":/images/on.png")); // 暂停图标} else {qmp->play();ui->on_button->setIcon(QIcon(":/images/stop.png"));  // 播放图标}});
//点击播放
connect(ui->mp4listWidget, &QListWidget::itemClicked, this, [=](QListWidgetItem *item){int index = ui->mp4listWidget->row(item);qmpl->setCurrentIndex(index);qmp->play();ui->on_button->setIcon(QIcon(":/images/stop.png"));ui->lineEdit->setText(item->text());});

第二段代码的作用是:
当用户点击 QListWidget 里的某个视频文件项时:

  1. 取到它的行号;
  2. 切换播放列表到这个视频;
  3. 开始播放;
  4. 更新按钮图标为“停止”;
  5. 在输入框显示当前视频的名字。

4.进度条

value:0-100%

pos:0-音乐时长(ms)

duration:完整音乐时长

这样换算就非常容易理解了

//进度条
//播放器播放时更新滑块
connect(qmp, &QMediaPlayer::positionChanged, this, [=](qint64 pos){if(qmp->duration() > 0){int value = static_cast<int>(pos * 100 / qmp->duration());ui->horizontalSlider->setValue(value);}
});//滑块拖动时更新播放器
connect(ui->horizontalSlider, &QSlider::sliderReleased, this, [=](){int value = ui->horizontalSlider->value();if(qmp->duration() > 0){qint64 newPos = value * qmp->duration() / 100;qmp->setPosition(newPos);}
});

4.音乐播放

先看看ui
在这里插入图片描述

我们可以发现这个和视频播放很像,无非就多了上一首、下一首,以及mode(单曲循环,随机播放,下一首)

1.进度和音量

其实是一模一样

//音量
connect(ui->verticalSlider, &QSlider::valueChanged, this, [=](int value){player->setVolume(value);  // QMediaPlayer 的音量 0~100
});
//进度条
//播放器播放时更新滑块
connect(player, &QMediaPlayer::positionChanged, this, [=](qint64 pos){if(player->duration() > 0){int value = static_cast<int>(pos * 100 / player->duration());ui->horizontalSlider->setValue(value);}
});//滑块拖动时更新播放器
connect(ui->horizontalSlider, &QSlider::sliderReleased, this, [=](){int value = ui->horizontalSlider->value();if(player->duration() > 0){qint64 newPos = value * player->duration() / 100;player->setPosition(newPos);}
});

2.加载列表

void music::loadMusicList()
{
// 获取程序所在目录并拼接 music 文件夹
QDir dir(QCoreApplication::applicationDirPath() + "/music");
QStringList filters;
filters << "*.mp3" << "*.wav";//筛选
QStringList files = dir.entryList(filters, QDir::Files);for (const QString &file : files) {// listWidget 显示文件名ui->mp3listWidget->addItem(QFileInfo(file).baseName());// playlist 添加文件playlist->addMedia(QUrl::fromLocalFile(dir.filePath(file)));
}
}

3.播放模式转换

/播放模式
connect(ui->mode_button, &QPushButton::clicked, this, [=](){switch(playlist->playbackMode()){case QMediaPlaylist::Loop:playlist->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);//单曲ui->mode_button->setIcon(QIcon(":/images/danqu.png"));break;case QMediaPlaylist::CurrentItemInLoop:playlist->setPlaybackMode(QMediaPlaylist::Random);//随机ui->mode_button->setIcon(QIcon(":/images/suiji.png"));break;case QMediaPlaylist::Random:default:playlist->setPlaybackMode(QMediaPlaylist::Loop);//循环ui->mode_button->setIcon(QIcon(":/images/xunhuan.png"));break;}

4.播放与点击列表播放

connect(ui->on_button, &QPushButton::clicked, this, [=](){if(player->state() == QMediaPlayer::PlayingState){player->pause();ui->on_button->setIcon(QIcon(":/images/on.png")); // 暂停图标} else {player->play();ui->on_button->setIcon(QIcon(":/images/stop.png"));  // 播放图标}});//点击播放
connect(ui->mp3listWidget, &QListWidget::itemClicked, this, [=](QListWidgetItem *item){int index = ui->mp3listWidget->row(item);playlist->setCurrentIndex(index);player->play();ui->on_button->setIcon(QIcon(":/images/stop.png"));ui->lineEdit->setText(item->text());
});//list显示播放歌曲
connect(playlist, &QMediaPlaylist::currentIndexChanged, this, [=](int index){if(index >= 0 && index < ui->mp3listWidget->count()){// 高亮当前播放歌曲ui->mp3listWidget->setCurrentRow(index);// 显示歌曲名ui->lineEdit->setText(ui->mp3listWidget->item(index)->text());}
});

5.上一首下一首

connect(ui->prev_button, &QPushButton::clicked, this, [=]() { playlist->previous();});
connect(ui->next_button, &QPushButton::clicked, this, [=]() { playlist->next();});

6.地图显示

看看ui

在这里插入图片描述

这个模块主要是 Qt 端 与高德地图 HTML/JS 页面交互,实现输入搜索、联想提示和路线绘制 的逻辑

开发文档


1.初始化地图和网络访问

mapView = new QWebEngineView(this);
manager = new QNetworkAccessManager(this);QString htmlPath = QCoreApplication::applicationDirPath() + "/map/map.html";
mapView->load(QUrl::fromLocalFile(htmlPath));
mapView->setGeometry(10, 10, 671, 651);
mapView->show();
  • mapView:嵌入一个 Web 引擎视图,用来显示高德地图的 HTML 页面。
  • manager:用于发送 HTTP 请求(调用高德输入提示接口)。
  • load:加载本地的 map.html 文件(你之前贴的 HTML/JS)。
  • setGeometry/show:设置大小并显示。

2.输入框联想与信号连接

connect(ui->start_lineEdit, &QLineEdit::textChanged, this, &map::searchRoute);
connect(ui->final_lineEdit, &QLineEdit::textChanged, this, &map::searchRoute);
  • 当用户在 起点/终点输入框 输入文字时,触发 searchRoute()
  • 功能:发送高德 输入提示接口 请求,获取联想建议。

3.联想列表点击事件

connect(ui->start_listWidget, &QListWidget::itemClicked, this, &map::onStartListClicked);
connect(ui->final_listWidget, &QListWidget::itemClicked, this, &map::onEndListClicked);
  • 当用户点击联想列表里的某一项时:
    • 填充输入框
    • 保存选中经纬度
    • 调用 JS 接口在地图上添加起点/终点标记

4 .搜索路线按钮

connect(ui->research_button, &QPushButton::clicked, this, &map::on_research_button_clicked);
  • 点击“搜索路线”按钮时,调用 on_research_button_clicked()
  • 功能:在地图上绘制起点到终点的路线(调用 JS 的 drawRoute())。

5.searchRoute() 函数

void map::searchRoute()
{QString start = ui->start_lineEdit->text();QString end = ui->final_lineEdit->text();// 起点联想if(!start.isEmpty()){QUrl startUrl("https://restapi.amap.com/v3/assistant/inputtips");QUrlQuery query;query.addQueryItem("key", AMAP_KEY);query.addQueryItem("keywords", start);query.addQueryItem("city", "全国");startUrl.setQuery(query);QNetworkReply *reply = manager->get(QNetworkRequest(startUrl));connect(reply, &QNetworkReply::finished, [=](){ handleStartTipsReply(reply); });}// 终点联想同理
}
  • 作用:向高德输入提示接口发送 HTTP GET 请求
  • 参数
    • key:你的高德地图开发者 Key
    • keywords:用户输入的文字
    • city:限制搜索城市,这里是全国
  • 返回结果会在 handleStartTipsReply / handleEndTipsReply 处理。

6.处理联想结果

void map::handleStartTipsReply(QNetworkReply *reply)
{QByteArray data = reply->readAll();reply->deleteLater();QJsonDocument doc = QJsonDocument::fromJson(data);QJsonArray tips = doc.object()["tips"].toArray();ui->start_listWidget->clear();for(auto tip : tips){QString name = tip.toObject()["name"].toString();QString location = tip.toObject()["location"].toString(); // "lng,lat"QListWidgetItem *item = new QListWidgetItem(name, ui->start_listWidget);item->setData(Qt::UserRole, location);ui->start_listWidget->addItem(item);}
}
  • 作用:把高德返回的联想结果解析出来,显示到 QListWidget
  • location(经纬度)保存到 UserRole 数据中,方便后续在地图上使用。

7.联想列表点击处理

void map::onStartListClicked(QListWidgetItem *item)
{ui->start_lineEdit->setText(item->text());startLocation = item->data(Qt::UserRole).toString(); // 保存选中经纬度mapView->page()->runJavaScript(QString("updateStart('%1')").arg(startLocation));
}
  • 更新输入框文本
  • 保存 经纬度 到成员变量 startLocation
  • 调用 HTML/JS 接口 updateStart() 在地图上添加标记
  • 终点处理类似,调用 updateEnd()

8.搜索路线按钮处理

void map::on_research_button_clicked()
{if(startLocation.isEmpty() || endLocation.isEmpty()) return;QString js = QString("drawRoute('%1','%2')").arg(startLocation).arg(endLocation);mapView->page()->runJavaScript(js);
}
  • 使用保存的经纬度,而不是输入框文字
  • 调用 JS drawRoute(startLoc, endLoc) 绘制路线
  • 地图上显示起点、终点和一条红色直线路径。

9.内嵌html源码

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>高德地图示例</title>
<script src="https://webapi.amap.com/maps?v=2.0&key=<your_key>"></script>
<style>
html, body, #container { margin:0; padding:0; width:100%; height:100%; }
</style>
</head>
<body>
<div id="container"></div><script>
var map = new AMap.Map('container',{center: [120.1551,30.2741],zoom: 11
});var startMarker, endMarker, routeLine;// 添加起点标记
function addStartMarker(lng, lat, name){if(startMarker) map.remove(startMarker);startMarker = new AMap.Marker({position: [lng, lat],title: name,icon: "https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png"});map.add(startMarker);
}// 添加终点标记
function addEndMarker(lng, lat, name){if(endMarker) map.remove(endMarker);endMarker = new AMap.Marker({position: [lng, lat],title: name,icon: "https://webapi.amap.com/theme/v1.3/markers/n/mark_r.png"});map.add(endMarker);
}// 更新起点(供 Qt 调用)
function updateStart(loc){if(!loc) return;var parts = loc.split(',');if(parts.length !== 2) return;var lng = parseFloat(parts[0]);var lat = parseFloat(parts[1]);if(isNaN(lng) || isNaN(lat)) return;addStartMarker(lng, lat, "起点");
}// 更新终点(供 Qt 调用)
function updateEnd(loc){if(!loc) return;var parts = loc.split(',');if(parts.length !== 2) return;var lng = parseFloat(parts[0]);var lat = parseFloat(parts[1]);if(isNaN(lng) || isNaN(lat)) return;addEndMarker(lng, lat, "终点");
}// 绘制路线(直线示意)
function drawRoute(startLoc, endLoc){if(!startLoc || !endLoc) return;var s = startLoc.split(',');var e = endLoc.split(',');if(s.length !== 2 || e.length !== 2) return;var start = [parseFloat(s[0]), parseFloat(s[1])];var end = [parseFloat(e[0]), parseFloat(e[1])];if(start.some(isNaN) || end.some(isNaN)) return;// 移除之前的路线if(routeLine) map.remove(routeLine);// 确保标记存在addStartMarker(start[0], start[1], "起点");addEndMarker(end[0], end[1], "终点");// 绘制直线路线routeLine = new AMap.Polyline({path: [start, end],strokeColor: "#FF0000",strokeWeight: 3});map.add(routeLine);// 自动调整视野map.setFitView([startMarker, endMarker]);
}
</script>
</body>
</html>

7.天气

我这里也是调用的高德api,其实可以换一个好一点的,它就是发送请求获得数据,我们分析json文本,自己设计格式

直接放源码了,有注释

weather::weather(QWidget *parent) :QWidget(parent),ui(new Ui::weather)
{ui->setupUi(this);// 背景this->setStyleSheet("background-color: #787FBF;");// 对象初始化mapView = new QWebEngineView(this);manager = new QNetworkAccessManager(this);QString htmlPath = QCoreApplication::applicationDirPath() + "/weather/weather.html";mapView->load(QUrl::fromLocalFile(htmlPath));mapView->setGeometry(0, 59, 1071, 471);mapView->show();// 直接加载默认城市(杭州)天气getWeatherByCity("杭州");
}weather::~weather()
{delete ui;
}// 获取城市 adcode
void weather::getWeatherByCity(const QString &cityName)
{QUrl url("https://restapi.amap.com/v3/geocode/geo");QUrlQuery query;query.addQueryItem("key", WEA_KEY);query.addQueryItem("address", cityName);url.setQuery(query);QNetworkReply *reply = manager->get(QNetworkRequest(url));connect(reply, &QNetworkReply::finished, this, [=]() {QByteArray data = reply->readAll();reply->deleteLater();QJsonDocument doc = QJsonDocument::fromJson(data);QJsonArray geocodes = doc.object()["geocodes"].toArray();if(!geocodes.isEmpty()) {QString adcode = geocodes[0].toObject()["adcode"].toString();if (!adcode.isEmpty()) {fetchWeather(adcode);}}});
}// 获取天气信息
void weather::fetchWeather(const QString &adcode)
{QUrl url("https://restapi.amap.com/v3/weather/weatherInfo");QUrlQuery query;query.addQueryItem("key", WEA_KEY);query.addQueryItem("city", adcode);query.addQueryItem("extensions", "all");url.setQuery(query);QNetworkReply *reply = manager->get(QNetworkRequest(url));connect(reply, &QNetworkReply::finished, this, [=]() {QByteArray data = reply->readAll();reply->deleteLater();QString jsonStr = QString::fromUtf8(data);// 转义单引号jsonStr.replace("'", "\\'");QString jsCode = QString("updateWeatherData('%1')").arg(jsonStr);mapView->page()->runJavaScript(jsCode);});
}// 点击搜索按钮
void weather::on_search_button_clicked()
{QString cityName = ui->lineEdit->text().trimmed();if (!cityName.isEmpty()) {getWeatherByCity(cityName);}
}

html源码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>天气预报</title>
<style>body {font-family: "微软雅黑", sans-serif;background-color: #787FBF;color: #fff;margin: 0;padding: 10px;}h1, h2 {margin: 0 0 10px 0;}#current {margin-bottom: 20px;font-size: 16px;}#forecast {border-collapse: collapse;width: 100%;font-size: 14px;}#forecast th, #forecast td {border: 1px solid #fff;padding: 5px 10px;text-align: left;}#forecast th {background-color: rgba(255,255,255,0.2);}
</style>
</head>
<body><h1 id="city">城市</h1>
<div id="current"><p>温度:<span id="temp">--</span>°C</p><p>天气:<span id="weather">--</span></p>
</div><h2>未来预报:</h2>
<table id="forecast"><thead><tr><th>日期</th><th>白天 / 夜晚天气</th><th>温度</th></tr></thead><tbody><!-- JS 动态生成内容 --></tbody>
</table><script>
function updateWeatherData(jsonStr) {try {let data = JSON.parse(jsonStr);// 城市let city = data["city"] || (data["forecasts"] && data["forecasts"][0]["city"]) || "未知";document.getElementById("city").innerText = city;// 当前温度/天气let weatherNow = (data["lives"] && data["lives"].length>0) ? data["lives"][0] : null;let temp = "--", weather = "--";if(weatherNow) {temp = weatherNow["temperature"] || "--";weather = weatherNow["weather"] || "--";} else if(data["forecasts"] && data["forecasts"].length>0) {let cast = data["forecasts"][0]["casts"][0];if(cast) {temp = cast["daytemp"] || "--";weather = cast["dayweather"] || "--";}}document.getElementById("temp").innerText = temp;document.getElementById("weather").innerText = weather;// 未来天气表格let tbody = document.getElementById("forecast").getElementsByTagName("tbody")[0];tbody.innerHTML = "";let forecasts = data["forecasts"] || [];forecasts.forEach(f => {f["casts"].forEach(cast => {let tr = document.createElement("tr");tr.innerHTML = `<td>${cast["date"] || "--"} (${cast["week"] || "--"})</td><td>白天 ${cast["dayweather"] || "--"}, 夜晚 ${cast["nightweather"] || "--"}</td><td>${cast["daytemp"] || "--"}~${cast["nighttemp"] || "--"}°C</td>`;tbody.appendChild(tr);});});} catch(e) {console.error("解析天气 JSON 出错:", e);}
}
</script></body>
</html>

总结

项目主要功能就是这些,地图和天气部分有点难以理解,后续我会发布一篇关于qt和api搭配的博客,感谢你的浏览

http://www.dtcms.com/a/403967.html

相关文章:

  • 有哪些免费推广软件网站seo推广排名
  • 41.传输层协议UDP
  • 优良的定制网站建设提供商c2c模式的网站
  • 记力扣2516.每种字符至少取k个 练习理解
  • 广州站电话科创纵横 网站建设
  • 进程与集群:提升性能
  • 北京建设信源官方网站如何让wordpress文本小工具支持php和简码?
  • NLP算法岗位面试题精讲:深入理解LoRA与QLoRA
  • 基于神经控制微分方程的采集无关深度学习用于定量MRI参数估计|文献速递-文献分享
  • 无锡嘉饰茂建设网站的公司天河区网站制作
  • 应用程序映像(Application Image)是什么?
  • 访问的网站显示建设中wordpress tag伪静态
  • 单调速率调度(RMS)算法
  • 百度智能云一念·智能创作平台
  • 做网站订阅号丰台建设企业网站
  • shell编程:sed - 流编辑器(2)
  • 在Grafana中配置MySQL数据源并创建查询面板
  • 做的比较好的二手交易网站有哪些小学学校网站建设计划书
  • OneSignal v2 PHP手搓请求消息推送-供参考
  • 中国建站公司wordpress主题 下单
  • Qt DPI相关逻辑
  • 约束优化问题的常用解决办法及优缺点、轨迹规划中应用
  • 电子元器件基础知识day1
  • 【C++游记】C++11特性
  • 光子、光量子、量子三者的关系
  • 网站更改目录做301承德信息网络有限公司
  • Pytorch中stack()方法的总结及理解
  • 网站建设需要那种技术开一个网站多少钱
  • 在windows系统如何使用docker将nginx容器化部署
  • 【异世界历险之数据结构世界(二叉搜索树)】