1

我正在使用解决方案沿QPainterPath. 但我需要慢慢增加或减少动画的速度。我创建了一个计时器并为动画设置了一个新的持续时间,但结果是一个断断续续的动画,因为椭圆是从头开始的。有没有更好的方法来实现这一点?

class AnimatedEllipses: public QGraphicsObject
{
    Q_OBJECT
    Q_PROPERTY(int progress READ progress WRITE setProgress)
private:
    QGraphicsPathItem path;
    QList<QGraphicsEllipseItem*> ellipses;
    int propProgress;
    QPropertyAnimation* animation;

public:
    int progress() const { return propProgress;}
    void setProgress(int value)
    {
        propProgress = value;
        int index = 0;
        for (QGraphicsEllipseItem* ellipse: ellipses)
        {
            // Keep value between 0 and length.
            int lgt = (propProgress + index * 40) % int(path.path().length());
            qreal percent = path.path().percentAtLength(lgt);
            ++index;
            ellipse->setPos(path.path().pointAtPercent(percent));
        }
    }
    AnimatedEllipses(QPainterPath const& path): QGraphicsObject(), path(path), propProgress(0)
    {
        qreal pos = 0;
        qreal length = path.length();
        while (pos < length)
        {
            qreal percent = path.percentAtLength(pos);
            QPointF pointAtPercent = path.pointAtPercent(percent);
            pos += 40;
            QGraphicsEllipseItem * item = new QGraphicsEllipseItem(-10, -10, 20, 20, this);
            item->setPos(pointAtPercent);
            ellipses << item;
        }

        animation = new QPropertyAnimation(this, "progress");
        animation->setStartValue(0);
        animation->setEndValue(length);
        animation->setDuration(10000);
        animation->setLoopCount(-1);
        animation->start();

        QTimer *timer = new QTimer();
        connect(timer, SIGNAL(timeout()), this, SLOT(SlotTimeOut()));
        timer->start(1000);
    }

    void SlotTimeOut() {
        int newDuration = GetRandomDuration();
        animation->setDuration(newDuration);
    }

    // QGraphicsItem interface
public:
    QRectF boundingRect() const { return path.boundingRect();}
    void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget){}
};
4

1 回答 1

3

你可以用 custom 做到这一点QEasingCurve。这是进度条值的一个小示例。

主窗口.h

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void OnChangeDurationTimer();

private:
    Ui::MainWindow *ui;
    QPropertyAnimation m_animProgress;
};

初始化

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    m_animProgress.setTargetObject(ui->progressBar);
    m_animProgress.setPropertyName("value");
    m_animProgress.setStartValue(0);
    m_animProgress.setEndValue(100);
    m_animProgress.setDuration(10000);
    m_animProgress.setLoopCount(-1);

    //setting custom QEasingCurve
    QEasingCurve eCurve;
    eCurve.setCustomType(myEasingFunction);
    m_animProgress.setEasingCurve(eCurve);

    m_animProgress.start();

    QTimer::singleShot(3000, this, &MainWindow::OnChangeDurationTimer);  //timer to change duration
}

最有趣的是myEasingFunction自定义 EasingCurve的功能

qreal g_offset = 0;       //value last animation stopped with
qreal g_offsetLast = 0;   //keep current value of animation

qreal myEasingFunction(qreal progress)
{
    qreal val = g_offset + progress;
    while (val > 1) {
        val -= 1;  //normalize
    }
    g_offsetLast = val;
    return val;
}

并更改计时器的持续时间

void MainWindow::OnChangeDurationTimer()
{
    g_offset = g_offsetLast;  //remember stopped value
    m_animProgress.stop();
    m_animProgress.setDuration((rand() % 10 + 1) * 1000);
    m_animProgress.start();

    QTimer::singleShot(3000, this, &MainWindow::OnChangeDurationTimer);  //next changing
}
于 2019-04-05T06:28:11.003 回答