QT--使用百度地图API显示地图并绘制路线
- 前言
- 准备工作
- 申请百度地图密钥(AK)
- 安装开发环境
- 开发过程
- 新建项目
- ui界面
- GPSManager类
- 主窗口
- Map
- 效果展示
前言
先吐槽一下下,本身qt学的就不咋滴,谁想到第一件事就是让写一个上位机工具,根据CAN总线传来的位置信息,在地图上去绘制路线,并获取当前路段的限速信息等。当听到这个需求的时候,第一时间是有点懵逼的。自己原本是没接触过这方面的知识,而且qt学的也特别的垃圾,但是以我的性格还是答应了下来。最终也是花了几天的时间做了出来。通过做这个简单的小工具,自己也学到了还能多。接下来我就简单说一说如何使用百度地图API来显示地图并根据位置信息绘制路线这一功能。其他的就不方便说了。
准备工作
申请百度地图密钥(AK)
在使用百度地图之前,我们需要拥有一个自己的百度账号,申请注册成为百度开发者,然后我们需要创建一个浏览器端应用,就可以获取到一个唯一的服务秘钥(AK)
具体的步骤小伙伴们可以去看一些其他博主的文章,这里我就不详细的去说了。
安装开发环境
说到开发环境,这里我踩了很多的坑啊,这里我来强调一下。
首先我的qt版本是5.14.2,在安装QT的时候一定把MSVC2017给选上!!!不然后面写代码导入模块时会出错的。
还有就是一定要安装一个Visual Studio 2017,因为我QT上是MSVC2017,所以这里我安装的是Visual Studio 2017。
如果环境搞得差不多了,就可以进行下面的开发了。
开发过程
新建项目
打开QT新建一个Application,在Kits页面将MSVC2017勾选上,如下图:
新建完成后,打开.pro文件添加如下代码:
QT +=webenginewidgets
重新构建一下项目,如果出现错误,请检查前面的开发环境。
ui界面
其中包括三个QLabel用来显示信息,分别是GPS信息,Speed信息,和绘制情况信息,一个按钮,来触发绘制,还有一个webEngineView,这个需要在Designer下拖拽上去。
GPSManager类
一、gpsmanager.h
#ifndef GPSMANAGER_H
#define GPSMANAGER_H
#include <QObject>
#include <QWebEngineView>
class GPSManager : public QObject
{
Q_OBJECT
public:
explicit GPSManager(QObject *parent = nullptr);
signals:
void routeDrawn();
void speedLimitReceived(int limit);
void gpsUpdated(double latitude, double longitude);
public slots:
void drawRoute(QWebEnginePage *webPage);
void setGPSLocation(double latitude, double longitude);
public:
int getSpeedLimit(double latitude, double longitude);
private:
double currentLatitude;
double currentLongitude;
};
#endif // GPSMANAGER_H
这个类旨在处理Qt应用程序中与GPS相关的功能。它发射信号以通知应用程序其他部分有关路线绘制、速度限制更新和GPS坐标更改的信息,并提供槽和函数来执行这些操作。
二、gpsmanager.cpp
构造函数:
GPSManager::GPSManager(QObject *parent) : QObject(parent)
{
currentLatitude = 0.0;
currentLongitude = 0.0;
}
这是 GPSManager 类的构造函数。它初始化了 currentLatitude 和 currentLongitude 两个成员变量为0.0。
drawRoute 函数:
void GPSManager::drawRoute(QWebEnginePage *webPage)
{
// 在这里触发在 HTML 页面中编写的 JavaScript 代码来绘制路线
QString javascriptCode = QString("drawNewPoint(%1, %2);").arg(currentLatitude).arg(currentLongitude);
if (webPage) {
// 执行 JavaScript 代码
webPage->runJavaScript(javascriptCode);
qDebug() << javascriptCode << endl;
}
// 获取限速信息并触发信号
int speedLimit = getSpeedLimit(currentLatitude, currentLongitude);
emit speedLimitReceived(speedLimit);
// 触发路线绘制完成的信号
emit routeDrawn();
}
这个函数用于绘制路线。它构建一个包含纬度和经度信息的 JavaScript 代码字符串,然后通过 QWebEnginePage 对象的 runJavaScript 方法在 HTML 页面中执行该代码。接着,它调用 getSpeedLimit 函数获取速度限制信息,并通过 emit 发射 speedLimitReceived 信号,以及发射 routeDrawn 信号表示路线绘制完成。
setGPSLocation 函数
void GPSManager::setGPSLocation(double latitude, double longitude)
{
// 设置 GPS 位置
currentLatitude = latitude;
currentLongitude = longitude;
emit gpsUpdated(currentLatitude, currentLongitude);
qDebug("setGPSLocation");
}
这个函数用于设置 GPS 的位置信息。它接受纬度和经度作为参数,并将这些值存储在 currentLatitude 和 currentLongitude 成员变量中。然后,它通过 emit 发射 gpsUpdated 信号表示 GPS 位置已更新。
getSpeedLimit 函数:
int GPSManager::getSpeedLimit(double latitude, double longitude)
{
// 在这里查询限速信息,这是一个示例
// 实际上,你需要与地图数据提供商的API进行交互来获取限速信息
// 这里我们模拟返回一个随机的限速值作为示例
int randomSpeedLimit = QRandomGenerator::global()->bounded(30, 110); // 生成30到109之间的随机数
return randomSpeedLimit;
}
这个函数用于获取速度限制信息。它是一个示例函数,实际中你需要与地图数据提供商的API进行交互来获取真实的速度限制信息。在示例中,它返回一个随机的速度限制值,范围在30到109之间。
主窗口
一、mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWebEngineView>
#include <QtWebChannel>
#include "gpsmanager.h"
#include <QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
//QWebEngineView *mapView;
GPSManager *gpsManager;
QTimer *timer;
private slots:
void onGpsUpdated(double latitude, double longitude);
void onRouteDrawn();
void onSpeedLimitReceived(int limit);
void on_pushButton_clicked();
void onTimerTimeout();
};
#endif // MAINWINDOW_H
这个头文件定义了 MainWindow 类,该类是 Qt C++ 应用程序的主窗口。它包含了一些成员变量,包括用户界面对象、GPS 管理器和定时器,以及一些用于处理信号和事件的槽函数。这些槽函数用于响应与 GPS 更新、路线绘制、速度限制等相关的事件。
二、mainwindow.cpp
构造函数:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 创建GPSManager对象
gpsManager = new GPSManager(this);
// 连接GPSManager的信号与MainWindow的槽函数
connect(gpsManager, &GPSManager::gpsUpdated, this, &MainWindow::onGpsUpdated);
connect(gpsManager, &GPSManager::routeDrawn, this, &MainWindow::onRouteDrawn);
connect(gpsManager, &GPSManager::speedLimitReceived, this, &MainWindow::onSpeedLimitReceived);
ui->webEngineView->setUrl(QUrl("D:/QtCode/Google/map.html"));
timer = new QTimer(this);
timer->setInterval(5000);
}
这是 MainWindow 类的构造函数。在其中,进行了如下操作:
初始化用户界面 (ui->setupUi(this))。
创建 GPSManager 对象,用于处理 GPS 相关的操作。
连接 GPSManager 的信号与 MainWindow 的槽函数,以便在 GPS 更新、路线绘制和速度限制接收时执行相应操作。
设置 QWebEngineView 显示的网页 URL。
创建一个定时器 timer,并设置其定时间隔为 5000 毫秒(5秒)。
析构函数:
MainWindow::~MainWindow()
{
delete ui;
delete gpsManager;
delete timer; // 释放定时器对象
}
这是 MainWindow 类的析构函数,用于释放动态分配的对象,包括用户界面对象 (ui)、GPSManager 对象和定时器对象。
槽函数 onGpsUpdated:
void MainWindow::onGpsUpdated(double longitude, double latitude)
{
// 在这里可以更新UI以显示当前GPS坐标
// 例如,更新UI的标签或其他元素
qDebug("onGpsUpdated");
ui->gps->setText(QString::number(longitude, 'f', 10) + " " + QString::number(latitude, 'f', 10));
}
这个槽函数用于处理 GPS 更新事件,更新用户界面上显示的 GPS 坐标信息。
槽函数 onRouteDrawn:
void MainWindow::onRouteDrawn()
{
// 在这里可以执行与路线绘制相关的操作
// 例如,显示路线的标签或其他元素
ui->route->setText("正在绘制路线...");
}
这个槽函数用于处理路线绘制完成事件,更新用户界面上显示的信息。
槽函数 onSpeedLimitReceived:
void MainWindow::onSpeedLimitReceived(int limit)
{
// 在这里可以更新UI以显示限速信息
// 例如,显示限速信息的标签或其他元素
ui->speed->setText("Speed Limit:" + QString::number(limit));
}
这个槽函数用于处理速度限制接收事件,更新用户界面上显示的限速信息。
槽函数 on_pushButton_clicked:
void MainWindow::on_pushButton_clicked()
{
if (ui->pushButton->text() == "绘制") {
connect(timer, &QTimer::timeout, this, &MainWindow::onTimerTimeout);
timer->start();
ui->pushButton->setText("取消绘制");
} else {
ui->pushButton->setText("绘制");
timer->stop();
ui->route->setText("");
}
}
这个槽函数用于处理按钮点击事件。如果按钮上的文本是 “绘制”,则连接定时器的超时信号到 onTimerTimeout 槽函数,并启动定时器以触发路线绘制。如果按钮上的文本是 “取消绘制”,则停止定时器并重置界面上显示的路线信息。
槽函数 onTimerTimeout:
void MainWindow::onTimerTimeout()
{
// 在定时器槽函数中调用gpsManager的函数
lng = lng - 0.0003;
lat = lat - 0.0003;
gpsManager->setGPSLocation(lng, lat);
gpsManager->drawRoute(ui->webEngineView->page());
qDebug("%.10f %.10f", lng, lat);
}
这个槽函数用于处理定时器超时事件。在超时时,它调用 gpsManager 的函数来模拟 GPS 位置的变化,并触发路线绘制。在示例中,lng 和 lat 分别减小了0.0003,表示模拟GPS位置的移动。
Map
map.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>运输轨迹图</title>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=key"></script>
</head>
<body>
<div style="width:100%; height:100vh; border:1px solid gray" id="container"></div>
<script type="text/javascript">
var map; // 保存地图对象
var polyline; // 保存绘制的路线
var points = []; // 保存所有点坐标
// 创建地图函数
function createMap() {
// 如果地图对象不存在,创建地图
map = new BMap.Map("container");
map.centerAndZoom(new BMap.Point(116.404, 39.915), 13);
map.addControl(new BMap.NavigationControl()); // 添加平移缩放控件
map.addControl(new BMap.ScaleControl()); // 添加比例尺控件
map.addControl(new BMap.OverviewMapControl()); // 添加缩略地图控件
map.enableScrollWheelZoom(true);
// 初始化地图大小
resizeMap();
// 监听窗口大小变化事件,以动态调整地图大小
window.addEventListener("resize", resizeMap);
}
// 初始化地图
createMap();
// 定义绘制路线的函数
function drawRoute() {
// 生成坐标点
var trackPoint = [];
for (var i = 0; i < points.length; i++) {
trackPoint.push(new BMap.Point(points[i].lng, points[i].lat));
}
// 如果路线已存在,先清除
//if (polyline) {
// map.removeOverlay(polyline);
//}
// 创建路线
polyline = new BMap.Polyline(trackPoint, {strokeColor:"green", strokeWeight:6, strokeOpacity:1});
map.addOverlay(polyline);
}
// 定义绘制新点的函数
function drawNewPoint(lng, lat) {
// 添加新的点坐标到 points 数组中
var newPoint = { lng: lng, lat: lat };
points.push(newPoint);
// 如果超过最大长度,删除最早的点坐标
if (points.length > 10) {
points.splice(0, points.length - 10);
}
// 调用绘制路线函数以绘制新的路线
drawRoute();
// 获取最后一个点的坐标
var lastPoint = new BMap.Point(lng, lat);
// 计算地图视野以包含整个路线
var view = map.getViewport(points);
// 调整视野以确保最后一个点在地图中央
var centerPoint = view.center;
map.centerAndZoom(centerPoint, view.zoom);
map.setCenter(lastPoint);
}
// 自适应地图大小
function resizeMap() {
var container = document.getElementById("container");
var viewportWidth = window.innerWidth || document.documentElement.clientWidth;
var viewportHeight = window.innerHeight || document.documentElement.clientHeight;
container.style.width = viewportWidth + "px";
container.style.height = viewportHeight + "px";
map.setViewport();
}
</script>
</body>
</html>