QML QtLocation地图应用学习-1:在Map中展示图元 Item

时间:2024-04-08 20:56:44

QML QtLocation地图应用学习-1:在Map中展示图元 Item_minimumzoomlevel-CSDN博客

0、前言

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 。

1、开始

要想展示一个地图,需要使用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

2、在Map中展示图元

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))
            }
        }

3、一个完整的例子

这里写了一个简单的例子,静态的展示图元,计算两点距离,旋转地图方位等。(测试发现拉伸窗口大小的时候,图元位置可能不会实时的跟着动,可以自己主动处理下,微调地图中心点或者缩放等级等等)

//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<coordinate>
            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
            }
        }
    }
}

4、Bug:当其他控件具有焦点时,地图上有灰白色方块

这是一个 Qt 的 Bug,参考Qt Bug反馈:Loading...,通过将Map或上级设置透明度为 0.99 可解决。

Map {
    opacity: 0.99
}