简体   繁体   中英

Qt animate ellipses along the circle

I am new to the Qt and I am confused how to use the QGraphicsScene . If I add for example 10 ellipses to the scene and animate them along the path, how would I do it? It gets even more complicated, because if I have 10 ellipses drawn along the ellipse and I want to animate those ellipses so they move away from the cente of the ellipse they are on. In the picture you can see the ellipses. Those are drawn with QPainter I haven't figured out how to add them to scene, but I would like the grey ellipses to move in between the inner and outter circle. I have gone through some examples, but can't really fit any of those to my situation.

Code used to draw ellipses with QPainter:

QPainter drElps;
drElps.setBrush(QBrush(QColor(0xaf, 0xaf, 0xaa)));
drElps.setPen(QPen(QColor(0xaf, 0xaf, 0xaa), 2));
double nrElps = 30;
int degree = (int)(360./nrElps);
painter.translate(QPointF(big_elps_circle_center));
while(--nrElps){
 painter.drawEllipse(0, -60, 3, 3);
 painter.rotate(degree);
}
painter.translate(QPOintF(back_to_origin));

静态图像

If you draw them with QPainter then you are on your on. The point of QGraphivsScene is to inherit from QGraphicsItem, paint what you need to paint on the paintEvent, add them to the scene.

you are drawint more than 1 item on your paintEvent - so you are on your own - and QGraphivsScene cannot help you there.

Now, how to do that Correctly:

  • Inherit from QGraphicsScene or QGraphivsView
  • Inherit from QGraphicsEllipseItem and create a MovableEllipseItem
  • in the MovableEllipseItem constructor, create a QTimer, connect it's timeout() signal with a move slot that you will define

on your move slot, do the calculations on where the ellipse should be and move(x,y) it.

You can use a custom Graphics Item, the QGraphicsScene::advance mechanism, together with a QTimeLine to control the animation.

The outline is like this:

QGraphicsScene *sc = new QGraphicsScene;
QTimeLine *tl = new QTimeLine(1000);
tl->setFrameRange(-20, 20);
connect(tl, &QTimeLine::frameChanged, sc, &QGraphicsScene::advance);
connect(tl, &QTimeLine::finished, tl, &QTimeLine::toggleDirection);
connect(tl, &QTimeLine::finished, tl, &QTimeLine::start);

for (int i = 0; i < 30; ++i) {
    sc->addItem(new AnimItem(360./30*i, tl));
}

In the custom AnimItem, you implement the drawing/animation logic. A good base would be QGraphicsEllipseItem . For example:

AnimItem::AnimItem(qreal angle, QTimeLine *timer, QGraphicsItem *parent)
    : QGraphicsEllipseItem(0, 0, 3, 3, parent),
      m_timer(timer)
{
    QTransform t;
    t.rotate(angle);
    t.translate(0, -120);
    setTransform(t);
    setBrush(QBrush(QColor(0xaf, 0xaf, 0xaa)));
}

void AnimItem::advance(int phase)
{
    if (phase == 1) {
        QTransform t = transform();
        t.translate(0, m_timer->currentFrame()/5);
        setTransform(t);
    }
}

Qt has a set of classes oriented to the animations, for this you must first create an object that inherits from QGraphicsObject , in this class you must implement the methods paint and boundingRect .

ellipseobject.h

#ifndef ELLIPSEOBJECT_H
#define ELLIPSEOBJECT_H

#include <QGraphicsObject>

class EllipseObject : public QGraphicsObject
{
    Q_OBJECT
public:
    EllipseObject(QGraphicsItem * parent = 0);

    void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
    QRectF boundingRect() const;
};

#endif // ELLIPSEOBJECT_H

ellipseobject.cpp

#include "ellipseobject.h"

#include <QPainter>

EllipseObject::EllipseObject(QGraphicsItem *parent):QGraphicsObject(parent)
{

}

void EllipseObject::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option)
    Q_UNUSED(widget)
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setPen(QColor(0xaf, 0xaf, 0xaa));
    painter->setBrush(QBrush(QColor(0xaf, 0xaf, 0xaa)));
    QRectF rect = boundingRect();
    painter->drawEllipse(rect);
}

QRectF EllipseObject::boundingRect() const
{
    return QRectF(-4, -4, 8, 8);
}

Then we can use the QPropertyAnimation class, with this we will animate the position.

EllipseObject *item = new EllipseObject;
QPropertyAnimation *animation = new QPropertyAnimation(item, "pos");
for(int j = 0; j < p; j++){
    animation->setKeyValueAt( 1.0*j/(p-1),
                               (r+ delta*sin(2*M_PI*j/p) )*QPointF(qSin(2*M_PI*i/number_of_items), qCos(2*M_PI*i/number_of_items)));
}
animation->setDuration(2000);

Since we have several elements that are animated in parallel, we can use QParallelAnimationGroup to handle each of the animations.

group = new QParallelAnimationGroup(this);
[...]
group->addAnimation(animation);

If we want to be continuous we can make the following code.

group->start();
connect(group, &QParallelAnimationGroup::finished,[=](){
    group->start();
});

The complete code is here .

在此输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM