1.QT的WebEngineView模块+VS 的msvc编译器+高德地图的JS API实现,效果如图:
2.程序源码:
QT的pro文件需要加上一行
QT += webengine webenginewidgets webchannel widgets
(1)amapmarktools.html,主要用于显示网页,以及调用高德的JS API进行交互
复制代码
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<title>高德地图打点小工具</title>
<script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=你在高德地图申请的key"></script>
<style>
*{
margin: 0;
padding: 0;
}
#container
{
width: 100%;
height: 100%;
position: absolute;
left: 0;
top:0;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
</script>
</body>
</html>
<script src="qwebchannel.js"></script>//与qt交互需要用到,在本文件同一目录下
<script type="text/javascript">
var map = new AMap.Map("container",{zoom:14,center:[113.324,23.106]});
var MarkIconpath;
var amap_bridge;
new QWebChannel(qt.webChannelTransport, function (channel) {
amap_bridge = channel.objects.amap_bridge; //bridge_name 与QT 中一致
});
var AuthorName=amap_bridge.GetAMapAuthorName();
function getMarkerIconpath(icon_path)
{
MarkIconpath=icon_path;
}
function addOneMarker(lat, lng,titleName)
{
//GPS转高德坐标
var gps = [parseFloat(lng),parseFloat(lat)];
if(titleName=="")
{
titleName="undefine_markname";
}
AMap.convertFrom(gps, 'gps', function (status, result)
{
if (result.info === 'ok')
{
var lnglats= result.locations; // Array.<LngLat>
var marker = new AMap.Marker(
{ position:lnglats[0], // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
title:titleName,
icon:MarkIconpath,
});
marker.setClickable(true);
marker.on("rightclick", function (e){
if (confirm('确定要删除吗') == true)
{
map.remove(marker);
return true;
}
else
{
return false;
}
},"rightclick");
marker.setMap(map);
map.setCenter(lnglats[0]);
}
});
}
function removeAllMark()
{
map.clearMap();
}
function saveMarkToFile()
{
var markeroverlaysList = map.getAllOverlays('marker');
for(var i=0;i<markeroverlaysList.length;i++)
{
var position=markeroverlaysList[i].getPosition();
var title=markeroverlaysList[i].getTitle();
amap_bridge.saveAllMarkToFileFromAMap(position.lat,position.lng,title);
}
}
</script>
复制代码
(2)qwebchannel.js,建立qt应用与html的数据交互,本文件由qt官方提供。
地址:https://doc.qt.io/qt-5.9/qtwebengine-webenginewidgets-markdowneditor-resources-qwebchannel-js.html
(3)amapmainwindow.cpp,用于调用WebEngineView,建立与html的数据交互,以及界面显示等.
复制代码
#pragma execution_character_set("utf-8")//防止中文乱码,并且需要用Notepad++把本文件的编码格式改为ucs-2 Little endian
#include "amapmainwindow.h"
#include "ui_amapmainwindow.h"
#include <QNetworkProxyFactory>
#include<QDoubleValidator>
#include <QSize>
#include<QFileDialog>
#include<QTextStream>
AMapMainWindow::AMapMainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::AMapMainWindow)
{
ui->setupUi(this);
setWindowTitle("AMapMarkTools地图打点小工具");
p_AmapViewWedget = new QMainWindow();//用于放置webView
p_AmapView=new QWebEngineView(p_AmapViewWedget);//将QWebEngineView的父Widget为p_AmapViewWedget
p_AmapChannel = new QWebChannel(p_AmapView->page()); //创建通道,与JS交互
p_AmapBridge=new JSWebBridge(p_AmapViewWedget); //创建通道,与JS交互
p_AmapChannel->registerObject("amap_bridge",(QObject*)p_AmapBridge);// 注册名"amap_bridge"与JS中用到的名称保持相同
p_AmapView->page()->setWebChannel(p_AmapChannel);//View与chanel建立连接关系
p_AmapViewWedget->setCentralWidget(p_AmapView);
p_AmapHLayoutWidget = new QWidget(this);//用于将webView放置在AMapMainWindow
p_AmapHLayoutWidget->setObjectName(QString::fromUtf8("p_AmapHLayoutWidget"));
p_AmapHLayoutWidget->setGeometry(QRect(0, 0, 720, 480));//窗口大小为720*480
p_AmapHLayoutWidget->move(150,0);
p_AmapHLayout=new QHBoxLayout(p_AmapHLayoutWidget);
p_AmapHLayout->addWidget((QWidget *)p_AmapViewWedget);
setLayout(p_AmapHLayout);
QNetworkProxyFactory::setUseSystemConfiguration(false);//不用代理
QString htmlFilePath =QApplication::applicationDirPath()+"/amapmarktools.html";
loadMarkFilePath=QApplication::applicationDirPath();
p_AmapView->page()->load(QUrl(htmlFilePath));
p_AmapView->page()->setBackgroundColor(Qt::transparent);//背景透明
this->setMinimumWidth(720);
this->setMinimumHeight(480);
p_operaterLayoutWidget=new QWidget(this);
p_addOneMark=new QPushButton(p_operaterLayoutWidget);
p_addOneMark->setFixedSize(QSize(100,30));
p_addOneMark->setText("增加标记");
p_addMarkFromFile=new QPushButton(p_operaterLayoutWidget);
p_addMarkFromFile->setFixedSize(QSize(100,30));
p_addMarkFromFile->setText("从文件导入标记");
p_removeAllMark=new QPushButton(p_operaterLayoutWidget);
p_removeAllMark->setFixedSize(QSize(100,30));
p_removeAllMark->setText("删除所有标记");
p_saveAllMarkToFile=new QPushButton(p_operaterLayoutWidget);
p_saveAllMarkToFile->setFixedSize(QSize(100,30));
p_saveAllMarkToFile->setText("导出所有标记");
p_operaterLayout=new QVBoxLayout(p_operaterLayoutWidget);
p_operaterLayoutWidget->setGeometry(QRect(0, 0, 200, 480));
p_operaterLayoutWidget->move(0,0);
latLineEdit=new QLineEdit(p_operaterLayoutWidget);
lngLineEdit=new QLineEdit(p_operaterLayoutWidget);
nameLineEdit=new QLineEdit(p_operaterLayoutWidget);
latLineEdit->setFixedSize(QSize(100,20));
latLineEdit->setPlaceholderText("gps维度:23.4");
lngLineEdit->setFixedSize(QSize(100,20));
lngLineEdit->setPlaceholderText("gps经度:123.4");
nameLineEdit->setFixedSize(QSize(100,20));
nameLineEdit->setPlaceholderText("标记名称(可选)");
QDoubleValidator *validator = new QDoubleValidator(0, 360, 10, this);
lngLineEdit->setValidator(validator);
latLineEdit->setValidator(validator);
p_operaterLayout->addWidget(latLineEdit);
p_operaterLayout->addWidget(lngLineEdit);
p_operaterLayout->addWidget(nameLineEdit);
p_operaterLayout->addWidget(p_addOneMark);
p_operaterLayout->addWidget(p_addMarkFromFile);
p_operaterLayout->addWidget(p_saveAllMarkToFile);
p_operaterLayout->addWidget(p_removeAllMark);
setLayout(p_operaterLayout);
p_operaterLayout->setAlignment(Qt::AlignJustify);
connect(p_addOneMark, SIGNAL(clicked()),this, SLOT(addOneMarkBtnClickEvent()));
connect(p_removeAllMark, SIGNAL(clicked()),this, SLOT(removeAllMarkBtnClickEvent()));
connect(p_addMarkFromFile, SIGNAL(clicked()),this, SLOT(addMarkFromFileBtnClickEvent()));
connect(p_saveAllMarkToFile, SIGNAL(clicked()),this, SLOT(saveAllMarkToFileBtnClickEvent()));
}
AMapMainWindow::~AMapMainWindow()
{
delete ui;
}
void AMapMainWindow::resizeEvent(QResizeEvent* size)
{
QSize m_size= this->size();
p_AmapHLayoutWidget->setGeometry(QRect(0, 0, m_size.width()-150,m_size.height()));//窗口大小为720*480
p_AmapHLayoutWidget->move(150,0);
p_operaterLayoutWidget->setGeometry(QRect(0, 0, 150, m_size.height()));
p_operaterLayoutWidget->move(0,0);
}
void AMapMainWindow::addOneMark(double lat,double lng,QString labelname)
{
QString latStr = QString::number(lat, 10, 6);
QString lngStr = QString::number(lng, 10, 6);
QString jsCmd=QString("addOneMarker('%1','%2','%3')").arg(latStr).arg(lngStr).arg(labelname);
qDebug()<<jsCmd;
p_AmapView->page()->runJavaScript(jsCmd);
}
void AMapMainWindow::addOneMarkBtnClickEvent()
{
qDebug()<<"addOneMarkBtnClickEvent";
if((lngLineEdit->text().length()<1)||(latLineEdit->text().length()<1))
return;
double longtitude=lngLineEdit->text().toDouble();
double latitude=latLineEdit->text().toDouble();
if(nameLineEdit->text().length()>=1)
{
addOneMark(latitude,longtitude,nameLineEdit->text());
}
else
{
addOneMark(latitude,longtitude,"");
}
getMarkerIconpath((QApplication::applicationDirPath()+"/markerIcon.png"));
}
void AMapMainWindow::removeAllMarkBtnClickEvent()
{
removeAllMark();
}
void AMapMainWindow::getMarkerIconpath(QString path)
{
static bool setFlg=false;
if(setFlg==false)
{
QString jsCmd=QString("getMarkerIconpath('%1')").arg(path);
qDebug()<<jsCmd;
p_AmapView->page()->runJavaScript(jsCmd);
setFlg=true;
}
}
void AMapMainWindow::removeAllMark()
{
QString jsCmd=QString("removeAllMark()");
qDebug()<<jsCmd;
p_AmapView->page()->runJavaScript(jsCmd);
}
void AMapMainWindow::addMarkFromFileBtnClickEvent()
{
getMarkerIconpath((QApplication::applicationDirPath()+"/markerIcon.png"));
QFileDialog fileDialog(this);
fileDialog.setWindowTitle(tr("打开文件"));
fileDialog.setDirectory(loadMarkFilePath);
fileDialog.setNameFilter(tr("*.txt *.log *.*"));
fileDialog.setFileMode(QFileDialog::ExistingFiles);
fileDialog.setViewMode(QFileDialog::Detail);
//fileDialog.setGeometry(200,200,300,300);
if(fileDialog.exec() == QDialog::Accepted)
{
QString path = fileDialog.selectedFiles()[0];//select first filename
fileDialog.close();
QFile rfile(path);
if(rfile.open(QIODevice::ReadOnly)== true)
{
QTextStream readTextStream(&rfile); //创建输出流
while(!readTextStream.atEnd())
{
double lng=-1;
double lat=-1;
QString markName;
QString oneLineText = readTextStream.readLine(); //读取一行
QString tmpText=oneLineText;
int i=0;
do
{
if(i>2)
break;
if((tmpText.contains(",")))
{
tmpText=oneLineText.section(',', (i)).trimmed();
qDebug()<<"i="<<i<<",tmpText"<<tmpText;
bool isOk=false;
switch (i)
{
case 0:
oneLineText.section(',', i,i).trimmed().toDouble(&isOk);
if(isOk)
{
lng=oneLineText.section(',', i,i).trimmed().toDouble();
qDebug()<<"经度:"<<lng;
}
break;
case 1:
oneLineText.section(',', i,i).trimmed().toDouble(&isOk);
if(isOk)
{
lat=oneLineText.section(',', i,i).trimmed().toDouble();
qDebug()<<"维度:"<<lat;
}
break;
case 2:
markName=oneLineText.section(',', i,i).trimmed();
qDebug()<<"名字:"<<markName;
break;
default:
break;
}
}
i++;
}while(tmpText.size()>0);
if(lng>0&&lat>0)
{
qDebug()<<"addOneMark"<<lat<<","<<lng<<","<<markName;
addOneMark(lat,lng,markName);
}
}
}
}
}
void AMapMainWindow::saveAllMarkToFile()
{
QString jsCmd=QString("saveMarkToFile()");
qDebug()<<jsCmd;
p_AmapView->page()->runJavaScript(jsCmd);
}
void AMapMainWindow::saveAllMarkToFileBtnClickEvent()
{
QString filename = QFileDialog::getSaveFileName(this,
tr("选择保存路径"),
"",
tr("*.txt;; *.log;; *.csv;; *.*")); //选择路径
if(filename.isEmpty())
{
return;
}
else
{
p_AmapBridge->saveAllMarkPath=filename;
qDebug()<<(p_AmapBridge->saveAllMarkPath);
}
saveAllMarkToFile();
}
复制代码
(4)jswebbridge.cpp,用于与html建立数据通道
复制代码
#pragma execution_character_set("utf-8")//防止中文乱码
#include "jswebbridge.h"
#include <QMutex>
#include <QFile>
static QMutex fileMutex;
JSWebBridge::JSWebBridge(QObject *parent) : QObject(parent)
{
saveAllMarkPath="D:/";
}
QString JSWebBridge::GetAMapAuthorName()
{
qDebug()<<"AuthorName:Jest";
return "AuthorName:Jest";
}
void JSWebBridge::GetPointLatLngFromAMap(const QString lat,const QString lng,const QString name)
{
qDebug()<<"来自web标记点输出" <<"维度"<<lat<<","<<"经度"<<lng<<",名字"<<name;
}
void JSWebBridge::saveAllMarkToFileFromAMap(QString lat,QString lng,QString labelname)
{
fileMutex.lock();
QFile file(saveAllMarkPath);
if(file.open(QIODevice::WriteOnly | QIODevice::Text|QIODevice::Append))
{
QString tmp_str=lng+","+lat+","+labelname;
QTextStream out(&file);
out<<tmp_str<< endl;
file.close();
}
fileMutex.unlock();
}
复制代码
3.记录几个踩到的坑
(1)文件编码为utf-8的源文件直接使用到中文会莫名报错,用Notepad++把本文件的编码格式改为ucs-2 Little endian,也可以用[tr("中文")]的方法。
(2)调用高德地图增加mark时,默认图标是只会显示一个很小的坏图片[x],就使用本地路径图片,这路径是通过qt传输的。尝试在AMapMainWindow构造函数传递此路径,但由于建立数据通道初始化未完成,路径没有传输到html保存,还是坏图片。所以在打点前会传输一次路径,路径才在html中保存
(3)在html中要加上这一句,指定调用什么js文件,否则html将无法调用qt中的函数。
<script src="qwebchannel.js"></script>//与qt交互需要用到,在本文件同一目录下
(4)创建通道的步骤也要注意,还有注册名要一致
(5)使用高德地图的JS API时,可以参考官方文档、网上例子,可以在html中用alert函数进行测试数据是否正确
4.导入文本文件的数据格式
格式:经度,维度,mark的title名称(可选)
例如:
113.2223,23.1111,mark1
113.2334,23.5644,
113.8223,23.9111,标记5
完整代码:https://github.com/jest549/AMap_Mark
https://github.com/549jest/AMap_Mark