Анимация MapQuickItem в QML при обновлении позиции - PullRequest
1 голос
/ 17 января 2020

У меня есть объект QAbstractListModel, в котором содержится список предметов, отображаемых на карте. Положение этих предметов меняется каждые несколько секунд, и в будущем легко будет рассчитать довольно точное положение через 60 секунд. Я пытаюсь установить позицию элемента, когда он получает новую позицию (эта часть работает хорошо), а затем немедленно переместить элемент в направлении вычисленной будущей позиции.

Код без анимации выглядит следующим образом и он отлично работает:

    Component {
       id: drawTarget

       MapQuickItem {
           id: marker

           coordinate: data.coords

           sourceItem: Item {
               id: item
               ...

У объекта data есть свойство, которое возвращает предполагаемое положение элемента через 60 секунд в будущем, поэтому я попытался это сделать:

    Component {
       id: drawTarget

       MapQuickItem {
           id: marker

           coordinate: data.coords

           CoordinateAnimation {
               id:anim
               property: "coordinate"
           }

           onCoordinateChanged: {
               anim.stop()
               anim.from = data.coords
               anim.to = data.coordsIn60sec
               anim.duration = 60000
               anim.start()
           }           

           sourceItem: Item {
               id: item
               ...

Но хотя позиция объекта обновляется должным образом при каждом обновлении позиции, анимация в отношении будущей оценочной позиции вообще не работает.

Как можно go сделать что-то подобное?

1 Ответ

1 голос
/ 17 января 2020

В своем коде он создает привязку coordinate: data.coords, которая утверждает, что «координата» принимает значение «координаты», но в то же время говорит, что «координата» зависит от анимации, не так ли это противоречиво? Ну, это противоречиво.

Идея состоит не в том, чтобы связывать coordinate: data.coords, а в том, чтобы обновлять свойство только с помощью анимации.

Следующий код является работоспособным примером:

main.qml

import QtQuick 2.14
import QtQuick.Window 2.14
import QtLocation 5.6
import QtPositioning 5.6

Window {
    visible: true
    width: 640
    height: 480
    Plugin {
        id: mapPlugin
        name: "osm"
    }
    Map {
        anchors.fill: parent
        plugin: mapPlugin
        center: QtPositioning.coordinate(59.91, 10.75) // Oslo
        zoomLevel: 10
        MapItemView{
            model: datamodel
            delegate: MapQuickItem{
                id: item
                // begin configuration
                property var position: model.position
                property var nextposition: model.nextposition
                onPositionChanged: restart();
                onNextpositionChanged: restart();
                function restart(){
                    anim.stop()
                    anim.from = position
                    anim.to = nextposition
                    anim.start()
                }
                CoordinateAnimation {
                    id: anim
                    target: item
                    duration: 60 * 1000
                    property: "coordinate"
                }
                // end of configuration
                anchorPoint.x: rect.width/2
                anchorPoint.y: rect.height/2
                sourceItem: Rectangle{
                    id: rect
                    color: "green"
                    width: 10
                    height: 10
                }
            }
        }
    }
}

datamodel.h

#ifndef DATAMODEL_H
#define DATAMODEL_H

#include <QAbstractListModel>
#include <QGeoCoordinate>
#include <QTimer>
#include <random>

#include <QDebug>

struct Data{
    QGeoCoordinate position;
    QGeoCoordinate nextposition;
};

static QGeoCoordinate osloposition(59.91, 10.75); // Oslo;

class DataModel : public QAbstractListModel
{
    Q_OBJECT
    QList<Data> m_datas;
public:
    enum PositionRoles {
        PositionRole = Qt::UserRole + 1,
        NextPositionRole
    };
    explicit DataModel(QObject *parent = nullptr)
        : QAbstractListModel(parent)
    {
        init();
    }
    int rowCount(const QModelIndex &parent = QModelIndex()) const override{
        return parent.isValid() ? 0: m_datas.count();
    }
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override{
        if (!index.isValid() || index.row() < 0 || index.row() >= m_datas.count())
            return QVariant();
        const Data &data = m_datas[index.row()];
        if (role == PositionRole)
            return QVariant::fromValue(data.position);
        else if (role == NextPositionRole)
            return QVariant::fromValue(data.nextposition);
        return QVariant();
    }
    QHash<int, QByteArray> roleNames() const override{
        QHash<int, QByteArray> roles;
        roles[PositionRole] = "position";
        roles[NextPositionRole] = "nextposition";
        return roles;
    }
private:
    void init(){
        for(int i=0; i< 10; ++i){
            Data data;
            data.position = osloposition;;
            data.nextposition = data.position;
            m_datas << data;
        }
        QTimer *timer = new QTimer(this);
        QObject::connect(timer, &QTimer::timeout, this, &DataModel::updateData);
        timer->start(60 * 1000);
        updateData();
    }
    void updateData(){
        qDebug() << __PRETTY_FUNCTION__;
        static std::default_random_engine e;
        static std::uniform_real_distribution<> dis(-.1, .1);
        for(int i=0; i < m_datas.count(); ++i){
            Data & data = m_datas[i];
            QModelIndex ix = index(i);
            data.position = data.nextposition;
            data.nextposition = QGeoCoordinate(osloposition.latitude() + dis(e),
                                           osloposition.longitude() + dis(e));
            Q_EMIT dataChanged(ix, ix, {PositionRole, NextPositionRole});
        }
    }
};

#endif // DATAMODEL_H

В следующей ссылке - полный пример

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...