Измените продолжительность QPropertyAnimation на лету - PullRequest
0 голосов
/ 05 апреля 2019

Я использую это решение для анимации эллипсов вдоль 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){}
};

1 Ответ

2 голосов
/ 05 апреля 2019

Вы можете сделать это с помощью пользовательского QEasingCurve. Вот небольшой пример для значения индикатора выполнения.

mainwindow.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;
};

1010 * Initialization *

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
}
...