Qt路径动画(一)

使用QPropertyAnimation类结合QPainterPath类实现路径动画效果
效果图
在这里插入图片描述
头文件

#ifndef QWHANIMATIONPATH_H
#define QWHANIMATIONPATH_H

#include <QPainterPath>
#include <QEasingCurve>

class QGraphicsScene;
class QGraphicsProxyWidget;
class QPropertyAnimation;
class QWidget;
class QWHAnimationPath : public QObject
{
    Q_OBJECT
    Q_PROPERTY(qreal m_curPercent READ getCurPercent WRITE setCurPercent)

public:
    enum Type
    {
        COMMON, // 常规
        SLOPE,  // 斜率
    };

    QWHAnimationPath(QGraphicsScene *scene);
    ~QWHAnimationPath();

    // 设置路径
    void setPath(const QPainterPath &path);
    // 设置路径窗口
    void setWidget(QWidget *widget, QGraphicsProxyWidget *proxyWidget);
    // 设置路径动画类型
    void setType(Type type);
    // 设置路径位置初始百分比
    void setStartPercent(qreal startPercent);
    // 设置路径位置结束百分比
    void setEndPercent(qreal endPercent);
    // 设置路径动画时长
    void setDuration(int msecs);
    // 设置路径动画效果过度曲线
    void setEasingCurve(const QEasingCurve &curve);
    // 开启动画
    void start();
    // 暂停动画
    void pause();
    // 结束动画
    void stop();

private:
    // 设置路径位置百分比
    void setCurPercent(qreal percent);
    // 获取路径位置百分比
    qreal getCurPercent();
    // 获取曲线斜率
    qreal angle(const QPointF &p1, const QPointF &p2);

private:
    qreal m_startPercent;                   // 路径位置初始百分比
    qreal m_endPercent;                     // 路径位置结束百分比
    qreal m_curPercent;                     // 路径位置当前百分比
    int m_duration;                         // 路径动画时长
    QEasingCurve m_easingCurve;             // 路径动画效果过度曲线

    QGraphicsScene *m_scene;                // 场景
    QWidget *m_widget;                      // 路径窗口
    QGraphicsProxyWidget *m_proxyWidget;    // 路径代理窗口
    QPainterPath m_path;                    // 路径
    QPropertyAnimation *m_animation;        // 属性动画
    Type m_type;                            // 动画类型
};

#endif // QWHANIMATIONPATH_H

核心代码

void QWHAnimationPath::setCurPercent(qreal percent)
{
    if (m_widget)
    {
        qreal m_lastPercent = m_curPercent;
        m_curPercent = percent;
        QPointF pos = m_path.pointAtPercent(percent);

        if (COMMON == m_type)
            m_proxyWidget->setPos(pos);
        else {// SLOPE == m_type
            QPointF p1 = m_path.pointAtPercent(m_lastPercent);
            QPointF p2 = m_path.pointAtPercent(m_curPercent);
            qreal angle = this->angle(p1, p2);
            m_proxyWidget->setPos(pos);
            m_proxyWidget->setRotation(angle + 90);
        }
    }
}

qreal QWHAnimationPath::angle(const QPointF &p1, const QPointF &p2)
{
    if (abs(p1.x() - p2.x()) < 0.000001)
        return ((p1.y() < p2.y()) ? 90 : -90);

    if (abs(p1.y() - p2.y()) < 0.000001)
        return ((p1.x() < p2.x()) ? 0 : 180);

    qreal angle = 0.0;
    if (p1.x() > p2.x())
        angle = qAtan((p2.y() - p1.y()) / (p2.x() - p1.x())) * 180.0 / M_PI;
    else
        angle = qAtan((p2.y() - p1.y()) / (p2.x() - p1.x())) * 180.0 / M_PI + 180;

    return angle;
}

示例代码

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 视图场景设置
    m_scene = new QGraphicsScene(-800, -450, 1600, 900);
    ui->graphicsView->setScene(m_scene);
    ui->graphicsView->setBackgroundBrush(QColor(213, 240, 247));
    ui->graphicsView->setRenderHint(QPainter::Antialiasing);
    // 成员初始化
    m_commonPath = new QWHAnimationPath(m_scene);
    m_slopePath = new QWHAnimationPath(m_scene);
    m_slopePathLove = new QWHAnimationPath(m_scene);
    m_btn = new QPushButton("路径窗口");
    QGraphicsProxyWidget *proxyWidget = m_scene->addWidget(m_btn);
    proxyWidget->setZValue(100);
    // 图元设置
    m_circleItem = m_scene->addEllipse(-150, -150, 300, 300);
    m_rectItem = m_scene->addRect(-800, -150, 400, 300);

    QPainterPath pathLove;
    pathLove.moveTo(800, -100);
    pathLove.arcTo(600, -200, 200, 200, 0, 180);
    pathLove.arcTo(400, -200, 200, 200, 0, 180);
    pathLove.lineTo(600, 200);
    pathLove.lineTo(800, -100);
    m_pathItem = m_scene->addPath(pathLove, QPen(Qt::red), QBrush(QColor(255, 191, 213)));

    // 普通路径
    QPainterPath path;
    QPolygonF polygonF = m_rectItem->mapToScene(m_rectItem->rect());
    path.addPolygon(polygonF);

    m_commonPath->setPath(path);
    m_commonPath->setWidget(m_btn, proxyWidget);
    m_commonPath->setStartPercent(0.0);
    m_commonPath->setEndPercent(1.0);
    m_commonPath->setDuration(5000);

    // 斜率路径
    QPainterPath path2;
    path2.addEllipse(-150, -150, 300, 300);

    m_slopePath->setPath(path2);
    m_slopePath->setWidget(m_btn, proxyWidget);
    m_slopePath->setType(QWHAnimationPath::SLOPE);
    m_slopePath->setStartPercent(0.0);
    m_slopePath->setEndPercent(1.0);
    m_slopePath->setDuration(5000);

    // 斜率路径Love
    m_slopePathLove->setPath(pathLove.toReversed());
    m_slopePathLove->setWidget(m_btn, proxyWidget);
    m_slopePathLove->setType(QWHAnimationPath::SLOPE);
    m_slopePathLove->setStartPercent(0.0);
    m_slopePathLove->setEndPercent(1.0);
    m_slopePathLove->setDuration(5000);
}
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浮生卍流年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值