Qt自定义动画移动路径

在使用Qt实现动画时,一般使用QPropertyAnimation来实现,一般我们实现控件的移动动画都是走直线,我们如何实现自己想要的移动路径呢,比如走圆弧。下面介绍通过QPropertyAnimation实现自定义动画移动路径,比如走圆曲线、圆弧曲线等

pos动画属性

#include "myanimation.h"

MyAnimation::MyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent):
    QPropertyAnimation (target, propertyName, parent)
{
    setPathType(LinearPath);
}

void MyAnimation::setPathType(MyAnimation::PathType pathType)
{
    if (pathType >= NPathTypes)
        qWarning("Unknown pathType %d", pathType);

    m_pathType = pathType;
    m_path = QPainterPath();
}

void MyAnimation::updateCurrentTime(int currentTime)
{
    if (m_pathType == CirclePath || m_pathType == ArcPath) {
        if (m_path.isEmpty()) {
            QPointF to = endValue().toPointF();
            QPointF from = startValue().toPointF();
            m_path.moveTo(from);
            if(m_pathType == CirclePath) {
                m_path.addEllipse(QRectF(from, to));
            }
            else {
                qreal tempWidth = from.rx() - to.rx();
                qreal tempHeight = from.ry() - to.ry();
                QRectF tempRect = QRectF(to.x() - tempWidth, to.y(), tempWidth*2, tempHeight*2);
                m_path.arcTo(tempRect, 0, 90);
            }
        }
        int dura = duration();
        const qreal progress = ((dura == 0) ? 1 : ((((currentTime - 1) % dura) + 1) / qreal(dura)));

        qreal easedProgress = easingCurve().valueForProgress(progress);
        if (easedProgress > 1.0) {
            easedProgress -= 1.0;
        } else if (easedProgress < 0) {
            easedProgress += 1.0;
        }
        QPointF pt = m_path.pointAtPercent(easedProgress);
        updateCurrentValue(pt);
        emit valueChanged(pt);
    } else {
        QPropertyAnimation::updateCurrentTime(currentTime);
    }
}

调用

m_pMyAnmation = new MyAnimation(ui->pushButton, "pos", this);
m_pMyAnmation->setDuration(1000);
m_pMyAnmation->setStartValue(QPointF(400, 350));
m_pMyAnmation->setEndValue(QPointF(200, 100));
m_pMyAnmation->setPathType(MyAnimation::ArcPath);

直线动画

圆曲线动画

圆弧曲线

通过重载updateCurrentTime,根据时间节点取到自定义路径的位置,更新updateCurrentValue的值;对于自定义路径,实例中采用QPainterPath绘制圆和圆弧,也可使用QPainterPath绘制直线与圆弧组合等,也可实现其他曲线路径,如sin曲线等。

geometry动画属性

上面例子使用的是pos属性,也可以使用geometry,实现位置与大小组合的动画效果

    QRectF startVal = startValue().toRectF();
    QRectF endVal = endValue().toRectF();

    qreal startWidth = startVal.width();
    qreal startHeight = startVal.height();
    qreal endWidth = endVal.width();
    qreal endHeigth = endVal.height();

    if (m_path.isEmpty()) {
        QPointF to = endVal.topLeft();
        QPointF from = startVal.topLeft();
        m_path.moveTo(from);

        qreal tempWidth = from.rx() - to.rx();
        qreal tempHeight = from.ry() - to.ry();
        QRectF tempRect = QRectF(to.x() - tempWidth, to.y(), tempWidth*2, tempHeight);
        m_path.lineTo(QPointF(from.rx(), from.ry() - tempHeight/2.));
        m_path.arcTo(tempRect, 0, 90);
    }
    int dura = duration();
    const qreal progress = ((dura == 0) ? 1 : ((((currentTime - 1) % dura) + 1) / qreal(dura)));

    qreal easedProgress = easingCurve().valueForProgress(progress);
    if (easedProgress > 1.0) {
        easedProgress -= 1.0;
    } else if (easedProgress < 0) {
        easedProgress += 1.0;
    }
    QPointF pt = m_path.pointAtPercent(easedProgress);

    QSizeF size = QSizeF(endWidth + startWidth * (1 - easedProgress), endHeigth + startHeight * (1 - easedProgress));
    QRectF retRect = QRectF(pt, size);
    updateCurrentValue(retRect);
    emit valueChanged(retRect);

调用:

    m_pMyAnmation = new MyAnimation(ui->pushButton, "geometry", this);
    m_pMyAnmation->setDuration(600);
    m_pMyAnmation->setStartValue(QRectF(400, 350, 60, 50));
    m_pMyAnmation->setEndValue(QRectF(200, 100, 0, 0));

效果

pos的值采用圆弧曲线的方式,size使用线性的方式,即根据运行百分比获取size的大小

运行的进度会再根据easingCurve来取值,所以可以使用设置相应的缓动曲线,具体效果看该博客https://blog.csdn.net/a137748099/article/details/107292996

m_pMyAnmation->setEasingCurve(QEasingCurve::InQuint);

例子代码下载https://download.csdn.net/download/a137748099/18485759

参考:Qt官方例子easing

  • 5
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Qt自定义Tree(树)是指开发者可以根据自己的需求对Qt中的Tree控件进行定制和扩展。 首先,在Qt中,Tree控件常用的有QTreeWidget和QTreeView两种。 QTreeWidget是一个直接继承自QTreeWidget类的控件,使用它可以很方便地创建一个简单的树形控件。我们可以通过addItem()方法来添加子项,通过setHeaderLabels()方法来设置表头(列标题),以及通过setExpanded()方法来设置节点的展开与折叠。 如果我们需要更复杂的树形控件,就可以使用QTreeView。QTreeView允许我们通过使用自定义的模型(QAbstractItemModel的子类)来完全自定义树形控件的数据和样式。我们可以继承QAbstractItemModel类并实现其抽象方法来创建自己的模型,通过设置setModel()方法将自定义模型与QTreeView关联起来。 在自定义模型中,我们可以通过重写data()方法来返回树形控件中的数据,重写headerData()方法来设置表头数据,重写flags()方法来设置节点的编辑和选择状态等。 此外,如果需要对树形控件中的节点进行自定义绘制,我们可以通过重写QTreeView的paintEvent()方法来实现。在该方法中,我们可以使用painter对象进行绘制,绘制每个节点的背景、文本等内容。 除了模型和绘制,我们还可以使用样式表(Qt Style Sheets)来对树形控件的样式进行自定义。样式表可以设置每个节点的背景、前景颜色,调整行高、缩进等等。 总之,Qt提供了丰富的API和机制,使开发者能够灵活自定义Tree控件。通过继承、重写方法、使用自定义模型、样式表等方式,开发者可以根据需求实现各种复杂的树形控件。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值