GeoJSON 查看器 (QML)
GeoJson 查看器示例演示了如何操作 MapItems、处理用户输入以及与 GeoJson 文件之间的输入/输出操作。

该示例显示了一张包含各种 MapItems 的地图。这些 MapItems 要么是从 GeoJson 文件中导入的(使用QtLocation 中的GeoJsonData API),要么是由用户通过TapHandlers 绘制的。
GeoJSON 文件的示例位于示例目录下的 data 目录中。
要绘制 MapItem,请在地图的空白区域右键单击,并在弹出的菜单中选择所需的项类型。后续的点击将定义所选项。该示例支持绘制MapCircles 、MapRectangles 、MapPolygons 以及MapPolylines 。完全由两个点定义的项(即圆形和矩形)可通过两次左键单击绘制。 由多个点定义的图形(即多边形和折线)可通过任意次数的左键点击创建,并用右键完成绘制。以这种方式绘制的图形将作为点、多边形和折线保存,以符合 GeoJSON 规范,详见https://geojson.org/。
运行示例
您可以通过以下方式运行示例:
- Qt Creator
打开“Welcome ”模式,并从Examples 中选择该示例。有关更多信息,请参阅Qt Creator :教程:构建与运行。
- Qt Extension for Visual Studio Code
在Command Palette 中运行Qt: Open Qt examples 命令,并从列表中选择该示例。有关详细信息,请参阅Qt Extension for Visual Studio Code :教程:构建和运行。
创建 MapView
首先,我们创建一张基础地图,所有项目均可放置其上。我们利用MapView 元素,该元素将基础的Map 与输入处理功能(鼠标滚轮、拖拽等)结合在一起。可通过map 属性访问底层的Map 。如果在MapView 中缺少某个属性,通常可通过MapView.map 访问该属性。
MapView {
id: view
anchors.fill: parent
map.plugin: Plugin { name: "osm" }
map.zoomLevel: 4
map.center: QtPositioning.coordinate(3, 8)
}设置 GeoJSON 模型 / 显示 MapItems
为了在地图上显示文件内容,我们将使用一种称为“模型/视图”的设计模式。首先,我们需要设置一个合适的视图,在本例中是MapItemView 元素。其父元素必须设置为MapView 的底层地图,才能正确显示其中放置的所有项目。
MapItemView {
id: miv
parent: view.map
}接下来,我们需要一个合适的模型,用于表示 GeoJSON 文档。为此,QtLocation 提供了GeoJsonData 元素,该元素能够读写 GeoJSON 文件。它可以轻松实例化
GeoJsonData {
id: geoDatabase
sourceUrl: ":/data/11-full.json"
}并将其赋值给MapItemView 。
model: geoDatabase.model文件11-full.json 作为示例在启动时被加载。
最后,我们需要一个 `delegate`,它将模型数据转换为项的表示形式,并填充 `MapItemView`。
delegate: GeoJsonDelegate {}GeoJsonDelegate 元素在文件GeoJsonDelegate.qml 中声明。它是一个DelegateChooser 元素,用于处理不同几何类型的多样化属性。
DelegateChooser {
id: dc
role: "type"
}DelegateChooser 包含 GeoJSON 文件中每种几何类型的DelegateChoice 。属性role 将与DelegateChoice.roleValue 进行匹配,以确定正确的委托。
例如,GeoJSON 中通过"type":"Point" 描述的点,在MapItemView 上由MapCircle 表示:
DelegateChoice {
roleValue: "Point"
delegate: MapCircle {
property string geojsonType: "Point"
property var props: modelData.properties
geoShape: modelData.data
radius: (props && props.radius) || 20*1000
border.width: 2
border.color: hh.hovered ? "magenta" : Qt.darker(color)
opacity: dc.defaultOpacity
color: (props && props.color) || (parent && parent.props && parent.props.color) || dc.defaultColor
}
}系统会尝试从 GeoJSON 文件中读取MapCircle 的属性(如color 或radius ),该文件以 modelData 属性的形式提供。但这并非 GeoJSON 的严格标准,因此所有属性都设置了备用值。
将 MapItems 写入 GeoJSON
要将 MapItems 写入 GeoJSON 文件,只需调用GeoJsonData::saveAs 函数并指定文件名即可。这将把当前模型中的所有项写入指定文件。任何其他需要写入文件的项,都必须先使用GeoJsonData::addItem 或GeoJsonData::setModelToMapContents 函数添加到模型中。
geoDatabase.saveAs(fileWriteDialog.selectedFile)用户与 MapItems 的交互
为了处理用户交互,我们将使用PointHandlers 。它们特别适合此任务,因为它们完全符合底层项的形状,而MouseArea 则始终覆盖一个正方形。从 GeoJson 文件导入的 MapItems 会在委托中直接获得其专属的HoverHandler 和TapHandler :
TapHandler {
onTapped: {
if (props !== undefined)
console.log(props.name)
else if (parent.parent.geojsonType == "MultiPoint")
console.log(parent.parent.props.name)
else
console.log("NO NAME!", props)
}
}
HoverHandler {
id: hh
}TapHandler 用于在用户点击项目时,在控制台上输出有关该项目的某些信息。HoverHandler 用于突出显示位于鼠标指针下方的项目。这是通过根据HoverHandler 的属性/状态hovered 来描述border.color 属性来实现的。
添加新项目
通过将HoverHandler 与TapHandler 结合应用于MapView ,我们可以响应用户的鼠标移动和点击操作。
如果TapHandler 发出singleTapped 信号,我们将创建或修改LeftButton 上的新 MapItem,并在RightButton 上完成该 MapItem。如果没有待完成的项,则RightButton 将打开一个菜单。
onSingleTapped: (eventPoint, button) => {
lastCoordinate = view.map.toCoordinate(tapHandler.point.position)
if (button === Qt.RightButton) {
if (view.unfinishedItem !== undefined) {
view.finishGeoItem()
} else
mapPopupMenu.show(lastCoordinate)
} else if (button === Qt.LeftButton) {
if (view.unfinishedItem !== undefined) {
if (view.unfinishedItem.addGeometry(view.map.toCoordinate(tapHandler.point.position), false)) {
view.finishGeoItem()
}
}
}
}pointChanged 信号用于临时更新MapItem,以便向用户提供预览。
HoverHandler {
id: hoverHandler
property variant currentCoordinate
grabPermissions: PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType
onPointChanged: {
currentCoordinate = view.map.toCoordinate(hoverHandler.point.position)
if (view.unfinishedItem !== undefined)
view.unfinishedItem.addGeometry(view.map.toCoordinate(hoverHandler.point.position), true)
}
}MapItem 由定义在单独 QML 文件中的原型生成。它们通过createComponent 函数创建,并使用addMapItem 添加到地图中。系统会存储对新项的引用,以便用户进行后续操作。
function addGeoItem(item)
{
var co = Qt.createComponent('mapitems/'+item+'.qml')
if (co.status === Component.Ready) {
unfinishedItem = co.createObject(map)
unfinishedItem.setGeometry(tapHandler.lastCoordinate)
unfinishedItem.addGeometry(hoverHandler.currentCoordinate, false)
view.map.addMapItem(unfinishedItem)
} else {
console.log(item + " is not supported right now, please call us later.")
}
}将项添加到Map 中即可显示该项。但是,若要进一步使用该项(例如将其保存到文件中),则必须将其添加到模型中。此操作应在编辑完成后进行:
function finishGeoItem()
{
unfinishedItem.finishAddGeometry()
geoDatabase.addItem(unfinishedItem)
map.removeMapItem(unfinishedItem)
unfinishedItem = undefined
}删除项目
要从地图中移除所有项目,只需调用GeoJsonData 对象的reset函数
function clearAllItems()
{
geoDatabase.clear();
}© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.