当前位置 博文首页 > 启舰:利用GDI+基于WIN32实现桌面雪花效果(一)

    启舰:利用GDI+基于WIN32实现桌面雪花效果(一)

    作者:[db:作者] 时间:2021-06-12 15:35

    前言:毕业论文写完了,闲着没事干,研究研究这些一直想做的效果,先从桌面飘雪花开始,下面是过程记录。最后给出代码,供大家参考。

    效果图:(桌面局部截图)


    一、创建空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;
    
    这里重写了CWinApp的两个函数,InitInstance()和ExitInstance();

    然后自己写了一个窗口类注册函数,完整代码如下:

    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();
    }
    这里主要讲解InitInstance()的流程,这是应用程序初始化函数,它首先对GDI+进行初始化,然后注册窗口类,利用CSowWnd类创建窗口,然后将snowWnd作为主窗体HWND,传给m_pMainWnd,供其显示窗体。最后利用Run()函数进入消息循环。流程与WIN32窗体的创建过程一样,只是这里是经过CWinApp类封装过的,所以流程显得不那么明显。

    三、雪花窗体显示

    这里分析两个问题:

    • 我们并不是将每个雪花创建一个窗口,而是将当前屏幕做为窗体,在它上面画图而已。
    • 雪花的种类是有限的,即原始图片,这里加载了六个,而大家可以看到,整个屏幕的雪花量却是很大的,所以我们要建一个基类完成原始图像加载、窗体刷新等功能。而雪花类则建立在此基类的基础上,完成雪花的下落、移动等功能。

    1、定义单个雪花图片对象

    该对象包含每个雪花显示所需的所有信息,结构体定义如下: