摘要:在地图应用中,有很多时候是需要断网环境中离线使用的,一般会采用两种做法,一种是只下载好离线瓦片地图,然后根据不同的缩放和经纬度坐标绘制瓦片。这种方式优点是任何地图都支持,只需要拿到瓦片即可,缺点是其他的接口都需要自己处理,比如覆盖物的绘制,工作量巨大,尽管Qt
在地图应用中,有很多时候是需要断网环境中离线使用的,一般会采用两种做法,一种是只下载好离线瓦片地图,然后根据不同的缩放和经纬度坐标绘制瓦片。这种方式优点是任何地图都支持,只需要拿到瓦片即可,缺点是其他的接口都需要自己处理,比如覆盖物的绘制,工作量巨大,尽管Qt的qml部分提供了location模块用于这个处理,但是功能还不是很完善,而且不支持widget,对于只会widget的我来说,歇菜。现阶段采用方式二,也就是浏览器控件加载地图的js交互来实现,优点就不说了,超过优点,缺点就一个,必须依赖浏览器控件,资源占用大。
百度地图的离线js开发包,网上到处都是,大部分都是2.0版本,这个基本上功能是齐全的,直接用就行,至于天地图,网上几乎没有,本人废了九牛二虎之力才搞定,一点点从官网趴下来的,所有支持的离线功能全部存在,非常完美,关键是掌握了这个方法思路就很好办,无论后期版本升级到多少,都可以轻轻松松实现最新版本的离线地图js开发包。离线搞定后,手机上运行离线地图就非常容易了,使用qml的浏览器控件加载离线网页即可。在手机上只有qml的浏览器组件能使用,widget的不支持,因为qml的浏览器组件使用本地浏览器内核,而不是webkit或者webengine,手机端是什么底层浏览器就是用何种浏览器。
#include "frmmapqml.h"#include "ui_frmmapqml.h"#include "qthelper.h"#include "maphelper.h"#include "mapwebsocket.h"//安卓上如果提示 net::ERR_CLEARTEXT_NOT_PERMITTED 需要在AndroidManifest.xml文件的Application节点添加 android:usesCleartextTraffic="true"frmMapQml::frmMapQml(QWidget *parent) : QWidget(parent), ui(new Ui::frmMapQml){ui->setupUi(this);this->initForm;this->initConfig;}frmMapQml::~frmMapQml{delete ui;}void frmMapQml::showEvent(QShowEvent *){//首次显示的时候自动加载/下面这种写法表示异步记载static bool isLoad = false;if (!isLoad) {isLoad = true;QMetaObject::invokeMethod(this, "loadMap", Qt::QueuedConnection);}}void frmMapQml::initForm{mapObj = NULL;flag = "movePerson";//拿到qml对象qmlObj = ui->quickWidget->rootObject;//实例化websocket通信用于网页交互connect(MapWebSocket::Instance, SIGNAL(receiveDataFromJs(QString, QString)), this, SLOT(receiveDataFromJs(QString, QString)));MapWebSocket::Instance->listen;}void frmMapQml::initConfig{MapHelper::loadMapCore(ui->cboxMapCore, AppConfig::MapCore);connect(ui->cboxMapCore, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig));connect(ui->cboxMapCore, SIGNAL(currentIndexChanged(int)), this, SLOT(loadMap));ui->cboxMoveSpeed->setCurrentIndex(ui->cboxMoveSpeed->findText(QString::number(AppConfig::MoveSpeed)));connect(ui->cboxMoveSpeed, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig));connect(ui->cboxMoveSpeed, SIGNAL(currentIndexChanged(int)), this, SLOT(loadData));ui->txtStartAddr->setText(AppConfig::StartAddr);connect(ui->txtStartAddr, SIGNAL(textChanged(QString)), this, SLOT(saveConfig));ui->txtEndAddr->setText(AppConfig::EndAddr);connect(ui->txtEndAddr, SIGNAL(textChanged(QString)), this, SLOT(saveConfig));}void frmMapQml::saveConfig{AppConfig::MapCore = ui->cboxMapCore->itemData(ui->cboxMapCore->currentIndex).toInt;AppConfig::MoveSpeed = ui->cboxMoveSpeed->currentText.toInt;AppConfig::StartAddr = ui->txtStartAddr->text.trimmed;AppConfig::EndAddr = ui->txtEndAddr->text.trimmed;AppConfig::writeConfig;}void frmMapQml::loadMap{//根据不同地图内核实例化地图类MapCore mapCore = (MapCore)ui->cboxMapCore->itemData(ui->cboxMapCore->currentIndex).toInt;MapHelper::initMapObj(this, &mapObj, mapCore);mapObj->setMapType(0);mapObj->setMapLocal(false);QString html = mapObj->load;//将生成的地图网页文件加载到qml中QString File = "file:///" + mapObj->getFileName;//安卓上放在固定的目录#ifdef Q_OS_ANDROIDfile = QString("file:///android_asset/%1/map.html").arg(MapHelper::getMapPath(mapCOre));#endifQMetaObject::invokeMethod((QObject *)qmlObj, "load", Q_ARG(QVariant, file));//QMetaObject::invokeMethod((QObject *)qmlObj, "loadhtml", Q_ARG(QVariant, html));ui->txtResult->clear;}void frmMapQml::loadData{if (datas.count runJs(QString("clearOverlay"));this->runJs(QString("drawRoute('%1', '#01caf4', 8, 1.0, '#ffffff')").arg(points));//生成移动对象points = datas.join("|");int speed = ui->cboxMoveSpeed->currentText.toInt;QString image = "../mapimage/move_fly.png";if (mapObj->getMapCore == MapCore_GaoDe && mapObj->getVersionKey.startsWith("2.")) {image = "../mapimage/move_fly2.png";}this->runJs(QString("addMove('%1', '%2', %3, true, false, '%4', 48, 48)").arg(flag).arg(points).arg(speed).arg(image));}void frmMapQml::runJs(const QString &js){QMetaObject::invokeMethod((QObject *)qmlObj, "runJs", Q_ARG(QVariant, js));}void frmMapQml::receiveDataFromJs(const QString &type, const QString &result){if (type == "click") {QString info = QString("触发鼠标单击\n当前经纬度值: %1").arg(result);QtHelper::showMessageBoxInfo(info);} else if (type == "rightclick") {QString info = QString("触发鼠标右键\n当前经纬度值: %1").arg(result);QtHelper::showMessageBoxInfo(info);} else if (type == "dblclick") {QString info = QString("触发鼠标双击\n当前经纬度值: %1").arg(result);QtHelper::showMessageBoxInfo(info);} else if (type == "geocoderresult") {QStringList list = result.split("|");QString flag = list.first;if (flag == "startAddr") {startPoint = list.last;QString endAddr = ui->txtEndAddr->text.trimmed;this->runJs(QString("getPointByAddr('endAddr', '%1')").arg(endAddr));} else if (flag == "endAddr") {endPoint = list.last;}//两个地址都有了再开启路径规划if (!startPoint.isEmpty && !endPoint.isEmpty) {this->runJs(QString("searchRoute(2, '%1', '%2', '%3')").arg(0).arg(startPoint).arg(endPoint));}} else if (type == "routeresult") {QStringList list = result.split("|");QString result = MapHelper::getRouteResult(list.first.toInt, list.last.toInt);ui->txtResult->setText(result);} else if (type == "routepoints") {datas.clear;QStringList list = result.split("|");foreach (QString data, list) {datas getMapCore;int interval = (mapCore == MapCore_BaiDuGL ? 500 : 0);QTimer::singleShot(interval, this, SLOT(loadData));} else if (type == "movestep") {MapCore mapCore = mapObj->getMapCore;if (mapCore != MapCore_BaiDuGL && mapCore != MapCore_GaoDe) {QString point = result.split("|").last;this->runJs(QString("setCenter('%1')").arg(point));}} else if (type == "moveend") {ui->widgetPara->setEnabled(true);on_btnStart_clicked;//再次执行则表示循环QMetaObject::invokeMethod(this, "on_btnStart_clicked", Qt::QueuedConnection);}}void frmMapQml::on_btnSelect_clicked{//执行地址转经纬度操作/路径规划一般只支持经纬度参数startPoint = endPoint = "";QString startAddr = ui->txtStartAddr->text.trimmed;this->runJs(QString("getPointByAddr('startAddr', '%1')").arg(startAddr));}void frmMapQml::on_btnStart_clicked{if (datas.count btnStart->text == "开始导航") {this->runJs(QString("addLine('%1', '%2', '#ff0000', 6)").arg(flag).arg(datas.first));//this->runJs(QString("setTilt(%1)").arg(60));this->runJs(QString("moveStart('%1')").arg(flag));ui->btnStart->setText("停止导航");ui->widgetPara->setEnabled(false);} else {this->runJs(QString("moveStop('%1')").arg(flag));ui->btnStart->setText("开始导航");ui->widgetPara->setEnabled(true);}}体验地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 文件名:bin_map.zip国内站点:https://gitee.com/feiyangqingyun国际站点:https://github.com/feiyangqingyun来源:Qt自定义控件
免责声明:本站系转载,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与本站联系,我们将在第一时间删除内容!