Auf dieser Seite

GeoJSON-Viewer (QML)

Das Beispiel „GeoJson-Viewer“ veranschaulicht, wie man MapItems bearbeitet, Benutzereingaben verarbeitet und Daten in eine GeoJson-Datei ein- und aus dieser ausliest.

Karte von Europa mit einem überlagerten Polygon und einer überlagerten Polylinie

Das Beispiel zeigt eine Karte mit verschiedenen MapItems an. Die MapItems werden entweder aus einer GeoJSON-Datei mithilfe der „ GeoJsonData “-API von QtLocation importiert oder vom Benutzer über TapHandlers gezeichnet.

Beispiele für GeoJSON-Dateien finden Sie im Verzeichnis „data“ innerhalb des Beispielverzeichnisses.

Um ein MapItem zu zeichnen, klicken Sie mit der rechten Maustaste auf einen leeren Bereich der Karte und wählen Sie im angezeigten Menü einen Elementtyp Ihrer Wahl aus. Die folgenden Klicks definieren das ausgewählte Element. Das Beispiel ermöglicht das Zeichnen von MapCircles, MapRectangles, MapPolygons und MapPolylines. Elemente, die vollständig durch zwei Punkte definiert sind, d. h. Kreise und Rechtecke, werden mit zwei Klicks der linken Maustaste gezeichnet. Objekte, die durch mehrere Punkte definiert sind, d. h. Polygone und Polylinien, werden durch eine beliebige Anzahl von Klicks mit der linken Maustaste erstellt und mit der rechten Maustaste fertiggestellt. Auf diese Weise gezeichnete Objekte werden als Punkte, Polygone und Polylinien gespeichert, um der GeoJSON-Spezifikation zu entsprechen, siehe https://geojson.org/.

Ausführen des Beispiels

Sie können das Beispiel wie folgt ausführen:

Erstellen einer MapView

Zunächst erstellen wir eine Basiskarte, auf der alle Elemente platziert werden können. Wir nutzen ein „ MapView “-Element, das eine einfache „ Map “ mit Eingabeverarbeitung (Mausrad, Ziehen usw.) kombiniert. Auf die zugrunde liegende „ Map “ kann über die Eigenschaft „ map “ zugegriffen werden. Sollte eine Eigenschaft in „ MapView “ fehlen, kann höchstwahrscheinlich über „ MapView.map “ darauf zugegriffen werden.

MapView {
    id: view
    anchors.fill: parent
    map.plugin: Plugin { name: "osm" }
    map.zoomLevel: 4
    map.center: QtPositioning.coordinate(3, 8)
}

Einrichten des GeoJSON-Modells / Anzeigen von MapItems

Um den Inhalt der Datei auf der Karte anzuzeigen, verwenden wir ein als „Model/View-Programmierung“ bekanntes Entwurfsmuster. Zunächst müssen wir eine geeignete Ansicht einrichten, in diesem Beispiel ein „ MapItemView “-Element. Dessen übergeordnetes Element muss auf die zugrunde liegende Karte von MapView gesetzt werden, damit alle darin platzierten Elemente korrekt angezeigt werden.

MapItemView {
    id: miv
    parent: view.map
}

Als Nächstes benötigen wir ein geeignetes Modell, das ein GeoJSON-Dokument repräsentiert. Zu diesem Zweck bietet „ QtLocation “ das Element „ GeoJsonData “ an, das GeoJSON-Dateien lesen und schreiben kann. Es lässt sich leicht instanziieren

GeoJsonData {
    id: geoDatabase
    sourceUrl: ":/data/11-full.json"
}

und dem ` MapItemView` zugewiesen werden.

model: geoDatabase.model

Die Datei „ 11-full.json “ wird beim Start als Beispiel geladen.

Schließlich benötigen wir ein ` delegate`, das die Modelldaten in eine Darstellung von Elementen übersetzt und damit das ` MapItemView` füllt.

delegate: GeoJsonDelegate {}

Das Element „ GeoJsonDelegate “ wird in der Datei „ GeoJsonDelegate.qml “ deklariert. Es handelt sich um ein „ DelegateChooser “-Element, um den unterschiedlichen Eigenschaften verschiedener Geometrietypen Rechnung zu tragen.

DelegateChooser {
    id: dc
    role: "type"
}

Die ` DelegateChooser ` enthält für jeden Geometrietyp, der in einer GeoJSON-Datei vorkommen kann, eine ` DelegateChoice `. Die Eigenschaft ` role ` wird mit ` DelegateChoice.roleValue ` abgeglichen, um den richtigen Delegaten zu ermitteln.

Beispielsweise wird ein Punkt, der in GeoJSON mit „ "type":"Point" “ beschrieben wird, durch „ MapCircle “ auf „ MapItemView “ dargestellt:

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

Es wird versucht, Eigenschaften des „ MapCircle “, wie beispielsweise „ color “ oder „ radius “, aus der GeoJSON-Datei auszulesen, die in Form der Eigenschaft „modelData“ verfügbar ist. Dies entspricht jedoch keinem strengen GeoJSON-Standard, weshalb für alle Eigenschaften Fallback-Werte festgelegt werden.

MapItems in GeoJSON schreiben

Um MapItems in eine GeoJSON-Datei zu schreiben, können wir einfach die Funktion „ GeoJsonData::saveAs “ mit dem angegebenen Dateinamen aufrufen. Dadurch werden alle Elemente des aktuellen Modells in die angegebene Datei geschrieben. Alle weiteren Elemente, die in die Datei geschrieben werden sollen, müssen zuvor mithilfe der Funktion „ GeoJsonData::addItem “ oder „ GeoJsonData::setModelToMapContents “ zum Modell hinzugefügt werden.

geoDatabase.saveAs(fileWriteDialog.selectedFile)

Benutzerinteraktion mit MapItems

Zur Verarbeitung von Benutzerinteraktionen verwenden wir „ PointHandlers “. Diese eignen sich besonders gut für diese Aufgabe, da sie sich genau an die Form des zugrunde liegenden Elements anpassen – im Gegensatz zu „ MouseArea “, das immer eine quadratische Form abdeckt. „MapItems“, die aus einer GeoJSON-Datei importiert werden, erhalten ihre eigenen „ HoverHandler “ und „ TapHandler “ direkt im Delegaten:

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
}

Die „ TapHandler “ wird verwendet, um beim Antippen des Elements einige Informationen darüber in die Konsole zu schreiben. Die „ HoverHandler “ dient dazu, Elemente hervorzuheben, die unter dem Mauszeiger liegen. Dies wird umgesetzt, indem die Eigenschaft „ border.color “ in Abhängigkeit von der Eigenschaft bzw. dem Zustand „ hovered “ des „ HoverHandler “ beschrieben wird.

Hinzufügen neuer Elemente

Eine Kombination aus „ HoverHandler “ und „ TapHandler “ für die Eigenschaft „ MapView “ ermöglicht es uns, auf Mausbewegungen und Klicks des Benutzers zu reagieren.

Wenn das TapHandler ein singleTapped -Signal aussendet, erstellen oder ändern wir ein neues MapItem auf LeftButton und schließen das MapItem auf RightButton ab. Wenn kein Element zum Abschließen vorhanden ist, öffnet die RightButton ein Menü.

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

Das Signal „ pointChanged “ dient dazu, ein MapItem vorübergehend zu aktualisieren, um dem Benutzer eine Vorschau zu ermöglichen.

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

MapItems werden aus Prototypen generiert, die in separaten QML-Dateien definiert sind. Sie werden mit der Funktion „ createComponent “ erstellt und mit „ addMapItem “ zur Karte hinzugefügt. Ein Verweis auf das neue Element wird gespeichert, damit der Benutzer es weiter bearbeiten kann.

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

Das Hinzufügen des Elements zu „ Map “ reicht aus, um das Element anzuzeigen. Um das Element jedoch weiter nutzen zu können (z. B. zum Speichern in einer Datei), muss es dem Modell hinzugefügt werden. Dies geschieht nach Abschluss der Bearbeitung:

function finishGeoItem()
{
    unfinishedItem.finishAddGeometry()
    geoDatabase.addItem(unfinishedItem)
    map.removeMapItem(unfinishedItem)
    unfinishedItem = undefined
}

Elemente entfernen

Um alle Elemente aus der Karte zu entfernen, rufen wir einfach die Reset-Funktion des „ GeoJsonData “-Objekts auf

function clearAllItems()
{
    geoDatabase.clear();
}

Beispielprojekt @ code.qt.io

© 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.