Qt动画类实例一

一、简述

前段时间群里小伙伴想写个自定义的控件,二话不说,我就答应帮他写了,结果一拖就拖到了今天。实现起来很简单,简单应用了动画类的效果就OK了。主要是对窗口的pos及新增了一个cornerOpacity属性做了动画处理,实现了窗口在鼠标进出时左右滑动,以及四个边框角的忽隐忽现效果。

图一为Qt动画实现效果:

这里写图片描述


图二为小伙伴提供要实现的效果:
这里写图片描述


二、代码之路

#include "AnimationTest.h"
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPainter>
#include <QDebug>

#define  CORNER_WIDTH 20        // 拐角边框宽度;
#define  CORNER_HEIGHT 6        // 拐角边框高度;

AnimationTest::AnimationTest(QWidget *parent)
    : QWidget(parent)
{
    initTopWidget();

    this->setWindowIcon(QIcon(":/AnimationTest/Resources/icon.jpg"));

    this->setProperty("cornerOpacity", 0.0);

    this->setWindowFlags(Qt::FramelessWindowHint);

    this->setStyleSheet("QWidget{background:white;} \
                        QPushButton{background:rgb(14, 150, 254);border:none;color:white;font-size:18px;font-weight:bold;}\
                        QPushButton:hover{background:rgb(44, 137, 255);}\
                        QPushButton:pressed{background:rgb(14, 135, 228);padding-top:3px;padding-left:3px;}\
                        ");
    this->setFixedSize(QSize(370, 370));
}

// 初始化顶层Widget;
void AnimationTest::initTopWidget()
{
    m_backWidget = new QLabel(this);
    m_backWidget->setObjectName("BackWidget");
    m_backWidget->setFixedSize(QSize(350, 350));
    m_backWidget->setPixmap(QPixmap(":/AnimationTest/Resources/backImage.jpg").scaled(m_backWidget->width(), m_backWidget->height()));

    m_topWidget = new QWidget(m_backWidget);
    m_topWidget->setFixedSize(QSize(350, 350));
    m_topWidget->move(QPoint(-m_topWidget->width(), 0));

    m_moveAnimation = new QPropertyAnimation(m_topWidget, "pos");
    m_moveAnimation->setDuration(300);
    m_moveAnimation->setStartValue(QPoint(-m_topWidget->width(), 0));
    m_moveAnimation->setEndValue(QPoint(0, 0));

    m_opcityAnimation = new QPropertyAnimation(this, "cornerOpacity");
    m_opcityAnimation->setDuration(300);
    m_opcityAnimation->setStartValue(0);
    m_opcityAnimation->setEndValue(1.0);

    connect(m_opcityAnimation, SIGNAL(valueChanged(const QVariant&)), this, SLOT(update()));

    QLabel* topWidgetInfo = new QLabel;
    topWidgetInfo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    topWidgetInfo->setPixmap(QPixmap(":/AnimationTest/Resources/labelInfo.png"));

    QPushButton* pButtonPreview = new QPushButton(QStringLiteral("预览"));
    pButtonPreview->setFixedSize(QSize(100, 50));
    QPushButton* pButtonDownloadJPG = new QPushButton(QStringLiteral("下载JPG"));
    pButtonDownloadJPG->setFixedSize(QSize(100, 50));
    QPushButton* pButtonDownloadPNG = new QPushButton(QStringLiteral("下载PNG"));
    pButtonDownloadPNG->setFixedSize(QSize(100, 50));

    QHBoxLayout* hLayoutLabel = new QHBoxLayout;
    hLayoutLabel->addStretch();
    hLayoutLabel->addWidget(topWidgetInfo);
    hLayoutLabel->addStretch();
    hLayoutLabel->setMargin(0);

    QHBoxLayout* hLayoutButton = new QHBoxLayout;
    hLayoutButton->addStretch();
    hLayoutButton->addWidget(pButtonPreview);
    hLayoutButton->addWidget(pButtonDownloadJPG);
    hLayoutButton->addWidget(pButtonDownloadPNG);
    hLayoutButton->addStretch();
    hLayoutButton->setSpacing(6);
    hLayoutButton->setMargin(0);

    QVBoxLayout* vLayout = new QVBoxLayout(m_topWidget);
    vLayout->addLayout(hLayoutLabel);
    vLayout->addLayout(hLayoutButton);
    vLayout->setMargin(0);
    vLayout->setSpacing(0);

    QHBoxLayout* mainLayout = new QHBoxLayout(this);
    mainLayout->addWidget(m_backWidget);
    mainLayout->setMargin(10);
}

// 进入离开事件;
// 主要进行动画的操作;
void AnimationTest::leaveEvent(QEvent *event)
{
    m_moveAnimation->setStartValue(QPoint(0, 0));
    m_moveAnimation->setEndValue(QPoint(m_topWidget->width(), 0));
    // 注掉以上两行代码使用下面代码则收缩往相反方向;
    // 使用以上两行代码则窗口收缩往相同方向;
//  m_moveAnimation->setDirection(QAbstractAnimation::Backward);
    m_moveAnimation->start();

    m_opcityAnimation->setDirection(QAbstractAnimation::Backward);
    m_opcityAnimation->start();
}

void AnimationTest::enterEvent(QEvent *event)
{
    m_moveAnimation->setStartValue(QPoint(-m_topWidget->width(), 0));
    m_moveAnimation->setEndValue(QPoint(0, 0));
    // 注掉以上两行代码使用下面代码则收缩往相反方向;
    // 使用以上两行代码则窗口收缩往相同方向;
//  m_moveAnimation->setDirection(QAbstractAnimation::Forward);
    m_moveAnimation->start();

    m_opcityAnimation->setDirection(QAbstractAnimation::Forward);
    m_opcityAnimation->start();
}

// 绘制事件,主要绘制四角的边框;
void AnimationTest::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    // 左上角;
    drawCorner(&painter, QPoint(0, 0), 0);
    // 右上角;
    drawCorner(&painter, QPoint(this->width(), 0), 90);
    // 右下角;
    drawCorner(&painter, QPoint(this->width(), this->height()), 180);
    // 左下角;
    drawCorner(&painter, QPoint(0, this->height()), -90);
}

// 绘制单个角的边框;
void AnimationTest::drawCorner(QPainter* painter, QPoint pos, int translateAngle)
{
    painter->save();
    // 通过角度,位置转换进行绘制四个角的边框;
    int transparentValue = 255 * this->property("cornerOpacity").toFloat();
    QBrush rectBrush(QColor(30, 150, 230, transparentValue));
    painter->translate(pos);
    painter->rotate(translateAngle);

    painter->fillRect(QRect(0, 0, CORNER_WIDTH, CORNER_HEIGHT), rectBrush);
    painter->fillRect(QRect(0, 0 + CORNER_HEIGHT, CORNER_HEIGHT, CORNER_WIDTH - CORNER_HEIGHT), rectBrush);
    painter->restore();
}

代码很简单,创建了两个动画类对象实现了以上效果,通过QPropertyAnimation 动画类我们可以实现更多好玩的效果,关键还是在于尝试。

下面简单介绍一下几个常用的动画类方法。

// 设置动画持续效果;
void setDuration(int msecs)


// 控制动画的变化曲线;
void setEasingCurve(const QEasingCurve & easing)
下面可以看到几个枚举值代表着变化的不同趋势。

这里写图片描述

// 设置动画的起始值;
void setStartValue(const QVariant & value)

// 设置动画的结束值;
void setEndValue(const QVariant & value)

上面两个是对应起来的,就拿上面移动位置举例,把widget从位置1移动到位置2,那么位置1就是起始值,位置2就是结束值(解释的挺2的)。

当然单纯这样的话我们可以通过时钟来把widget从位置1移动到位置2,效果也是一样的,不过简单的时钟的效果可能只能实现下面这种曲线效果。更复杂的可能相对麻烦,所以直接用动画类方便、快捷。

这里写图片描述


// 开始/结束 动画效果
void start(QAbstractAnimation::DeletionPolicy policy = KeepWhenStopped)

void stop()

下面为start()方法的参数,也就是动画结束之后是否删除该对象。

这里写图片描述


以上写了一个简单的小例子以及简单地介绍了一下动画类,更多的在于大家的尝试。

晚安哈 O(∩_∩)O!


代码下载

Qt动画类实例一

猜你喜欢

转载自blog.csdn.net/goforwardtostep/article/details/78650341