QT QmlMap PolyLine не обновляется должным образом при изменении базовой модели - PullRequest
0 голосов
/ 24 декабря 2018

Я пытаюсь соединить несколько GeoCoordinates с ломаной линией на моей карте.Координаты хранятся в классе модели (QAbstractListModel), где я могу изменять (удалять и добавлять) Coords в C ++.

Просто отображение маркеров для каждой координаты работает нормально, но когда я соединяю их с полилинией и удаляю некоторые существующие координаты из моей модели, полилиния не обновляется.

map.qml

import QtQuick 2.0
import QtLocation 5.6
import QtPositioning 5.6

Item {
    width: 512
    height: 512
    visible: true

    id: mainWindow

    Map { //our map
        anchors.fill: parent
        id: map
        plugin: mapPlugin
        zoomLevel: 14
        focus: true

        Plugin {
            id: mapPlugin
            name: "osm"
        }

        MapItemView {
            model: markerModel
            delegate: mapcomponent
        }

        MapItemView {
            model: markerModel
            delegate: MapPolyline {
                antialiasing: true
                line.color: "darkBlue"
                line.width: 3
                path: pathRole
            }
        }

        Component {
            id: mapcomponent
            MapQuickItem{
                id: marker
                coordinate: positionRole
                sourceItem: Image{
                    id: markerimage
                    width: 20
                    height: 30
                    source: "qrc:/marker.png"
                }
                anchorPoint.x: markerimage.width / 2
                anchorPoint.y: markerimage.height
            }
        }

        MouseArea {
            anchors.fill: parent

            onClicked: {
                var coord = parent.toCoordinate(Qt.point(mouse.x,mouse.y))
                markerModel.addMarker(coord)
            }
        }
    }
}

markermodel.h , в котором хранятся координаты

class MarkerModel : public QAbstractListModel {
    Q_OBJECT
public:
    using QAbstractListModel::QAbstractListModel;
    enum MarkerRoles{positionRole = Qt::UserRole, pathRole};

    Q_INVOKABLE void addMarker(const QGeoCoordinate &coordinate) {
        beginInsertRows(QModelIndex(), rowCount(), rowCount());
        m_coordinates.append(coordinate);
        endInsertRows();
    }

    int rowCount(const QModelIndex &parent = QModelIndex()) const override {
        Q_UNUSED(parent)
        return m_coordinates.count();
    }

    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override {
        if(row + count > m_coordinates.count() || row < 0)
            return false;

        beginRemoveRows(parent, row, row+count-1);
        for(int i = 0; i < count; ++i)
            m_coordinates.removeAt(row + i);
        endRemoveRows();

        return true;
    }

    bool removeRow(int row, const QModelIndex &parent = QModelIndex()) {
        return removeRows(row, 1, parent);
    }

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
        if (index.row() < 0 || index.row() >= m_coordinates.count())
            return QVariant();
        if(role == Qt::DisplayRole)
            return QVariant::fromValue(index.row());
        if(role == MarkerModel::positionRole)
            return QVariant::fromValue(m_coordinates[index.row()]);        
        if(role == MarkerModel::pathRole) {
            QVariantList coordlist;
            for(auto &geocoord : m_coordinates)
                coordlist << QVariant::fromValue(geocoord);

            return coordlist;
        }

        return QVariant();
    }

    QHash<int, QByteArray> roleNames() const {
        QHash<int, QByteArray> roles;
        roles[positionRole] = "positionRole";
        roles[pathRole] = "pathRole";
        return roles;
    }

private:
    QList<QGeoCoordinate> m_coordinates;
};

GIF-файл, показывающий моипроблема:

enter image description here

Я что-то упустил при удалении строк в моей модели?Есть ли способ заставить qml визуализировать полилинию с совершенно новыми данными из модели?

Ответы [ 2 ]

0 голосов
/ 25 декабря 2018

Поскольку они указывают, что в вашем коде есть логическая ошибка, в своем ответе я покажу реализацию, поскольку @ GrecKo уже объяснил правильную логику:

markermodel.h

#ifndef MARKERMODEL_H
#define MARKERMODEL_H

#include <QAbstractListModel>
#include <QGeoCoordinate>

class MarkerModel : public QAbstractListModel {
    Q_OBJECT
    Q_PROPERTY(QVariantList path READ path NOTIFY pathChanged)
public:
    enum MarkerRoles{positionRole = Qt::UserRole, pathRole};
    MarkerModel(QObject *parent=nullptr): QAbstractListModel(parent)
    {
        connect(this, &QAbstractListModel::rowsInserted, this, &MarkerModel::pathChanged);
        connect(this, &QAbstractListModel::rowsRemoved, this, &MarkerModel::pathChanged);
        connect(this, &QAbstractListModel::dataChanged, this, &MarkerModel::pathChanged);
        connect(this, &QAbstractListModel::modelReset, this, &MarkerModel::pathChanged);
        connect(this, &QAbstractListModel::rowsMoved, this, &MarkerModel::pathChanged);
    }

    Q_INVOKABLE void addMarker(const QGeoCoordinate &coordinate) {
        beginInsertRows(QModelIndex(), rowCount(), rowCount());
        m_coordinates.append(coordinate);
        endInsertRows();
    }
    int rowCount(const QModelIndex &parent = QModelIndex()) const override {
        if(parent.isValid()) return 0;
        return m_coordinates.count();
    }
    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override {
        if(row + count > m_coordinates.count() || row < 0)
            return false;
        beginRemoveRows(parent, row, row+count-1);
        for(int i = 0; i < count; ++i)
            m_coordinates.removeAt(row + i);
        endRemoveRows();
        return true;
    }

    bool removeRow(int row, const QModelIndex &parent = QModelIndex()) {
        return removeRows(row, 1, parent);
    }

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
        if (index.row() < 0 || index.row() >= m_coordinates.count())
            return QVariant();
        if(role == Qt::DisplayRole)
            return QVariant::fromValue(index.row());
        else if(role == MarkerModel::positionRole)
            return QVariant::fromValue(m_coordinates[index.row()]);
        return QVariant();
    }
    QHash<int, QByteArray> roleNames() const override{
        QHash<int, QByteArray> roles;
        roles[positionRole] = "positionRole";
        return roles;
    }
    QVariantList path() const{
        QVariantList path;
        for(const QGeoCoordinate & coord: m_coordinates){
            path << QVariant::fromValue(coord);
        }
        return path;
    }
signals:
    void pathChanged();
private:
    QList<QGeoCoordinate> m_coordinates;
};

#endif // MARKERMODEL_H

*. Qml

import QtQuick 2.0
import QtLocation 5.6
import QtPositioning 5.6

Item {    
    width: 512
    height: 512
    visible: true

    id: mainWindow

    Map { //our map
        anchors.fill: parent
        id: map
        plugin: mapPlugin
        zoomLevel: 14
        focus: true

        Plugin {
            id: mapPlugin
            name: "osm"
        }

        MapItemView {
            model: markerModel
            delegate: mapcomponent
        }

        MapPolyline{
            antialiasing: true
            line.color: "darkBlue"
            line.width: 3
            path: markerModel.path
        }

        Component {
            id: mapcomponent
            MapQuickItem{
                id: marker
                coordinate: positionRole
                sourceItem: Image{
                    id: markerimage
                    width: 20
                    height: 30
                    source: "qrc:/marker.png"
                }
                anchorPoint.x: markerimage.width / 2
                anchorPoint.y: markerimage.height
            }
        }

        MouseArea {
            anchors.fill: parent

            onClicked: {
                var coord = parent.toCoordinate(Qt.point(mouse.x,mouse.y))
                markerModel.addMarker(coord)
            }
        }
    }
}
0 голосов
/ 24 декабря 2018

Наличие pathRole не имеет особого смысла здесь.Эта роль одинакова для всех рядов вашей модели.Вы отображаете n MapPolyline, где n - количество координат, вам нужна только одна для всей вашей модели.

Я бы посоветовал вам удалить pathRole и просто выставить свойство path в вашей модели.и отправьте сигнал уведомления в addMarker и removeRows.

...