在 QML 中为 MapQuickItem 设置位置更新动画
Posted
技术标签:
【中文标题】在 QML 中为 MapQuickItem 设置位置更新动画【英文标题】:Animating MapQuickItem in QML on position updates 【发布时间】: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
...
但是,尽管对象的位置在每次位置更新时都会正确更新,但朝向未来估计位置的动画根本不起作用。
如何去做这样的事情?
【问题讨论】:
【参考方案1】:在它的代码中,它做了一个绑定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
下面link是完整的例子
【讨论】:
Eyllanesc,这是一篇极好的帖子。它不仅解决了我的问题,而且我同时学到了其他一些东西。赞一个!以上是关于在 QML 中为 MapQuickItem 设置位置更新动画的主要内容,如果未能解决你的问题,请参考以下文章