图形项目通过QGraphicsItemAnimation跳转到路径末尾而不移动

时间:2013-09-09 12:46:58

标签: qt animation

我有一个圆圈,我想在路径上顺利移动。路径类类似于从QPainterPath派生的水平U.当我启动计时器(QTimeLine对象)时,圆圈只是从路径的开始跳到结束(上部U叉的开始到下部叉的末端),没有平滑的动画。不幸的是,QTimeLine :: setLoopCount(int n)也不起作用。

你对这个原因有什么看法吗?

// UPath(int forkLen, int forksDistance, QPointF startPoint)
UPath* uPath = new UPath(500, 60, QPointF(10, 10));

QList<QPointF> points = uPath->pathPoints(0.006); // returns the points of the path
                                                  // implemented by QPainterPath::pointAtPercent()

QGraphicsItem *ball = new QGraphicsEllipseItem(0, 0, 10, 10);

QTimeLine *timer = new QTimeLine(5000);
timer->setFrameRange(0, 100);
timer->setLoopCount(2);    // doesn't work

QGraphicsItemAnimation *animation = new QGraphicsItemAnimation;
animation->setItem(ball);
animation->setTimeLine(timer);

for (int i = 0; i < points.count(); ++i)
    animation->setPosAt(i/points.count(), points.at(i));

QGraphicsScene *scene = new QGraphicsScene();
scene->addItem(ball);

QGraphicsView *view = new QGraphicsView(scene);
view->setRenderHint(QPainter::Antialiasing);
view->show();

timer->start();

1 个答案:

答案 0 :(得分:2)

不推荐使用QGraphicsAnimation类。你想要的是QPainterPath和动画系统之间的适配器。请参阅下面的完整示例。

使用画家路径制作动画需要一些额外的平滑(重新取样),因为路径上会有速度变化,看起来并不那么好。运行下面的代码时,您可能会注意到它。画家路径用于绘画,而不是用于制作动画。

这种不当行为的程度将取决于您使用的路径类型,因此最终可能会对您所使用的特定用例工作正常。

#include <QApplication>
#include <QAbstractAnimation>
#include <QPainterPath>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsEllipseItem>
#include <QDebug>

class PathAnimation : public QAbstractAnimation {
    Q_OBJECT
    Q_PROPERTY(int duration READ duration WRITE setDuration)
    QPainterPath m_path;
    int m_duration;
    QVector<QPointF> m_cache;
    QGraphicsItem * m_target;
    int m_hits, m_misses;
public:
    PathAnimation(const QPainterPath & path, QObject * parent = 0) :
        QAbstractAnimation(parent), m_path(path), m_duration(1000), m_cache(m_duration), m_target(0), m_hits(0), m_misses(0) {}
    ~PathAnimation() { qDebug() << m_hits << m_misses; }
    int duration() const { return m_duration; }
    void setDuration(int duration) {
        if (duration == 0 || duration == m_duration) return;
        m_duration = duration;
        m_cache.clear();
        m_cache.resize(m_duration);
    }
    void setTarget(QGraphicsItem * target) {
        m_target = target;
    }
    void updateCurrentTime(int ms) {
        QPointF point = m_cache.at(ms);
        if (! point.isNull()) {
            ++ m_hits;
        } else {
            point = m_path.pointAtPercent(qreal(ms) / m_duration);
            m_cache[ms] = point;
            ++ m_misses;
        }
        if (m_target) m_target->setPos(point);
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsEllipseItem * item = new QGraphicsEllipseItem(-5, -5, 10, 10);
    item->setPen(QPen(Qt::red, 2));
    item->setBrush(Qt::lightGray);

    QPainterPath path;
    path.addEllipse(0, 0, 100, 100);
    PathAnimation animation(path);
    animation.setTarget(item);

    QGraphicsScene scene;
    scene.addItem(item);
    QGraphicsView view(&scene);
    view.setSceneRect(-50, -50, 200, 200);

    animation.setLoopCount(-1);
    animation.start();
    view.show();

    return a.exec();
}

#include "main.moc"