曾經收到過一份禮物,一個雪花飄落的程序,覺得效果很炫,通過前幾篇的學習,我們已經掌握了貼圖的一些技巧了,那么現在就可以自己實現了(當然你必須先擁有qt信號與槽的基礎知識),這里先看效果,然后再分析如何實現。
效果圖:
這個程序實現很久了,也是當初學習qt的時候寫的,因為工作的原因,當初的部分設想,並沒有全部實現,現在分享,供大家一起學習。
當初的設想:
1、雪花隨機飄落
2、地面的花草,可以支持自由的move操作
3、地面的植物可以積聚到雪花。
因為工作的原因,第3點並沒有實現,有興趣的可以自己實現,接下來講解一下實現步奏。
實現方案:
1、SnowNode雪花節點類,定義雪花的形狀、初始化狀態、行為
2、WaitFallen待飄落的雪花類,用於定時向屏幕投入雪花
3、Snowfalling 正在飄落的雪花,定時掃描雪花是否到達地上,雪花到達地上時,發送信號
4、Snowpack 地上的積雪,定時將積雪回收
5、GroundLife 地面物體
Vegetable 植物
6、SnowFrame雪花畫面,對雪花進行統一管理功能插件:
PngButton 圖片按鈕
WidgetMove 普通的按鈕移動
Virtual3DMove 將按鈕虛擬成三維效果,按鈕移動時進行放大和縮小
變量收集:
雪花池數量: 200
向屏幕投送雪花間隔: 1000
每次投送雪花數量:0-5
雪花飄落全程時間:10秒
關鍵點實現:
1、主窗體設置
1: //讓程序無邊框
2: setWindowFlags( Qt::FramelessWindowHint );
3: //讓程序背景透明
4: setAttribute(Qt::WA_TranslucentBackground, true);
2、建立雪花池、飄落、回收的聯動,形成一個循環系統
1: connect(&m_snowWait, SIGNAL(falling(SNOWLIST*)), &m_snowFalling, SLOT(AcceptSnow(SNOWLIST*)));
2: connect(&m_snowFalling, SIGNAL(snowLander(SNOWLIST*)), &m_snowLander, SLOT(LanderSnow(SNOWLIST*)));
3: connect(&m_snowLander, SIGNAL(snowRecycle(SNOWLIST*)), &m_snowWait, SLOT(SnowRecycle(SNOWLIST*)));
3、每一朵雪花我們可以用一個button來承載,並為每一朵雪花定義飄落的行為。
雪花節點頭文件:
1: #include <QToolButton>
2: #include <QPropertyAnimation>
3: class QPixmap;
4: class QPaintEvent;
5: class QPoint;
6: class QSize;
7:
8: class SnowNode : public QToolButton
9: {
10: public:
11: static const int MAXSWOW ;
12: SnowNode(QWidget *parent = 0);
13: QSize GetSnowSize();
14: bool IsLander();
15: void InitSnow();
16: void FallingAnimation();
17:
18: protected:
19: void paintEvent(QPaintEvent *event);
20: private:
21: QString GetImgFileName();
22: private:
23: QPixmap m_pixmap;
24: QPropertyAnimation *m_animation;
25: QSize m_areaSize;
26: };
雪花節點實現文件:
1: #include "pubbase.h"
2: #include "snownode.h"
3: #include <QSize>
4: #include <QPoint>
5: #include <QBitmap>
6: #include <QPixmap>
7: #include <QToolButton>
8: #include <QApplication>
9: #include <QDesktopWidget>
10: #include <QGraphicsScene>
11: #include <QGraphicsView>
12: const int SnowNode::MAXSWOW = 19;
13:
14: SnowNode::SnowNode(QWidget *parent):
15: QToolButton(parent),m_animation(new QPropertyAnimation(this, "geometry"))
16: {
17: //必須設置為無邊框,否則可見區域和圖片繪制區域將出現不重疊
18: setWindowFlags( Qt::FramelessWindowHint );
19: resize(GetSnowSize());
20: //對圖片進行縮放
21: m_pixmap.load(GetImgFileName());
22: m_pixmap = m_pixmap.scaled(this->size(),Qt::IgnoreAspectRatio);
23: setHidden(true);
24: m_areaSize.setWidth(QApplication::desktop()->width());
25: m_areaSize.setHeight(QApplication::desktop()->height());
26: }
27:
28: //初始化雪花
29: void SnowNode::InitSnow()
30: {
31: this->move(qrand() % m_areaSize.width(), -32);
32: }
33:
34: //設置雪花動畫
35: void SnowNode::FallingAnimation()
36: {
37: int x = qrand()% m_areaSize.width();
38: //雪花飄落全程時間
39: m_animation->setDuration(8000);
40: m_animation->setStartValue(QRect( pos(), size()));
41: m_animation->setEndValue(QRect( QPoint(x,m_areaSize.height()), size()));
42: m_animation->start();
43: }
44:
45: //返回雪花是否已着陸
46: bool SnowNode::IsLander()
47: {
48: if(this->pos().y() >= m_areaSize.height()
49: && m_animation->state() == QAbstractAnimation::Stopped
50: )
51: {
52: return true;
53: }
54: return false;
55: }
56:
57: void SnowNode::paintEvent(QPaintEvent *event)
58: {
59: //繪制背景圖片
60: this->setIcon(QIcon(m_pixmap));
61: this->setIconSize(size());
62: //將png圖片透明部分設置為穿透
63: this->setMask(m_pixmap.mask());
64: //繪制
65: QToolButton::paintEvent(event);
66:
67: }
68:
69: //每一朵雪花的大小,采用隨機生成
70: QSize SnowNode::GetSnowSize()
71: {
72: int x = qrand() % 10;
73: return x >= 6 ? QSize(32,32) : x >= 3 ? QSize(24,24) : QSize(16,16);
74: }
75:
76: //獲取雪花文件名
77: QString SnowNode::GetImgFileName()
78: {
79: return QString().sprintf(":/image/_%d.png", qrand()% MAXSWOW);
80: }
81:
4、替換一個桌面背景
1: 調用windows API函數來設置桌面背景
2: ::SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, (void*)imgFileName, SPIF_UPDATEINIFILE)
5、定義一個定時器,定時投放雪花即可

