【问题标题】:Animating MapQuickItem in QML on position updates在 QML 中为 MapQuickItem 设置位置更新动画
【发布时间】:2020-01-17 01:42:40
【问题描述】:

我有一个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
               ...

但是,尽管对象的位置在每次位置更新时都会正确更新,但朝向未来估计位置的动画根本不起作用。

如何去做这样的事情?

【问题讨论】:

    标签: qt animation qml coordinates


    【解决方案1】:

    在它的代码中,它做了一个绑定coordinate: data.coords,声明“坐标”取“坐标”的值,但同时又说“坐标”取决于动画,是不是矛盾?嗯,这是矛盾的。

    想法不是绑定coordinate: data.coords,而是仅通过动画更新属性。

    以下代码是一个可行的例子:

    ma​​in.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
    

    下面link是完整的例子

    【讨论】:

    • Eyllanesc,这是一篇极好的帖子。它不仅解决了我的问题,而且我同时学到了其他一些东西。赞一个!
    猜你喜欢
    • 2019-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多