刚接触MFC没多久,很多知识学过就忘,所以急需写一个小程序来巩固下知识,从小就喜欢雪花,喜欢在大雪中奔跑,喜欢大雪中两人手牵手的浪漫。如果能写个桌面下雪程序既是对雪花的喜爱也能练练window下的编程岂不是两全其美。
说做就做,让我们一起来完成一个漂亮的雪花程序
首先分析下程序,屏幕下雪大致可以分为以下步骤
1、创建雪花类,初始化雪花
2、在OnPaint()函数中绘制雪花
3、在定时器OnTimer()中更新雪花位置等数据,重绘桌面
这样每次刷新雪花的x,y轴,每次重绘桌面就会看到一个下雪的动作
以下为具体步骤:
我使用的是VS2008环境,首先创建一个单文档项目
然后创建一个雪花类SnowFlower
class SnowFlower
{
public:
SnowFlower(void);
~SnowFlower(void);
public :
int SnowType;//雪花类型
int x;//x位置
int y;//y位置
};
让背景为桌面,去掉window默认的窗口
修改MainFrm.cpp中PreCreateWindow函数
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: 在此处通过修改
if(cs.hMenu!=NULL){
::DestroyMenu(cs.hMenu);
cs.hMenu = NULL;
}
cs.x=0; //改变初始位置
cs.y=0;
//全屏
int nFullWidth = GetSystemMetrics(SM_CXSCREEN);
int nFullHeight = GetSystemMetrics(SM_CYSCREEN);
cs.cx = nFullWidth;
cs.cy = nFullHeight;
//去掉边框
cs.style=WS_POPUP;
cs.dwExStyle = WS_EX_TOPMOST;
return TRUE;
}
这样程序的窗口和边框都被隐藏,而且窗口大小为全屏模式
我们 需要在View中绘图,打开xxxxxxxView类
定义一个雪花数宏
#define SNOW_COUNT 200
定义一个雪花数组
SnowFlower sf[SNOW_COUNT];
添加初始化雪花代码
void CSnowTestView::InitSnowFlower(void)
{
for(int i=0;i<SNOW_COUNT;i++){
sf[i].x = 30+i*10;
sf[i].y = rand()%500;
int typesRand = rand()%100;
if(typesRand<3){
sf[i].SnowType = 6;
}else if(typesRand>=3 && typesRand<8){
sf[i].SnowType = 5;
}else if(typesRand>=8 && typesRand<13){
sf[i].SnowType = 4;
}else if(typesRand>=13 && typesRand<20){
sf[i].SnowType = 3;
}else if(typesRand>=20 && typesRand<50){
sf[i].SnowType = 2;
}else if(typesRand>=70 && typesRand<101){
sf[i].SnowType = 1;
}
}
}
在类视图中点击xxxxxView,在属性中添加对WM_TIMER的消息相应
void CSnowTestView::OnTimer(UINT_PTR nIDEvent)
{
for(int i=0;i<SNOW_COUNT;i++){
if(sf[i].y>760){
sf[i].y = 0;
sf[i].x = rand()%1000;
}
int snowType = sf[i].SnowType;
switch(snowType){
case 1:
sf[i].y += 1;
sf[i].x +=1;
break;
case 2:
sf[i].y += 2;
sf[i].x +=2;
break;
case 3:
sf[i].y += 3;
sf[i].x +=1;
break;
case 4:
sf[i].y += 4;
sf[i].x +=1;
break;
case 5:
sf[i].y += 5;
sf[i].x +=1;
break;
case 6:
sf[i].y += 8;
sf[i].x +=2;
break;
}
}
Invalidate();
CView::OnTimer(nIDEvent);
}
void CSnowTestView::OnPaint()
{
CPaintDC dc(this); // device context for painting
CDC MemDc;
MemDc.CreateCompatibleDC(&dc);
CBitmap bg_bitmap;
bg_bitmap.LoadBitmap(IDB_BITMAP1);
MemDc.SelectObject(&bg_bitmap);
CBrush brush;
brush.CreateSolidBrush(RGB(255,255,255));
MemDc.SelectObject(&brush);
for(int i=0;i<SNOW_COUNT;i++){
int snowType = sf[i].SnowType;
switch(snowType){
case 1:
MemDc.Ellipse(sf[i].x,sf[i].y,sf[i].x+6,sf[i].y+6);
break;
case 2:
MemDc.Ellipse(sf[i].x,sf[i].y,sf[i].x+9,sf[i].y+9);
break;
case 3:
MemDc.Ellipse(sf[i].x,sf[i].y,sf[i].x+13,sf[i].y+13);
break;
case 4:
MemDc.Ellipse(sf[i].x,sf[i].y,sf[i].x+17,sf[i].y+17);
break;
case 5:
MemDc.Ellipse(sf[i].x,sf[i].y,sf[i].x+21,sf[i].y+21);
break;
case 6:
MemDc.Ellipse(sf[i].x,sf[i].y,sf[i].x+25,sf[i].y+25);
break;
}
}
dc.BitBlt(0,0,1370,770,&MemDc,0,0,SRCCOPY );
<span style="white-space:pre"> </span>MemDc.DeleteDC();
}
为了让程序播放音乐,点开资源,添加资源选择*.wav文件
添加音乐播放函数PlayMusic(),
需要加入以下文件头和库
#include "mmsystem.h"
#pragma comment(lib,"WINMM.LIB")
#pragma comment(lib,"msimg32.lib")
void CSnowTestView::PlayMusic(void)
{
PlaySound(MAKEINTRESOURCE(IDR_WAVE1),AfxGetResourceHandle(),SND_RESOURCE|SND_ASYNC|SND_LOOP);
}
为了让程序一启动就开始运行,在view中重写OnInitialUpdate方法添加调用雪花初始化函数,定时器函数等
void CSnowTestView::OnInitialUpdate()
{
InitSnowFlower();
SetTimer(1,30,NULL);
PlayMusic();
CView::OnInitialUpdate();
// TODO: 在此添加专用代码和/或调用基类
}
以上代码程序已经可以跑起来了,看到桌面飘舞的雪花是不是非常兴奋呢?
为了程序更加完善,我们还可以为程序添加一个托盘
1、打开MainFrm.cpp
2、添加一个NOTIFYICONDATA成员变量 m_nid;
3、声明一个消息响应函数 afx_msg void onShowTask(WPARAM wParam,LPARAM IParam);
LRESULT CMainFrame::onShowTask(WPARAM wParam,LPARAM lParam) {
<span style="white-space:pre"> </span>//wParam接收的是图标的ID,lParam接收的是鼠标的行为
if(IDI_ICON1 != wParam){
return 1;
}
switch(lParam){
case WM_RBUTTONUP://右键起来时弹出快捷菜单
{
LPPOINT lpoint=new tagPOINT;
::GetCursorPos(lpoint);//得到鼠标位置
CMenu menu;
menu.LoadMenu(IDR_MENU1);
CMenu* pPopup = menu.GetSubMenu(0);
//pPopup->CheckMenuItem(ID_32777,MF_BYCOMMAND | MF_CHECKED);
SetForegroundWindow();
pPopup->TrackPopupMenu(TPM_LEFTALIGN| TPM_RIGHTBUTTON,lpoint->x,lpoint->y,this);
//资源回收
HMENU hmenu=menu.Detach();
menu.DestroyMenu();
delete pPopup;
delete lpoint;
}
break;
case WM_LBUTTONDBLCLK://双击左键的处理
{
SendMessage(WM_YHMESSAGE1);
}
break;
}
return 0;
}
4、定义一个自定义消息 #define WM_SHOWTASK WM_USER+1
5、在BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)和END_MESSAGE_MAP()之间添加 ON_MESSAGE(WM_SHOWTASK,onShowTask)注册信息
6、添加ToTray()方法初始化m_nid
void CMainFrame::ToTray(void)
{
m_nid.cbSize = (DWORD)sizeof(NOTIFYICONDATA);
m_nid.hWnd = this->m_hWnd;
m_nid.uID = IDI_ICON1; //应用程序定义的该图标的ID号
m_nid.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;
m_nid.uCallbackMessage = WM_SHOWTASK; //自定义消息
m_nid.hIcon = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1));
wcscpy(m_nid.szTip,_T("雪花尽情的飘舞吧"));
Shell_NotifyIcon(NIM_ADD,&m_nid);//在托盘区添加图标
}
效果图:
程序下载地址:http://pan.baidu.com/s/1o63I1yM