地图查看器(QML)

地图查看器示例展示了如何在 Qt Location 中显示和交互地图、搜索地址以及查找行车路线。

这是一个大型示例,涵盖了 Qt Location 中许多基本地图、定位和导航服务的用法。本页面分为几个部分,每部分都包含相关功能的代码片段。

运行示例

要从 Qt Creator 中运行此示例,请打开 欢迎使用 模式并从 示例 中选择此示例。有关更多信息,请访问 构建和运行示例

示例可以与任何可用的地理服务插件一起工作。但是,某些插件可能需要额外的 插件参数 以正确运行。可以使用 --plugin 参数将 插件参数 传递到命令行,该参数的形式如下

--plugin.<parameter name> <parameter value>

有关详细信息,请参阅每个地理服务插件的文档,了解它们支持的插件参数。本示例默认使用的插件是 Qt Location Open Street Map 插件,它不需要任何参数。

概述

此示例中展示的 QML 类型

显示地图

如图所示,使用 MapView 类型在屏幕上绘制地图,如下所示。

MapView {
    id: view
    map.zoomLevel: (maximumZoomLevel - minimumZoomLevel)/2
    map.center {
        // The Qt Company in Oslo
        latitude: 59.9485
        longitude: 10.7686
    }
}

MapView 包含一个 map 并扩展了基本导航功能。在此示例中,我们给地图设置了一个初始中心 坐标,并设置了纬度和经度。我们还将初始缩放级别设置为 50%(最大和最小之间的中间值)。

查找地址(地理编码)

为了在地图上定位特定地址或地点,需要使用地理编码的过程。为了执行地理编码操作,我们首先需要调整我们的 Map 对象以接收结果。

通过 GeocodeModel 接收地理编码的结果

GeocodeModel {
    id: geocodeModel
    plugin: view.map.plugin
    onStatusChanged: {
        if ((status == GeocodeModel.Ready) || (status == GeocodeModel.Error))
            view.geocodeFinished()
    }
    onLocationsChanged:
    {
        if (count === 1) {
            view.map.center.latitude = get(0).coordinate.latitude
            view.map.center.longitude = get(0).coordinate.longitude
        }
    }
}

要显示 GeocodeModel 的内容,我们使用 MapItemView

MapItemView {
    parent: view.map
    model: geocodeModel
    delegate: pointDelegate
}

MapItemView 使用一个名为 delegate 的对象作为其创建的项目的模板。这可以包含任何所需的地图对象,但在本例中,我们显示了一个包含标记图像的 MapQuickItem

Component {
    id: pointDelegate

    MapQuickItem {
        id: point
        parent: view.map
        coordinate: locationData.coordinate

        sourceItem: Image {
            id: pointMarker
            source: "../resources/marker_blue.png"
}
}
}

有了这三个对象,我们就有了接收地理编码响应并在我们的地图上显示它们所需要的全部。最后一步是要发送实际的地理编码请求。

要发送一个地理编码请求,首先我们创建一个地址对象,并用期望的参数填写它。

Address {
    id :fromAddress
    street: "Sandakerveien 116"
    city: "Oslo"
    country: "Norway"
    state : ""
    postalCode: "0484"
}

然后我们将geocodeModel.query设置为我们填写的地址,并调用GeocodeModel的update()方法。

// send the geocode request
geocodeModel.query = fromAddress
geocodeModel.update()

路线和出行路线

类似于GeocodeModel,Qt Location还提供了RouteModel类型,该类型允许接收和使用两个或多个点之间的路线信息(例如驾驶方向),以在地图上显示和使用。

同样地,我们将RouteModel实例化为我们地图的一个属性

RouteModel {
    id: routeModel
    plugin : view.map.plugin
    query:  RouteQuery {
        id: routeQuery
    }
    onStatusChanged: {
        if (status == RouteModel.Ready) {
            switch (count) {
            case 0:
                // technically not an error
                view.routeError()
                break
            case 1:
                view.showRouteList()
                break
            }
        } else if (status == RouteModel.Error) {
            view.routeError()
        }
    }
}

为了将模型的内容显示给用户,我们需要一个视图。我们再次将MapItemView用于在地图上将路线显示为对象

MapItemView {
    parent: view.map
    model: routeModel
    delegate: routeDelegate

为了使视图创建的对象模板化,我们创建了一个代理组件

Component {
    id: routeDelegate

    MapRoute {
        id: route
        route: routeData
        line.color: "#46a2da"
        line.width: 5
        smooth: true
        opacity: 0.8

随着模型、视图和代理组件都准备好了,唯一缺少的组件是对模型的一种控制,以开始路由请求过程。在最简单的情况下,我们可以使用两个已有的坐标填充一个路线请求

property variant fromCoordinate: QtPositioning.coordinate(59.9483, 10.7695)
property variant toCoordinate: QtPositioning.coordinate(59.9645, 10.671)

在下一个代码片段中,我们展示如何设置请求对象并指示模型更新。我们也指示地图以路由请求的起始坐标为中心

// clear away any old data in the query
routeQuery.clearWaypoints();
// add the start and end coords as waypoints on the route
routeQuery.addWaypoint(startCoordinate)
routeQuery.addWaypoint(endCoordinate)
routeQuery.travelModes = RouteQuery.CarTravel
routeQuery.routeOptimizations = RouteQuery.FastestRoute
routeModel.update();
// center the map on the start coord
view.map.center = startCoordinate;

这就是在地图上显示路线所需的所有内容。然而,能够检索路线文本和出行路线说明也是有用的。在示例中,这些信息在ListView元素中显示。为了创建这个内容,我们使用标准的ListModelListView对。ListModel中的数据是从routeModel的输出中构建的

ListView {
    interactive: true
    model: ListModel { id: routeInfoModel }
    header: RouteListHeader {}
    delegate:  RouteListDelegate{
        routeIndex.text: index + 1
        routeInstruction.text: instruction
        routeDistance.text: distance
    }
}

如上图所示,在RouteModel内部,我们添加了一个onStatusChanged处理器,它调用showRouteList()来更新routeInfoModel

routeInfoModel.clear()
if (routeModel.count > 0) {
    for (var i = 0; i < routeModel.get(0).segments.length; i++) {
        routeInfoModel.append({
            "instruction": routeModel.get(0).segments[i].maneuver.instructionText,
             "distance": Helper.formatDistance(routeModel.get(0).segments[i].maneuver.distanceToNextInstruction)
        });
    }
}

示例项目 @ code.qt.io

© 2024 The Qt Company Ltd. 本文档中的文档贡献是各自所有者的版权。本处提供的文档是根据自由软件基金会发布的GNU自由文档许可协议版本1.3的条款许可的。Qt及其相应标志是芬兰和/或世界其他地区的The Qt Company Ltd.的商标。所有其他商标均为各自所有者的财产。