用QTimeLine实现滑动动画

一般在Qt实现动画可以用QAbstractAnimation的子类实现。这里给出一个不一样的例子实现动画,即用QTimeLine实现。功能是有一个QStackedWidget,它有两个子页面。默认显示第一页。点击“动画”按钮播放一段动画使页面第一页滑动到第二页,然后切换到第二页。程序测试环境是VS2017和Qt5.9。下面是程序的两张截图:

头文件:

/* 我们用视觉效果绘制两个子Widget同时出现的效果 */
class MSlideEffect : public QGraphicsEffect
{
    Q_OBJECT
    Q_PROPERTY(qreal ratio READ ratio WRITE setRatio)

public:
    MSlideEffect(QObject *parent = 0);
    void setFirstWidget(QWidget* first);
    void setSecondWidget(QWidget* second);
    qreal ratio() const;
    void setRatio(qreal ratio);

private:
    void draw(QPainter *painter) override;

private:
    qreal moveRatio; // [0,1]
    QPixmap p1;
    QPixmap p2;
};

CPP文件。下述代码中QtTest是主窗口类。为了简单在主窗口里只有一个QStackedWidget,它是ui.swSelect。ui.swPage1和ui.swPage2是ui.swSelect的两个子页面。另外,下方代码中的QTimeLine*可以手动释放,而不必等到程序结束才释放:

QtTest::QtTest(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
}

//---------------------------------------------------------------------------------------
// 播放第一页切换到第二页的滑动动画
//---------------------------------------------------------------------------------------
void QtTest::on_pbFlash_clicked()
{
    MSlideEffect* effect = new MSlideEffect(this);
    effect->setFirstWidget(ui.swPage1);
    effect->setSecondWidget(ui.swPage2);
    ui.swSelect->setGraphicsEffect(effect);

    QTimeLine* timeLine = new QTimeLine(250, this);
    timeLine->setFrameRange(0, 500);
    timeLine->setCurveShape(QTimeLine::EaseInOutCurve);
    connect(timeLine, &QTimeLine::frameChanged, this, 
        [effect](int frame) { effect->setRatio(frame / 500.0); });
    connect(timeLine, &QTimeLine::finished, this,
        [this]() { ui.swSelect->setCurrentIndex(1); ui.swSelect->setGraphicsEffect(0); });
    timeLine->start();

    /* 播放动画的时候隐藏它们 */
    /* 因为在某些情况下它会影响动画显示 */
    ui.swPage1->hide();
    ui.swPage2->hide();
}

/////////////////////////////////////////////////////////////////////////////////////////

MSlideEffect::MSlideEffect(QObject *parent) : 
    QGraphicsEffect(parent)
{
    moveRatio = 0;
}

void MSlideEffect::setFirstWidget(QWidget* first)
{
    p1 = first->grab();
}

void MSlideEffect::setSecondWidget(QWidget* second)
{
    second->resize(p1.size());
    p2 = second->grab();
}

void MSlideEffect::draw(QPainter *painter)
{
    int full = p1.width();
    int offset = int(full * moveRatio);
    painter->translate(-offset, 0);
    painter->drawPixmap(0, 0, p1);
    painter->drawPixmap(full, 0, p2);
}

qreal MSlideEffect::ratio() const
{
    return moveRatio;
}

void MSlideEffect::setRatio(qreal ratio)
{
    moveRatio = ratio;
    update();
}

 

posted @ 2024-02-25 19:15  兜尼完  阅读(30)  评论(0编辑  收藏  举报