利用GDI+基于WIN32实现桌面雪花效果(一)
来源:互联网 发布:sdrsharp软件下载 编辑:程序博客网 时间:2024/06/05 10:01
前言:毕业论文写完了,闲着没事干,研究研究这些一直想做的效果,先从桌面飘雪花开始,下面是过程记录。最后给出代码,供大家参考。
效果图:(桌面局部截图)
一、创建空WIN32工程并初始化
1、创建空WIN32工程(snow)
2、设置
项目-》属性-》配置属性-》MFC的使用-》在静态库中使用MFC
3、初始化GDI+和MFC库函数
新建一个Common.h文件,用来存放一些公用的结构体及代码,并在其中初始化GDI+,在其中放下如下代码来初始化GDI+
- #include <gdiplus.h>
- #pragma comment(lib,"GdiPlus.lib")
- using namespace Gdiplus;
在stdafx.h中添加如下代码:(添加对MFC类和所有函数库支持)
- #include <math.h>
- #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的
- // 关闭 MFC 对某些常见但经常可放心忽略的警告消息的隐藏
- #define _AFX_ALL_WARNINGS
- #include <afxwin.h> // MFC 核心组件和标准组件
- #include <afxext.h> // MFC 扩展
- #include <afxdisp.h> // MFC 自动化类
- #ifndef _AFX_NO_OLE_SUPPORT
- #include <afxdtctl.h> // MFC 对 Internet Explorer 4 公共控件的支持
- #endif
- #ifndef _AFX_NO_AFXCMN_SUPPORT
- #include <afxcmn.h> // MFC 对 Windows 公共控件的支持
- #endif // _AFX_NO_AFXCMN_SUPPORT
二、新建应用程序入口类(派生自CWinApp)
新建一个类(CSnowApp),该类派生自MFC的CWinApp类,(在头文件右击-》添加-》类)
头文件代码如下:
- #pragma once
- #include "Common.h"
- // CSnowApp
- class CSnowApp : public CWinApp
- {
- DECLARE_DYNCREATE(CSnowApp)
- public:
- CSnowApp(); // 动态创建所使用的受保护的构造函数
- virtual ~CSnowApp();
- public:
- virtual BOOL InitInstance();
- virtual int ExitInstance();
- protected:
- DECLARE_MESSAGE_MAP()
- public:
- ULONG_PTR m_gdiplusToken;
- BOOL RegisterClass(LPCTSTR lpszClassName);
- };
- extern CSnowApp theApp;
然后自己写了一个窗口类注册函数,完整代码如下:
- BOOL CSnowApp::RegisterClass(LPCTSTR lpszClassName)
- {
- WNDCLASS wndcls;
- memset(&wndcls,0,sizeof(WNDCLASS));
- wndcls.style=CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
- wndcls.lpfnWndProc=::DefWindowProc;
- wndcls.hInstance=AfxGetInstanceHandle();
- wndcls.hIcon=NULL;
- wndcls.hCursor=::LoadCursor(NULL,IDC_ARROW);
- wndcls.hbrBackground=(HBRUSH)(COLOR_BTNFACE+1);
- wndcls.lpszMenuName=NULL;
- wndcls.lpszClassName=lpszClassName;
- if(!AfxRegisterClass(&wndcls))
- {
- TRACE("Class Registration Failed\n");
- return FALSE;
- }
- return TRUE;
- }
- BOOL CSnowApp::InitInstance()
- {
- // TODO: 在此执行任意逐线程初始化
- //初始化GDI+
- GdiplusStartupInput gdiplusStartupInput;
- GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
- //初始化应用程序
- CWinApp::InitInstance();
- //注册窗口类
- if (!RegisterClass(L"CometAnimationUI"))
- {
- return FALSE;
- }
- //创建窗口
- CSnowWindow snowWnd;
- snowWnd.Create(NULL);
- //将snowWnd作为主窗体HWND,传给m_pMainWnd,供其显示窗体
- m_pMainWnd=&snowWnd;
- Run();
- return TRUE;
- }
- int CSnowApp::ExitInstance()
- {
- // TODO: 在此执行任意逐线程清理
- GdiplusShutdown(m_gdiplusToken);
- return CWinApp::ExitInstance();
- }
三、雪花窗体显示
这里分析两个问题:
- 我们并不是将每个雪花创建一个窗口,而是将当前屏幕做为窗体,在它上面画图而已。
- 雪花的种类是有限的,即原始图片,这里加载了六个,而大家可以看到,整个屏幕的雪花量却是很大的,所以我们要建一个基类完成原始图像加载、窗体刷新等功能。而雪花类则建立在此基类的基础上,完成雪花的下落、移动等功能。
1、定义单个雪花图片对象
- typedef struct tagAnimationImage
- {
- Gdiplus::Image* pImage;
- int X; //图片的X坐标
- int Y; //图片的Y坐标
- int Width; //图片显示高度
- int Height; //图片显示宽度
- int Angle; //旋转角度
- bool firstInit; //是否初步初始化,用于在初次初始化时设定该雪花是往左走还是往右走还是直线下落
- int OffsetMode; //图片的行走方式,向左、向右、向下三种
- } AnimationImage, *PAnimationImage,*LPAnimationImage;
2、雪花窗体基类CLayeredWnd(派生自CWnd)
CLayeredWnd头文件如下:
- class CLayeredWnd : public CWnd
- {
- DECLARE_DYNAMIC(CLayeredWnd)
- public:
- CLayeredWnd();
- virtual ~CLayeredWnd();
- protected:
- DECLARE_MESSAGE_MAP()
- public:
- int m_nWidth;
- int m_nHeight;
- CArray<LPAnimationImage,LPAnimationImage> m_ImageArray;//图片数组
- int m_ImageCount;//图片数量
- public:
- // 载入图片
- BOOL LoadImage(LPAnimationImage pImage,LPCTSTR lpName);
- // 添加图片到数组
- LPAnimationImage AddImage(LPCTSTR lpName);
- // 释放图片数组
- void ReleaseImage();
- // 重新绘制窗口
- void ReDrawWindow(void);
- // 虚函数 绘制窗口
- virtual void OnDrawWindow(Gdiplus::Graphics* pGraphics);
- };
m_ImageArray:存储原始图片,即加载的六张雪花图;
m_ImageCount:数组的长度,即存储的原始图片的个数;
成员函数就不讲解功能了,每个函数上面都有标注;
具体实现:
加载图片:LoadImage()
- BOOL CLayeredWnd::LoadImage(LPAnimationImage pImage,LPCTSTR lpPath)
- {
- //初始化空间
- if(pImage->pImage)
- {
- delete pImage->pImage;
- pImage->pImage=NULL;
- }
- ZeroMemory(pImage,sizeof(AnimationImage));
- //加载图片
- pImage->pImage = Gdiplus::Image::FromFile(lpPath);
- if(!pImage->pImage)
- return FALSE;
- pImage->Width=pImage->pImage->GetWidth();
- pImage->Height=pImage->pImage->GetHeight();
- return TRUE;
- }
增加图片:AddImage()
- LPAnimationImage CLayeredWnd::AddImage(LPCTSTR lpPath)
- {
- LPAnimationImage pImage=new AnimationImage;
- ZeroMemory(pImage,sizeof(AnimationImage));
- LoadImage(pImage,lpPath);
- m_ImageArray.Add(pImage);
- m_ImageCount=m_ImageArray.GetCount();
- return pImage;
- }
重绘窗口:ReDrawWindow
- void CLayeredWnd::ReDrawWindow(void)
- {
- HDC hDC=::GetDC(m_hWnd);
- HDC hMemDC=::CreateCompatibleDC(hDC);
- BITMAPINFO bitmapinfo;
- bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bitmapinfo.bmiHeader.biBitCount = 32;
- bitmapinfo.bmiHeader.biHeight = m_nHeight;
- bitmapinfo.bmiHeader.biWidth = m_nWidth;
- bitmapinfo.bmiHeader.biPlanes = 1;
- bitmapinfo.bmiHeader.biCompression=BI_RGB;
- bitmapinfo.bmiHeader.biXPelsPerMeter=0;
- bitmapinfo.bmiHeader.biYPelsPerMeter=0;
- bitmapinfo.bmiHeader.biClrUsed=0;
- bitmapinfo.bmiHeader.biClrImportant=0;
- bitmapinfo.bmiHeader.biSizeImage = bitmapinfo.bmiHeader.biWidth * bitmapinfo.bmiHeader.biHeight * bitmapinfo.bmiHeader.biBitCount / 8;
- HBITMAP hBitmap=CreateDIBSection (hMemDC,&bitmapinfo, 0,NULL, 0, 0);
- HBITMAP hOldBitmap = (HBITMAP)SelectObject (hMemDC,hBitmap);
- Graphics g(hMemDC);
- //-------------------------------------------------------------
- OnDrawWindow(&g);
- //设置透明窗口-------------------------------------------------
- CPoint DestPt(0,0);
- CSize psize(m_nWidth,m_nHeight);
- BLENDFUNCTION blendFunc32bpp;
- blendFunc32bpp.AlphaFormat = AC_SRC_ALPHA;
- blendFunc32bpp.BlendFlags = 0;
- blendFunc32bpp.BlendOp = AC_SRC_OVER;
- blendFunc32bpp.SourceConstantAlpha = 255;
- ::UpdateLayeredWindow(m_hWnd,hDC,NULL,&psize,hMemDC,&DestPt,0,&blendFunc32bpp,ULW_ALPHA);
- //释放资源-------------------------------------------------
- ::SelectObject (hMemDC,hOldBitmap);
- ::DeleteObject(hBitmap);
- ::DeleteDC(hMemDC);
- ::ReleaseDC(m_hWnd,hDC);
- }
最后在整个画布完成以后,利用UpdateLayeredWindow更新到窗体上显示出来。
3、雪花显示窗体类CSnowWindow
头文件内容如下:
- class CSnowWindow :
- public CLayeredWnd
- {
- public:
- CSnowWindow(void);
- ~CSnowWindow(void);
- private:
- CArray<LPAnimationImage,LPAnimationImage> m_SnowArray;//雪花图片数组
- int m_SnowCount;//雪花图片数量
- int m_RowCount;//每行图片数量
- int m_AllCount;//可显示图片总数
- public:
- DECLARE_MESSAGE_MAP()
- afx_msg void OnTimer(UINT_PTR nIDEvent);
- public:
- //创建窗体
- BOOL Create(HWND hWndParent=NULL);
- //初始化初次显示界面
- void InitImage();
- //添加原始图片资源到CLayeredWnd的m_ImageArray中
- void AddResImg(LPCTSTR lpName,int nAngle);
- //向m_SnowArray添加雪花图片
- void AddSnow(int nCount);
- //下移雪花
- void DownSnow();
- //根据上限和下限,随机产生一个数字
- int GetRndNum(int nMin,int nMax);
- public:
- //绘制当前界面,重写CLayeredWnd的此虚函数
- virtual void OnDrawWindow(Gdiplus::Graphics* pGraphics);
- };
- void CSnowWindow::InitImage()
- {
- AddResImg(_T("C:\\Snow01.png"),0);
- AddResImg(_T("C:\\Snow02.png"),0);
- AddResImg(_T("C:\\Snow03.png"),-1);
- AddResImg(_T("C:\\Snow04.png"),-1);
- AddResImg(_T("C:\\Snow05.png"),0);
- AddResImg(_T("C:\\Snow06.png"),0);
- AddResImg(_T("C:\\Snow07.png"),0);
- AddResImg(_T("C:\\Snow08.png"),0);
- AddResImg(_T("C:\\Snow09.png"),0);
- AddResImg(_T("C:\\Snow10.png"),0);
- AddResImg(_T("C:\\Snow11.png"),0);
- AddResImg(_T("C:\\Snow12.png"),0);
- m_RowCount=m_nWidth/(m_ImageArray[0]->Width+20);
- m_AllCount=m_RowCount*(m_nHeight/(m_ImageArray[0]->Height+20));
- AddSnow(m_RowCount);
- }
- //添加要显示的雪花图片到CLayeredWnd的m_ImageArray中
- void CSnowWindow::AddResImg(LPCTSTR lpName,int nAngle)
- {
- LPAnimationImage pImage=AddImage(lpName);
- pImage->Angle=nAngle;
- }
- //添加雪花图片
- void CSnowWindow::AddSnow(int nCount)
- {
- for(int i=0;i<nCount;i++)
- {
- //随机取一张图片
- int nIndex=GetRndNum(0,m_ImageCount-1);
- LPAnimationImage pImage=new AnimationImage;
- LPAnimationImage pSrcImage=m_ImageArray[nIndex];
- CopyMemory(pImage,pSrcImage,sizeof(AnimationImage));
- //随机设置图片的初始位置
- pImage->X=GetRndNum(0,m_nWidth);
- pImage->Y=0-GetRndNum(pImage->Height,pImage->Height*2);
- //随机缩放图片
- float f=(float)GetRndNum(50,100);
- f=f/(float)100;
- pImage->Width=(int)((float)pImage->Width*f);
- pImage->Height=(int)((float)pImage->Height*f);
- pImage->firstInit=true;//初始化为TRUE,此参数用来判定是否首次初始化OffsetMode参数
- m_SnowArray.Add(pImage);
- }
- m_SnowCount=m_SnowArray.GetCount();
- }
1、AddResImg()实现根据图片路径将图片加载到CLayeredWnd的m_ImageArray中
2、AddSnow()实现随机从m_ImageArray中取一张图片,并对其初始化,最后将其添加到m_SnowArray中。
3、InitImage()就是实现了初次显示的雪花图片的初始化工作,AddSnow(m_RowCount);将每行所具有的雪花个数的图片,以第一行显示出来。
在初次顶端雪花初始化完成以后,就要定时将雪花图片移动(下移和平移)
1、设置定时器
由于是定时刷新当前界面以使雪花下移,所以必定要设定定时器,并对WM_TIMER消息进行处理,下面看对WM_TIMER消息处理的代码:
- void CSnowWindow::OnTimer(UINT_PTR nIDEvent)
- {
- // TODO: 在此添加消息处理程序代码和/或调用默认值
- CLayeredWnd::OnTimer(nIDEvent);
- DownSnow();
- }
- //下移雪花图片
- void CSnowWindow::DownSnow()
- {
- int nTop=25;
- for(int i=m_SnowCount-1;i>=0;i--)
- {
- LPAnimationImage pImage=m_SnowArray[i];
- pImage->Y+=5;//下移
- if(pImage->Y>m_nHeight)//超出屏幕高度
- {
- m_SnowArray.RemoveAt(i);//移除这张图片
- delete pImage;
- continue;//转到下一次循环
- }
- //-------------
- if(pImage->Y<nTop)
- nTop=pImage->Y;//找到当前最后一个雪花离屏幕顶部的距离
- //横向移动
- if (pImage->firstInit)
- {
- pImage->firstInit=false;
- pImage->OffsetMode=GetRndNum(1,3);
- }
- switch (pImage->OffsetMode)
- {
- case 1:
- pImage->X--;
- break;
- case 2:
- pImage->X++;
- break;
- }
- }
- m_SnowCount=m_SnowArray.GetCount();
- int nCount=m_AllCount-m_SnowCount;
- if(nCount>0 && nTop>20)//设定每行的竖向间隔,这里设定每20个像素显示一行雪花
- {
- if(nCount>m_RowCount)
- nCount=m_RowCount;
- AddSnow(nCount);
- }
- ReDrawWindow();
- }
1、for循环中对每个雪花进行平移和下移。
2、如何产生下一行雪花。
注意这里有几句代码:
首先定义了一个距离,25个像素。
- <span style="color:#006600;">int nTop=25;</span>
- if(pImage->Y<nTop)
- nTop=pImage->Y;//找到当前最后一个雪花离屏幕顶部的距离
由于当雪花落在屏幕边界外后,会将雪花从数组中删除,而且随着雪花的下落,屏幕上还要继续落雪花,新产生的行所具有的要求是:
(1)、数量不能超,而且不能少
这里使用int nCount=m_AllCount-m_SnowCount;nCount=m_RowCount;来设定每行要显示的雪花数量。
(2)、每行雪花的行距
上面说了利用nTop来找到最后一个雪花离屏幕的距离(20-25),所以当nTop>20的时候,说明是时候显示下一行了,这时才可以显示,不然就挤在一块了。
- m_SnowCount=m_SnowArray.GetCount();
- int nCount=m_AllCount-m_SnowCount;
- if(nCount>0 && nTop>20)//设定每行的竖向间隔,这里设定每20个像素显示一行雪花
- {
- if(nCount>m_RowCount)
- nCount=m_RowCount;
- AddSnow(nCount);
- }
3、调用CLayeredWnd的ReDrawWindow()
由于在ReDrawWindow中调用了虚函数OnDrawWindow(),根据虚函数性质,会调用CSnowWindow重写的OnDrawWindow函数,看OnDrawWindow的实现:
- // 虚函数 绘制窗口
- void CSnowWindow::OnDrawWindow(Gdiplus::Graphics* pGraphics)
- {
- for(int i=0;i<m_SnowCount;i++)
- {
- LPAnimationImage pImage=m_SnowArray[i];
- pGraphics->DrawImage(pImage->pImage,pImage->X,pImage->Y,pImage->Width,pImage->Height);
- }
- }
到这里,本文雪花飘落相关的东东已经介绍完成了,下篇在此基础上完成雪花在下落过程中实现旋转的功能。
源码来啦:http://download.csdn.net/detail/harvic880925/6999829
请大家尊重原创,转载请标明处出,谢谢!!!本文出处:http://blog.csdn.net/harvic880925/article/details/20565125
相关网页:
《深入解析MFC -- CWinApp》:http://blog.sina.com.cn/s/blog_660ca10d0100lg0z.html
《MFC中的CWnd类与Windows窗体的关系》:http://blog.tianya.cn/blogger/post_read.asp?BlogID=4361806&PostID=44293548
《桌面动画-雪花和兔子-源码分享》http://blog.csdn.net/cometnet/article/details/17332699 (感谢本文作者,参考了他的源码)
- 利用GDI+基于WIN32实现桌面雪花效果(一)
- 利用GDI+基于WIN32实现桌面雪花效果(一)
- 利用GDI+基于WIN32实现桌面雪花效果(一)
- 利用GDI+基于WIN32实现桌面雪花效果(二)
- 利用GDI+基于WIN32实现桌面雪花效果(二)
- 利用SurfaceView实现墨迹天气雪花效果
- ActionScript 实现雪花效果
- 雪花效果实现
- 实现雪花飞舞效果
- canvas实现雪花效果
- Qt 实现桌面雪花飘落
- WIN32 GDI+ 学习笔记(一):配置GDI+
- 桌面时钟(GDI实现) 学习总结
- 简单实现飘雪花效果
- Android 实现雪花飞舞效果
- 桌面雪花
- Qt 实现桌面雪花飘落 - 修改1
- Qt 实现桌面雪花飘落 - 修改2
- 自定义Cell步骤
- mysql 问题汇总
- RED5语音视频延时-解决办法[转]
- Verilog HDL 实验环境搭建
- 图片相关--相册选择、拍照、缩放、裁减
- 利用GDI+基于WIN32实现桌面雪花效果(一)
- spring mvc校验部分属性,springmvc校验属性,java.lang.ClassNotFoundException: com.fasterxml.classmate.Filter
- 1.如何提高tableView的效率
- 重写EditText,使其具有下划线
- 动态添加综合布局---动态添加控件及将某XML动态加入到Activity显示(续)
- 黑马程序员——Java基础语法 之运算符
- LeetCode 8: String to Integer (atoi)
- JavaScript中document.write()的用法
- ANDROID开发之SQLite详解