地图是桌面客户端经常使用到的组件之一,诸如热点标记、轨迹规划等。多数情况下是使用js实现,通过QWebEngine将其加载嵌入Qt中,地图方面可以使用Ceisum或是其他三方库实现,也可以通过其他第三方服务商提供的成熟接口,诸如腾讯地图、高德地图等。本文使用的就是腾讯地图提供的API。
实际使用前需要先申请对应权限的key,保证服务的正常使用,如下图所示
申请完key之后,需要加载在线API资源,调用接口即可。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>点击地图拾取坐标</title>
</head>
<script charset="utf-8" src="http://map.qq.com/api/gljs?v=1.exp&key=你的key"></script>
<script src="handleCmd.js"></script>
<script src="qwebchannel.js"></script>
<script src="jquery.min.js"></script>
<style type="text/css">
html,
body {
height: 100%;
margin: 0px;
padding: 0px;
}
#container {
width: 100%;
height: 100%;
}
#info {
position: absolute;
left: 20px;
top: 20px;
font-size: 14px;
background: #FFF;
width: 270px;
padding: 10px;
border-radius: 3px;
}
</style>
<body onload="initMap()">
<div id="container"></div>
<script>
function initMap() {
var position = document.getElementById("position");
var center = new TMap.LatLng(39.984104, 116.307503);//设置中心点坐标
// 初始化地图
window.map = new TMap.Map("container", {
center: center
});
// 绑定点击事件
window.map.on("click", function (evt) {
var lat = evt.latLng.getLat().toFixed(6);
var lng = evt.latLng.getLng().toFixed(6);
position.innerHTML = lat + "," + lng;
})
}
</script>
<div id="info">当前点击坐标为:<span id="position"></span></div>
</body>
</html>
数据传递需要通过QWebChannel完成,数据从qt传递至js中选中的是通过信号传递,传递回来是通过槽函数。
qt代码如下:
class CustomWebWidget : public QWidget
{
Q_OBJECT
public:
CustomWebWidget(QWidget *parent = nullptr);
~CustomWebWidget();
signals:
void sig_pickupLocation(double lat, double lng);
void sig_currentLocation(double lat, double lng);
void sig_keywordSearch(QList<QPair<QString, QPointF>> tmpList);
void sig_clearPolylineLayer();
// 传递至web
signals:
void sig_tips(QString str);
void sig_setCenter(double lat, double lng);
void sig_addMarker(double lat, double lng);
void sig_requestCurrentLocation();
void sig_requestKeywordSearch(QString str);
void sig_requestRoutePlanning(QString startPos, QString endPos);
public slots:
void slot_pickupLocation(double lat, double lng);
void slot_currentLocation(double lat, double lng);
void slot_keywordSearch(QJsonArray val);
private:
class QWebEngineView* m_view;
class QWebChannel* m_channel;
};
CustomWebWidget::CustomWebWidget(QWidget *parent)
: QWidget(parent)
{
m_view=new QWebEngineView(this);
m_channel = new QWebChannel(this);
m_channel->registerObject("webObject", this);
m_view->page()->setWebChannel(m_channel);
m_view->load(QUrl("file:///E:/JsTest/TencentMap/index.html"));
//m_view->load(QUrl("http://127.0.0.1:8088"));
auto mainLayout = new QHBoxLayout(this);
mainLayout->addWidget(m_view);
}
CustomWebWidget::~CustomWebWidget()
{
m_channel->deregisterObject(this);
}
void CustomWebWidget::slot_pickupLocation(double lat, double lng)
{
emit sig_pickupLocation(lat, lng);
}
void CustomWebWidget::slot_currentLocation(double lat, double lng)
{
emit sig_currentLocation(lat, lng);
}
void CustomWebWidget::slot_keywordSearch(QJsonArray val)
{
QList<QPair<QString, QPointF>> tmpList;
for(auto iter = val.begin(); iter != val.end(); iter++){
QJsonObject tmpObj = iter->toObject();
QJsonObject locationObj =tmpObj.value("location").toObject();
tmpList << qMakePair(tmpObj.value("title").toString(), QPointF(locationObj.value("lat").toDouble(), locationObj.value("lng").toDouble()));
}
if(!tmpList.isEmpty())
sig_keywordSearch(tmpList);
}
js代码如下:
// 创建通道对象并设置全局变量
new QWebChannel(qt.webChannelTransport, function (channel) {
window.webObj = channel.objects.webObject; //对象名与QT中一致
window.webObj.sig_tips.connect(function (name) {
alert(name);
});
window.webObj.sig_setCenter.connect(function (lat, lng) {
window.map.setCenter(new TMap.LatLng(lat, lng));
});
window.webObj.sig_requestCurrentLocation.connect(function () {
requestCurrtLocation();
});
window.webObj.sig_requestKeywordSearch.connect(function (keyword) {
requestKeywordSearch(keyword);
});
window.webObj.sig_requestRoutePlanning.connect(function (startPos, endPos) {
requestRoutePlanning(startPos, endPos);
});
window.webObj.sig_clearPolylineLayer.connect(function () {
if (window.polylineLayer) {
for (i in window.polylineLayer) {
indow.polylineLayer[i].setMap(null);
}
window.polylineLayer.length = 0;
}
});
window.webObj.sig_addMarker.connect(function (lat, lng) {
window.markerLayer.add({
position: new TMap.LatLng(lat, lng)
});
});
});
定位服务主要是ip定位、地名搜索以及轨迹规划
var tencentToken = "你的key";
// http请求
function currentLocation(callback) {
$.ajax({
type: "get",//接口规定,只能用get
async: true,//异步
url: "https://apis.map.qq.com/ws/location/v1/ip",//接口地址
data: { "key": tencentToken, "output": "jsonp" },
dataType: "jsonp",//跨域,必须用到jsonp
success: function (data) {
if (typeof callback == "function") {
callback(data.result.location);
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log(JSON.stringify(XMLHttpRequest));
}
});
}
function keywordSearch(keyword, callback) {
$.ajax({
type: "get",//接口规定,只能用get
async: true,//异步
url: "https://apis.map.qq.com/ws/place/v1/suggestion",//接口地址
data: { "key": tencentToken, "output": "jsonp", "keyword": keyword },
dataType: "jsonp",//跨域,必须用到jsonp
success: function (result) {
if (typeof callback == "function") {
callback(result.data);
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log(JSON.stringify(XMLHttpRequest));
}
});
}
function routePlanning(startPos, endPos, callback) {
$.ajax({
type: "get",//接口规定,只能用get
async: true,//异步
url: "https://apis.map.qq.com/ws/direction/v1/walking",//接口地址
data: { "key": tencentToken, "output": "jsonp", "from": startPos, "to": endPos },
dataType: "jsonp",//跨域,必须用到jsonp
success: function (data) {
if (typeof callback == "function") {
callback(data.result.routes);
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log(JSON.stringify(XMLHttpRequest));
}
});
}
// 请求函数
function requestCurrtLocation() {
currentLocation(function (coordinate) {
window.webObj.slot_currentLocation(coordinate.lat, coordinate.lng);
});
}
function requestKeywordSearch(keyworkd) {
keywordSearch(keyworkd, function (data) {
window.webObj.slot_keywordSearch(data);
});
}
function displayPolyline(pline){
//创建 MultiPolyline显示折线
var polylineLayer = new TMap.MultiPolyline({
// id: 'polyline-layer', //图层唯一标识
map: window.map,//绘制到目标地图
//折线样式定义
styles: {
'style_blue': new TMap.PolylineStyle({
'color': '#3777FF', //线填充色
'width': 8, //折线宽度
'borderWidth': 5, //边线宽度
'borderColor': '#FFF', //边线颜色
'lineCap': 'round', //线端头方式
})
},
//折线数据定义
geometries: [
{
'id': 'pl_1',//折线唯一标识,删除时使用
'styleId': 'style_blue',//绑定样式名
'paths': pline
}
]
});
window.polylineLayer.push(polylineLayer);
}
function requestRoutePlanning(startPos, endPos) {
routePlanning(startPos, endPos, function (routes) {
var coords = routes[0].polyline, pl = [];
//坐标解压(返回的点串坐标,通过前向差分进行压缩)
var kr = 1000000;
for (var i = 2; i < coords.length; i++) {
coords[i] = Number(coords[i - 2]) + Number(coords[i]) / kr;
}
//将解压后的坐标放入点串数组pl中
for (var i = 0; i < coords.length; i += 2) {
pl.push(new TMap.LatLng(coords[i], coords[i+1]));
}
displayPolyline(pl)//显示路线
});
}
Qt源码:https://download.csdn.net/download/weixin_42219627/87321644
Js源码:https://download.csdn.net/download/weixin_42219627/87321577