目录
0、前言
1、开始
2、在Map中展示图元
3、一个完整的例子
4、Bug:当其他控件具有焦点时,地图上有灰白色方块
Qt Location模块可用于轻量级的地图应用开发,不过官方示例及网上的例子都很少,而且仅仅是轻度使用的话没有用高德或者百度地图的Web API来得方便。
在QML中使用Qt Location模块,还需要引入Qt Positioning模块,因为Qt Location依赖他。
import QtPositioning 5.12
import QtLocation 5.12
想要深入的了解可以参照官方文档,如:https://doc.qt.io/qt-5.12/qtlocation-index.html 。
要想展示一个地图,需要使用Map组件,并为其设置Plugin。Plugin指定了相关的位置服务插件,有esri、mapbox、osm等。最简单的地图展示代码如下:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtLocation 5.12
import QtPositioning 5.12
Window {
width: 512
height: 512
visible: true
Plugin {
id: mapPlugin
name: "osm" // "mapboxgl", "esri", ...
}
Map {
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(30.67, 104.07)
zoomLevel: 14
}
}
根据我的测试,只有 osm 和 esri 可以正常加载,并且使用 osm 还要把 openssl 的动态库放到运行目录里。
Map使用OpenGL(ES)和Qt Scene Graph堆栈来渲染地图,因此在可以使用GL加速硬件的情况下,其表现非常出色。它有一些常用的属性,如 center 中心点坐标, zoomLevel 缩放等级等。其中坐标是一个单独的类型,在QML中为 coordinate 类型,有经纬度和海拔高度属性(latitude 纬度,longitude 经度,altitude 海拔高度单位米),还包含了计算距离和方位角的方法。参考官方文档:https://doc.qt.io/qt-5.12/qml-qtlocation-map.html 。
QtLocation 模块中定义了很多小部件的类型,可以在 Map 中绘制点线等图元。
MapQuickItem 可以在地图上显示任意 Qt Quick 对象,通过 sourceItem 属性指定 Qt Quick 对象;coordinate 标定坐标点;anchorPoint 表示sourceItem左上角相对于coordinate的偏移((0,0)的话左上角是在coordinate的位置);zoomLevel 表示缩放等级,0则不会缩放,否则是和对应的地图缩放等级一起放大缩小的。
//在地图上显示任意Qt Quick对象
MapQuickItem{
id: point_1
//缩放等级默认0固定大小,否则会和缩放等级一起放大缩小
zoomLevel: 0
//指示的坐标点
coordinate: QtPositioning.coordinate(30.67, 104.07)
//sourceItem左上角相对于coordinate的偏移
anchorPoint: Qt.point(sourceItem.width/2,sourceItem.height/2)
//Qt Quick对象
sourceItem: Rectangle{
width: 14
height: 14
radius: 7
color: "green"
border.color: "red"
border.width: 1
}
//Qt5.14加了一个淡入属性autoFadeIn
}
此外,还有MapCircle,MapRectangle,MapPolygon,MapPolyline 等图元类型,这些好像是和地图的缩放锚定的,如绘制一个多边形(每个顶点由地理坐标点指定):
MapPolygon{
id: point_3
color: "blue"
border.width: 1
border.color: "red"
//根据坐标点绘制多边形
path:[QtPositioning.coordinate(30.70, 104.08)]
Component.onCompleted: {
point_3.addCoordinate(QtPositioning.coordinate(30.72, 104.08))
point_3.addCoordinate(QtPositioning.coordinate(30.72, 104.10))
point_3.addCoordinate(QtPositioning.coordinate(30.69, 104.12))
}
}
这里写了一个简单的例子,静态的展示图元,计算两点距离,旋转地图方位等。(测试发现拉伸窗口大小的时候,图元位置可能不会实时的跟着动,可以自己主动处理下,微调地图中心点或者缩放等级等等)
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtPositioning 5.12
import QtLocation 5.12
//参考文档 https://doc.qt.io/qt-5.12/qtlocation-index.html
Window {
visible: true
width: 640
height: 480
title: qsTr("龚建波 1992")
Slider{
id: bearing_slider
height: 20
width: parent.width
from: 0
to: 360
value: 0
}
//拖动窗口大小图元位置不能实时跟随,做此下策
onWidthChanged: item_map.zoomLevel+=0.000001
onHeightChanged: item_map.zoomLevel-=0.000001
//绘制地图的容器
Map{
id: item_map
anchors.fill: parent
anchors.topMargin:20
plugin: Plugin{
//参见文档https://doc.qt.io/qt-5.12/qml-qtlocation-plugin.html
//首选插件语言环境的有序列表,但是貌似没啥用
locales: "zh-CN"
//插件的名称
//osm需要把openssl的dll放到运行目录
//esri默认就能用,mapbox的我这里加载不了,here的不知道咋用
//esri默认这个图成都那里不对(放大后)
name: "esri" // "mapboxgl", "esri", "osm"...
//首选插件名称的有序列表,设置了name值时无效
//preferred: ["here","osm"]
//选择附加到哪个服务插件时Plugin对象所需的功能集,设置了name值时无效
//required: Plugin.AnyMappingFeatures | Plugin.AnyGeocodingFeatures
}
//初始中心点-成都
center: QtPositioning.coordinate(30.67, 104.07)
//初始缩放等级
zoomLevel: 12
//最大缩放等级
maximumZoomLevel: 14
//最小缩放等级
minimumZoomLevel: 1
//背景色,没有正常加载时显色的图块颜色
color: "green"
//地图的方位
//如果用于Map的插件支持方位,则该值的有效范围在0到360之间。
//如果用于Map的插件不支持方位,则更改此属性将无效。
bearing: bearing_slider.value
//在地图上显示任意Qt Quick对象
MapQuickItem{
id: point_1
//缩放等级默认0固定大小,否则会和缩放等级一起放大缩小
zoomLevel: 0
//指示的坐标点
coordinate: QtPositioning.coordinate(30.67, 104.07)
//sourceItem左上角相对于coordinate的偏移
anchorPoint: Qt.point(sourceItem.width/2,sourceItem.height/2)
//Qt Quick对象
sourceItem: Rectangle{
width: 14
height: 14
radius: 7
color: "green"
border.color: "red"
border.width: 1
MouseArea{
anchors.fill: parent
onClicked: console.log("click")
}
//coordinate类型有经纬度高度三个属性
//latitude 纬度
//longitude 经度
//altitude 海拔高度,单位米
//以及计算距离和方位角的方法
//这里用文本显示两个点的距离
Text{
text: " "+Math.round(point_1.coordinate.distanceTo(
point_2.coordinate))/1000+" km"
color: "green"
font.bold: true
font.pixelSize: 16
}
}
//Qt5.14加了一个淡入属性autoFadeIn
}
MapQuickItem{
id: point_2
zoomLevel: 10 //和缩放等级一起放大缩小
coordinate: QtPositioning.coordinate(30.67, 104.04)
anchorPoint: Qt.point(sourceItem.width/2,sourceItem.height/2)
sourceItem: Rectangle{
width: 14
height: 14
radius: 7
color: "green"
border.color: "red"
border.width: 1
}
}
//此外,还有MapCircle,MapRectangle,MapPolygon等图元类型
//他们是和地图成比例的
// 画多边形
MapPolygon{
id: point_3
color: "blue"
border.width: 1
border.color: "red"
//根据坐标点绘制多边形
path:[QtPositioning.coordinate(30.70, 104.08)]
Component.onCompleted: {
point_3.addCoordinate(QtPositioning.coordinate(30.72, 104.08))
point_3.addCoordinate(QtPositioning.coordinate(30.72, 104.10))
point_3.addCoordinate(QtPositioning.coordinate(30.69, 104.12))
}
}
// 绘制折线
MapPolyline{
line.width: 2
line.color: "green"
//路径列表 path : list
path: [point_1.coordinate,point_2.coordinate,point_3.path[0]]
}
Rectangle{
x: 10
y: 10
height: item_center.height+20
width: item_center.width+20
color: "green"
Text{
id: item_center
x: 10
y: 10
color: "white"
font.pixelSize: 16
font.bold: true
//展示缩放等级 和 map的中心点经纬度
text: "zoom level:"+Math.floor(item_map.zoomLevel)+
" center:"+item_map.center.latitude+
" "+item_map.center.longitude
}
}
}
}
这是一个 Qt 的 Bug,参考Qt Bug反馈:https://bugreports.qt.io/browse/QTBUG-62463,通过将Map或上级设置透明度为 0.99 可解决。
Map {
opacity: 0.99
}