Qt QPropertyAnimation动画实现雪花飘落

做了一个雪花飘落的程序,参考了以下两篇文章。雪花是以波浪线飘落。雪花用QToolButton添加图片制成。雪花在下落时会曲线移动,通过继承QPropertyAnimation来设置移动曲线。

参考文章:Qt实现桌面动态背景雪花飘落程序 - 零落年华 - 博客园

QT QPainter绘制图形-动态正弦曲线(水波效果)_jmlinux的博客-CSDN博客

snownode.cpp //雪花类

#include "snownode.h"
#include <QSize>
#include <QPoint>
#include <QBitmap>
#include <QPixmap>
#include <QToolButton>
#include <QApplication>
#include <QDesktopWidget>
#include <QGraphicsScene>
#include <QGraphicsView>
const int SnowNode::MAXSWOW = 19;

SnowNode::SnowNode(QWidget *parent):
    QToolButton(parent),m_animation(new MyAnimation(this, "pos"))
{
    //必须设置为无边框,否则可见区域和图片绘制区域将出现不重叠
    setWindowFlags( Qt::FramelessWindowHint );
    resize(GetSnowSize());
    //对图片进行缩放
    m_pixmap.load(GetImgFileName());
    m_pixmap = m_pixmap.scaled(this->size(),Qt::IgnoreAspectRatio);
    setHidden(true);
    m_areaSize.setWidth(QApplication::desktop()->width());
    m_areaSize.setHeight(QApplication::desktop()->height());
}

//初始化雪花
void SnowNode::InitSnow()
{
    this->move(qrand() % m_areaSize.width(), -32);
}

//设置雪花动画
void SnowNode::FallingAnimation()
{
    int x = qrand()% m_areaSize.width();
	//雪花飘落全程时间
    m_animation->setDuration(8000);
    m_animation->setStartValue(pos());
    m_animation->setEndValue(QPoint(x,m_areaSize.height()));
    m_animation->start();
}

//返回雪花是否已着陆
bool SnowNode::IsLander()
{
    if(this->pos().y() >= m_areaSize.height()
        && m_animation->state() == QAbstractAnimation::Stopped)
    {
        return true;
    }
    return false;
}

void SnowNode::paintEvent(QPaintEvent *event)
{
    //绘制背景图片
    this->setIcon(QIcon(m_pixmap));
    this->setIconSize(size());
    //将png图片透明部分设置为穿透
    this->setMask(m_pixmap.mask());
    //绘制
    QToolButton::paintEvent(event);

}

//每一朵雪花的大小,采用随机生成
QSize SnowNode::GetSnowSize()
{
    int x = qrand() % 10;
    return x >= 6 ? QSize(32,32) : x >= 3 ? QSize(24,24) : QSize(16,16);
}

//获取雪花文件名
QString SnowNode::GetImgFileName()
{
    return QString().sprintf(":/image/_%d.png", qrand()% MAXSWOW);
}

myanimation.cpp//动画类,实现移动路线

#include "myanimation.h"
#include <QtMath>

MyAnimation::MyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent):
    QPropertyAnimation(target, propertyName, parent)
{

}

void MyAnimation::updateCurrentTime(int currentTime)
{
    if (m_path.isEmpty())
    {
        QPoint to = endValue().toPoint();
        QPoint from = startValue().toPoint();
        int height=to.y() - from.y();
        //正弦曲线公式 y = A * sin(ωx + φ) + k
        double w = M_PI/200;  //w为角速度 ,可以理解为波浪的密度,越大密度越大
        double A = 40;    //  A表示振幅,可以理解为水波的高度,越大高度越高
        double k = from.x();    //  k表示y轴偏移
        int offset = to.x() - from.x();

        for(int y = from.y(); y <= to.y(); y++)  //x从0~w的值而改变,从而得到正弦曲线
        {
            double waveX = (double)(A * qSin(w * y)) + k + y * offset / height;// waveY随着x的值改变而改变,从而得到正弦曲线
            if (y == from.y())
            {
                m_path.moveTo(waveX, y);
            }
            m_path.lineTo(waveX, y);   //从上一个绘制点画一条线到(x,waveY);
        }
    }
    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);
}

mainwindow.cpp//界面类,设置雪花飘落的逻辑

#include "mainwindow.h"
#include <QKeyEvent>
#include <QPixmap>
#include <QBitmap>
#include <QTime>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    //让程序无边框
    setWindowFlags( Qt::FramelessWindowHint );
    //让程序背景透明
    setAttribute(Qt::WA_TranslucentBackground, true);

    InitEnv();

    m_timeManager = new QTimer(this);
    connect( m_timeManager,SIGNAL(timeout()), SLOT(SnowFalling()));
    m_timeManager->start(500);

    m_snowPool = 100;
    for(int i=0; i<m_snowPool; ++i)
    {
        SnowNode* node = new SnowNode(this);
        Q_ASSERT(node);
        m_snowWaitList.append(node);
    }
}

//初始化资源
void MainWindow::InitEnv()
{
    //初始化随机数种子
    qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
}

MainWindow::~MainWindow()
{
	
}

void MainWindow::keyPressEvent( QKeyEvent * event )
{
    //按下esc键时,关闭
    if(event->key() == Qt::Key_Escape)
    {
        close();
    }
}

void MainWindow::AcceptShow(QList<SnowNode*> addList)
{
    foreach (SnowNode* var, addList)
    {
        Q_ASSERT(var);
        m_snowFallingList.append(var);
        var->FallingAnimation();
    }
    QList<SnowNode*> landerList;

    for(int i=0; i<m_snowFallingList.size(); )
    {
        if (!m_snowFallingList.at(i)->IsLander())
        {
            ++i;
            continue;
        }
        landerList.append(m_snowFallingList.at(i));
        m_snowFallingList.removeAt(i);
    }
    if (landerList.size() > 0)
    {
        emit SnowRecycle(landerList);
    }
}

void MainWindow::SnowFalling()
{
    QList<SnowNode*> fallingList;
    int count = qrand() % 4;

    for (int i=0; i< count; i++)
    {
        SnowNode *node = m_snowWaitList.first();
        node->InitSnow();
        node->setHidden(false);
        fallingList.append(node);
        m_snowWaitList.pop_front();
    }

    if (fallingList.size() > 0)
    {
        AcceptShow(fallingList);
    }
}

void MainWindow::SnowRecycle(QList<SnowNode*> addList)
{
    for (int i=0; i<addList.size(); ++i)
    {
        m_snowWaitList.append(addList.at(i));
    }
}

最后效果如下

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值