Qt动画椭圆沿圆

Posted

技术标签:

【中文标题】Qt动画椭圆沿圆【英文标题】:Qt animate ellipses along the circle 【发布时间】:2017-04-23 20:19:35 【问题描述】:

我是 Qt 新手,对如何使用 QGraphicsScene 感到困惑。如果我在场景中添加例如 10 个椭圆并沿路径为它们设置动画,我会怎么做?它变得更加复杂,因为如果我沿着椭圆绘制了 10 个椭圆并且我想为这些椭圆设置动画,以便它们远离它们所在的椭圆的中心。在图片中,您可以看到椭圆。这些是用QPainter 绘制的,我还没有弄清楚如何将它们添加到场景中,但我希望灰色椭圆在内外圆之间移动。我已经浏览了一些示例,但其中的任何一个都不能真正适合我的情况。

使用 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));

【问题讨论】:

您可以显示您使用 QPainter 实现的代码。 @eyllanesc 我已经添加了代码。因为我现在没有可用的代码,所以我根据我的记忆编写了这段代码。 【参考方案1】:

Qt 有一组面向动画的类,为此您必须首先创建一个继承自QGraphicsObject 的对象,在该类中您必须实现方法paintboundingRect

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);

然后我们可以使用QPropertyAnimation 类,我们将为位置设置动画。

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);

由于我们有多个并行动画的元素,我们可以使用QParallelAnimationGroup 来处理每个动画。

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

如果我们想要连续,我们可以编写以下代码。

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

完整代码为here。

【讨论】:

这是迄今为止最好的,虽然它不是我想要的,但它给出了一个非常清晰的想法。虽然我认为我将它与 advance() 方法结合使用 BTW github 链接导致空 Qt 项目。 advance(),这是什么意思? QGraphicsSceneadvance() 方法可以在超时时调用,类似于下面的@king_nak 答案 在你的问题中你没有说什么,我提出了一个对我来说最适合这类任务的解决方案。 除了项目库code之外,已经更新了你想要的代码。【参考方案2】:

如果您使用 QPainter 绘制它们,那么您就可以开始了。 QGraphivsScene的重点是继承自QGraphicsItem,在paintEvent上绘制需要绘制的内容,添加到场景中。

您在您的paintEvent 上绘制了超过 1 个项目 - 所以您只能靠自己 - 而 QGraphivsScene 无法帮助您。

现在,如何正确地做到这一点:

从 QGraphicsScene 或 QGraphivsView 继承 从 QGraphicsEllipseItem 继承并创建一个 MovableEllipseItem 在 MovableEllipseItem 构造函数中,创建一个 QTimer,将它的 timeout() 信号与您将定义的移动槽连接起来

在你的移动槽上,计算椭圆的位置并移动(x,y)。

【讨论】:

我是否理解正确,那么对于添加到场景中的每个椭圆,都会有一个单独的计时器? 如果您将 QTimer 作为静态添加到 Ellipse 对象内,那么您将只有一个。重要的是将 timeout() 连接到每个 Ellipse 实例。【参考方案3】:

您可以使用自定义图形项,QGraphicsScene::advance 机制,以及 QTimeLine 来控制动画。

大纲是这样的:

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));

在自定义 AnimItem 中,您实现绘图/动画逻辑。一个好的基础是QGraphicsEllipseItem。例如:

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动画椭圆沿圆的主要内容,如果未能解决你的问题,请参考以下文章

CAShapeLayer 动画路径毛刺/闪烁(从椭圆到矩形并返回)

C4D搭配椭圆动态及闪动控制动画效果

java 特殊的java应用程序,具有椭圆形的简单图形动画。

C4D搭配动画效果

Silverlight & Blend动画设计系列六:动画技巧(Animation Techniques)之对象与路径转化波感特效

Qt炫酷动画专栏导航目录