Qt加载百度地图详细流程(附带报错解决方法)

发布于:2025-09-12 ⋅ 阅读:(17) ⋅ 点赞:(0)

作者:求一个demo

版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

内容通俗易懂,废话不多说,我们直接开始------>>>>>>

!!!!!!成果展示!!!!!!

一、创建一个Qt工程(QWidget/QMainWindow均可)

我的Qt环境:Qt是5.14.2,Qt Creator是4.11.1。

(此处以创建QMainWindow为例)

二、在百度地图开发者平台获取密钥

1、首先在“百度地图开放平台”注册一个账号,链接:百度地图-百万开发者首选的地图服务商,提供专属的行业解决方案

2、选择控制台

3、点击“应用管理”—“我的应用”—“创建应用”。

4、应用类型一定要选择“浏览器端”,Referer白名单的话,如果自己没有专门的需求,填一个星号*就行,然后保存自己的AK。

三、创建网页html,并放在相应位置

此处博主创建名为“index.html”的文件,代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>BDMap Sample</title>
    <style type="text/css">
        html{height:100%}
        body{height:100%;margin:0px;padding:0px}
        #container{height:100%} /* 确保地图容器占满QWebEngineView */
    </style>
    <!-- 1. 加载百度地图 JS API v3(非WebGL,兼容性更好) -->
    <script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=tSE1tEJjbMzrknZMAQgoj5A"></script>
    <!-- 2. 加载QWebChannel(使用qrc资源路径,避免绝对路径问题) -->
    <script type="text/javascript" src="qrc:/qtchannel/qwebchannel.js"></script>
</head>
<body>
    <div id="container"></div>

    <script type="text/javascript">
        // 3. 先初始化QWebChannel,再初始化地图(确保交互通道就绪)
        var JSInterface = null;
        new QWebChannel(qt.webChannelTransport, function(channel) {
            JSInterface = channel.objects.JSInterface; // 获取Qt注册的交互对象
            JSInterface.logFromJS("QWebChannel初始化成功"); // 通知Qt交互就绪

            // 4. QWebChannel就绪后,再初始化百度地图(避免阻塞)
            initBaiduMap();
        });

        // 5. 百度地图初始化函数(独立封装,逻辑清晰)
        function initBaiduMap() {
    try {
        if (typeof BMap === 'undefined') {
            console && console.error && console.error('BMap 未加载,检查网络或AK');
            if (JSInterface && JSInterface.logFromJS) JSInterface.logFromJS('BMap 未加载,可能是网络或AK问题');
            return;
        }
        var map = new BMap.Map("container");
        
        // 沈阳浑南区默认坐标(作为定位失败的备选)
        var defaultPoint = new BMap.Point(123.431982, 41.766281);
        
        // 初始化地图(先显示默认位置)
        map.centerAndZoom(defaultPoint, 15);
        map.enableScrollWheelZoom(true);

        // IP定位获取当前位置
        var geolocation = new BMap.Geolocation();
        geolocation.getCurrentPosition(function(r) {
            if (this.getStatus() == BMAP_STATUS_SUCCESS) {
                // 定位成功,移动到当前位置
                var currentPoint = r.point;
                map.panTo(currentPoint);
                
                // 添加当前位置标注
                var marker = new BMap.Marker(currentPoint);
                map.addOverlay(marker);
                
                // 显示定位信息
                var infoWindow = new BMap.InfoWindow(
                    "当前位置:<br/>经度:" + currentPoint.lng + "<br/>纬度:" + currentPoint.lat,
                    {width: 200, height: 100, title: "定位成功"}
                );
                marker.addEventListener("click", function() {
                    map.openInfoWindow(infoWindow, currentPoint);
                });
                
                JSInterface.logFromJS("定位成功:(" + currentPoint.lng + "," + currentPoint.lat + ")");
            } else {
                // 定位失败,使用默认坐标(沈阳浑南)
                JSInterface.logFromJS("定位失败,错误码:" + this.getStatus() + ",使用默认位置");
                
                var marker = new BMap.Marker(defaultPoint);
                map.addOverlay(marker);
            }
        }, {enableHighAccuracy: true}); // 启用高精度定位

        window.map = map; // 将地图实例挂载到window,供addMarker使用
        JSInterface.logFromJS("百度地图初始化成功");
    } catch (e) {
        JSInterface.logFromJS("地图初始化异常:" + e.message);
    }
}

        // 6. 简化addMarker函数(移除无意义的alert,避免阻塞)
        function addMarker(lng, lat) {
            if (!window.map) {
                JSInterface.logFromJS("addMarker失败:地图未初始化");
                return;
            }
            var newPoint = new BMap.Point(lng, lat);
            var newMarker = new BMap.Marker(newPoint);
            window.map.addOverlay(newMarker);
            JSInterface.logFromJS("添加标注成功:(" + lng + "," + lat + ")");
        }

        // 全局错误日志
        window.onerror = function(message, source, lineno, colno, error) {
            try {
                if (JSInterface && JSInterface.logFromJS) {
                    JSInterface.logFromJS('JS错误: ' + message + ' @' + source + ':' + lineno + ':' + colno);
                }
            } catch (e) {}
        };
    </script>
</body>
</html>

下面截图将告诉html中哪些地方需要修改:

四、配置相关资源文件

1、首先,找到自己相关路径下的qwebchannel.js文件(例如我的路径是E:\perfect\qt5.14.2\Examples\Qt-5.14.2\webchannel\shared\qwebchannel.js),将其放到你的工程文件根目录(也就是你各个类代码文件的位置,如下图)。(释:qwebchannel.js能够让你的Qt工程和JS文件进行通信)。

2、为了方便管理工程的静态资源文件(qwebchannel.js),将其打包到可执行程序中(打包成qrc文件),避免程序运行时依赖外部文件路径,提高项目可移植性和稳定性。步骤如下:

3、在html文件中添加你的qrc资源文件路径,便于Qt和JS通信。

4、创建Qt中的ui,并进行相关配置。(释:将Widget控件提升为QWebEngineView,是因为QWebEngineView支持网页渲染与交互能力。它支持加载 HTML、JS、CSS,实现网页交互。)

5、别忘记在.pro文件中加入下面这段代码(释:目的是为了引入Qt WebEngine模块,让项目能使用QWebEngineView等网页相关的类。):

QT += webenginewidgets

五、编写Qt代码

项目结构如下:

1、MagImageProDisplay.pro代码如下:

QT       += core gui
QT += webenginewidgets

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

# 交互类源文件
SOURCES += \
    jsinterface.cpp \
    main.cpp \
    mainwindow.cpp

# 交互类头文件
HEADERS += \
    jsinterface.h \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    qwebchannelresources.qrc

2、创建JSInterface类(JSInterface 是一个桥梁类,用于实现 C++ 与 JavaScript 之间的双向通信),代码中有详细注释。

(1)JSInterface.h如下:

#ifndef JSINTERFACE_H
#define JSINTERFACE_H
#include <QObject>
#include <QDebug>

class JSInterface : public QObject
{
    Q_OBJECT
public:
    explicit JSInterface(QObject *parent = nullptr);

// (可添加供HTML调用的方法,如后续扩展功能)
public slots:
    void logFromJS(const QString &msg) {
        qDebug() << "[HTML Log]:" << msg; // 接收HTML日志,辅助调试
    }
};

#endif // JSINTERFACE_H

/*
JSInterface 是一个桥梁类,用于实现 C++ 与 JavaScript 之间的双向通信:
1、让网页中的 JS 代码能够调用 C++ 方法;
2、处理从网页发送过来的数据或命令;
3、在 C++ 端对来自网页的数据进行安全验证;
4、执行需要在 C++ 端处理的核心功能。

如果去掉此类,WebChannel失去意义:
QWebChannel 需要注册 QObject 才能工作,没有注册对象,WebChannel 就只是一个空通道。
*/

(2)JSInterface.cpp如下:

#include "JSInterface.h"

JSInterface::JSInterface(QObject *parent) : QObject(parent)
{

}

3、MainWindow类。

(1)MainWindow.h如下:

#ifndef MAINWINDOW_H // 防止头文件重复包含的宏定义
#define MAINWINDOW_H // 定义主窗口头文件宏

#include <QMainWindow>
#include <QWidget>
#include <QWebEngineHistory> // 包含Web引擎历史记录类头文件
#include <QWebEngineHistoryItem>  // 包含Web引擎历史记录项类头文件
#include <QWebEnginePage>  // 包含Web引擎页面类头文件
#include <QWebEngineView>  // 包含Web引擎视图类头文件
#include <QtWebEngineWidgets/QtWebEngineWidgets>  // 包含Web引擎部件模块头文件

QT_BEGIN_NAMESPACE // 开始Qt命名空间
namespace Ui { class MainWindow; }
QT_END_NAMESPACE // 结束Qt命名空间

class MainWindow : public QMainWindow
{
    Q_OBJECT  // Qt元对象系统宏,支持信号槽机制

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

(2)MainWindow.cpp如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "JSInterface.h"  // 包含JavaScript交互接口头文件
#include <QFile>  // 包含文件操作类头文件
#include <QUrl>  // 包含URL处理类头文件

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QWebEnginePage *page = ui->BaiduMap->page();  // 获取Web引擎视图的页面对象
    QWebEngineProfile *profile = page->profile();  // 获取页面配置文件(未使用)

    // 处理网页特性权限请求(地理位置等),自动授予当前页面的定位权限
    connect(page, &QWebEnginePage::featurePermissionRequested, this,
            [page](const QUrl &securityOrigin, QWebEnginePage::Feature feature) {
        if (feature == QWebEnginePage::Geolocation) {
            page->setFeaturePermission(securityOrigin, feature, QWebEnginePage::PermissionGrantedByUser);
        }
    });

    // 启用跨域请求支持
    QWebEngineSettings *settings = page->settings();  // 获取页面设置对象
    settings->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);  // 允许本地内容访问远程URL
    settings->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true);  // 允许本地内容访问文件URL
    settings->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, true);  // 允许运行不安全内容(混合内容)
    settings->setAttribute(QWebEngineSettings::WebGLEnabled, false);  // 关闭WebGL,避免显卡驱动导致崩溃
    settings->setAttribute(QWebEngineSettings::Accelerated2dCanvasEnabled, false);  // 关闭2D加速

    // 初始化交互对象(独立于QWebEngineView),即 创建JavaScript交互接口对象
    JSInterface *jsInterface = new JSInterface(this);

    // 配置QWebChannel(必须在load之前完成)
    QWebChannel *webChannel = new QWebChannel(this);  // 创建Web通道对象
    webChannel->registerObject("JSInterface", jsInterface);  // 注册交互对象到Web通道,JavaScript中可通过此名称访问
    ui->BaiduMap->page()->setWebChannel(webChannel);  // 将Web通道设置到页面

    // 加载HTML(确保路径正确,使用QUrl::fromLocalFile避免路径解析错误)
    QString htmlPath = QCoreApplication::applicationDirPath() + "/html/index.html";  // 构建HTML文件路径
    QFile htmlFile(htmlPath); // 创建文件对象
    // 检查文件是否存在
    if (!htmlFile.exists()) {
        qDebug() << "[Error] HTML文件不存在:" << htmlPath;
        return;
    }
    QUrl htmlUrl = QUrl::fromLocalFile(htmlPath);  // 将文件路径转换为URL
    ui->BaiduMap->page()->load(htmlUrl);  // 加载HTML文件
    qDebug() << "[Info] 加载HTML路径:" << htmlUrl.toString();  // 输出加载信息

}

MainWindow::~MainWindow()
{
    delete ui;
}

六、可能遇见的问题

按照上面的流程是不会出现下面这些问题的,因为博主就是解决了下面的问题才写出上面的流程和代码的,加上这章节内容只是为了记录一下,万一某天某刻某人遇到下面问题了呢!

问题一:可能出现下面图片报错。
解决:建议重新注册一个百度的api,因为KEY可能被删除了(可以去看第二章节如何获取密钥的)。

问题二:地图快要加载出来的时候,然后整个地图的ui闪退没了(下图)。
解决:检查一下HTML中QWebChannel与百度地图API的加载顺序,加载顺序不当会触发 Qt WebEngine 控件崩溃。所以一定要先确保QWebChannel通信通道初始化完成并注册好交互对象(JSInterface),避免页面JS运行时通道还没建好。

问题三:地图的内容一直加载不出来(如下图)

解决:保留地理位置自动授权(主要还是权限没有),(后面都是次要)将前端从 BMapGL 切换为 BMap v3(非 WebGL),避免显卡驱动/QtWebEngine WebGL 崩溃。

最后,如有不足和错误的地方,期待私信指正!


网站公告

今日签到

点亮在社区的每一天
去签到