在Quickwidget openstreet地图中添加/删除标记

时间:2019-06-03 10:01:54

标签: c++ qt qml

我在QT5 gui中使用QQuickwidget。我已经通过相应地添加qml文件在其上加载了一个openstreet地图。 通过在qml文件中添加一个函数,我可以使用QMetaObject :: invokeMethod通过cpp文件对其进行调用。此功能在某些坐标处添加标记。这是因为我想通过c ++代码本身来控制标记。

我的问题:我能够成功加载地图和标记,但是无法删除标记。我的目的是在地图上显示移动物体的路径。因此,我想使用计时器来定期更新其位置。每t_samp秒,我要删除标记并将其添加到其他位置。

使用map.addMapItem(item)将在addMarker代码中创建的“ item”添加到地图中。通过将map.removeMapItem(item)附加到函数,标记消失。但是,问题是,我似乎无法在函数外部访问“项目”。因此,由于无法输入标记,因此无法使用map.removeMapItem。 我还尝试使函数输出为“ item”,以便随后可以使用它来添加/删除标记。不幸的是,我不知道商品的数据类型,因此无法接收它。

mapview.qml:



import QtQuick 2.12
import QtLocation 5.12
import QtPositioning 5.12

Item {

    id: window
    Plugin
    {
        id: mapPlugin
        name:"osm"

    }

    function addMarker(latitude, longitude)
    {
        var component= Qt.createComponent("qrc:///qml/marker.qml")
        var item= component.createObject(window, {coordinate: QtPositioning.coordinate(latitude,longitude)})


        map.addMapItem(item)

    }


    Map
    {
        id: map
        anchors.fill: parent
        plugin: mapPlugin
        center: QtPositioning.coordinate(15.4561,73.8021);
        zoomLevel: 14

    }

}
marker.qml:

import QtQuick 2.12
import QtLocation 5.12
import QtPositioning 5.12

    MapQuickItem
    {
    id: marker
    anchorPoint.x: marker.width / 4
    anchorPoint.y: marker.height

    sourceItem: Image
        {

            id: icon
            source: "qrc:///images/mapmark.png"
            sourceSize.width: 50
            sourceSize.height: 50


        }

    }
mainwindow.cpp: (only relevant snippet)

QObject* target= qobject_cast<QObject*>(ui->quickWidget->rootObject());
    QString functionName= "addMarker";

    QMetaObject::invokeMethod(target,functionName.toUtf8().constData(), Qt::AutoConnection, Q_ARG(QVariant, 15.4561), Q_ARG(QVariant,73.8021));

1 个答案:

答案 0 :(得分:0)

最好将QObject从C ++导出到QML,而不是将QML标记导出到C ++,并且由于要处理多个标记,因此必须使用模型。

方法说明:

MVC模式是Qt处理大量信息的自然方法,为此它实现了诸如MapItemView之类的视图以及可以基于QAbstractXXXModel创建的模型。因此,唯一的责任就是为目标专门化类,例如实现仅保留n个元素的逻辑,如果有新元素,则删除最旧的元素。

为什么将QObject导出到QML更好? QML中的对象生命周期由QML处理,因此在您的情况下,您可以在给定的时间访问标记,QML可以删除标记这样,C ++中的指针将追加非保留的内存。另一个优点是,Q_PROPERTY在QML中可以识别,并且数据类型是QML和C ++已知的,这与将QML对象导出到C ++不同,因为仅会使用QObject或QQuickItem的属性。同样,使用setContextProperty导出时,QObject是全局的。缺点是添加了更多代码。有关更多详细信息,请阅读Interacting with QML from C++

markermodel.h

#ifndef MARKERMODEL_H
#define MARKERMODEL_H

#include <QAbstractListModel>
#include <QGeoCoordinate>

class MarkerModel : public QAbstractListModel
{
    Q_OBJECT
    Q_PROPERTY(QGeoCoordinate current READ current NOTIFY currentChanged)
public:
    enum MarkerRoles{
        PositionRole = Qt::UserRole + 1000,
    };
    explicit MarkerModel(QObject *parent = nullptr);
    void moveMarker(const QGeoCoordinate & coordinate);
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    QHash<int, QByteArray> roleNames() const override;
    int maxMarkers() const;
    void setMaxMarkers(int maxMarkers=0);
    QGeoCoordinate current() const;
signals:
    void currentChanged();
private:
    void insert(int row, const QGeoCoordinate & coordinate);
    void removeLastMarker();
    QList<QGeoCoordinate> m_markers;
    QGeoCoordinate m_current;
    int m_maxMarkers;
};

#endif // MARKERMODEL_H

markermodel.cpp

#include "markermodel.h"

MarkerModel::MarkerModel(QObject *parent)
    : QAbstractListModel(parent),
      m_maxMarkers(0)
{
}

void MarkerModel::moveMarker(const QGeoCoordinate &coordinate)
{
    QGeoCoordinate last = m_current;
    m_current = coordinate;
    Q_EMIT currentChanged();
    if(!last.isValid())
        return;
    if(m_maxMarkers == 0){
        insert(0, last);
        return;
    }
    if(rowCount() >= m_maxMarkers){
        while (rowCount() >= m_maxMarkers)
            removeLastMarker();
        removeLastMarker();
    }
    insert(0, last);
}
int MarkerModel::maxMarkers() const
{
    return m_maxMarkers;
}

void MarkerModel::setMaxMarkers(int maxMarkers)
{
    m_maxMarkers = maxMarkers > 1 ? maxMarkers: 0;
}

QGeoCoordinate MarkerModel::current() const
{
    return m_current;
}

int MarkerModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;
    return m_markers.count();
}

QVariant MarkerModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();
    if(role == PositionRole)
        return QVariant::fromValue(m_markers[index.row()]);
    return QVariant();
}

QHash<int, QByteArray> MarkerModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[PositionRole] = "position";
    return roles;
}

void MarkerModel::insert(int row, const QGeoCoordinate & coordinate)
{
    beginInsertRows(QModelIndex(), row, row);
    m_markers.insert(row, coordinate);
    endInsertRows();
}

void MarkerModel::removeLastMarker()
{
    if(m_markers.isEmpty())
        return;
    beginRemoveRows(QModelIndex(), rowCount()-1, rowCount()-1);
    m_markers.removeLast();
    endRemoveRows();
}

mainwindow.h

// ...
MarkerModel marker_model;
// ...

mainwindow.cpp

// ...
ui->quickWidget->rootContext()->setContextProperty("marker_model", &marker_model);
ui->quickWidget->setSource(QUrl("qrc:/mapview.qml"));
// ...

main.qml

// ...
Map{
    id: map
    anchors.fill: parent
    plugin: mapPlugin
    center: QtPositioning.coordinate(15.4561,73.8021);
    zoomLevel: 14
    Marker{
        coordinate: marker_model.current
    }
    MapItemView{
        model: marker_model
        delegate: Marker{
            coordinate: model.position
        }
    }
}
// ...

完整的示例是here

相关问题