桌面下雪程序的编写

桌面下雪程序的编写一.综述考虑到雪花将会很多,并且每个雪花都有自己的行为路径,统一处理比较麻烦,因此自定义一个类CSnowflake,它所呈现的主要接口有两个:下落和“死亡”判断。下落路径由雪花对象自身处理,主框架中只是采用定时器来控制其下落。当然,雪花落到屏幕底后就相当于“死亡”了,为了保持活动雪花总数大致不变,我又开启了一个定时器,用来产生雪花。在用户交互上我做了一个托盘,可以显示提示,右键弹出菜单。还有

一.
综述

考虑到雪花将会很多,并且每个雪花都有自己的行为路径,统一处理比较麻烦,因此自定义一个类CSnowflake,它所呈现的主要接口有两个:下落和“死亡”判断。下落路径由雪花对象自身处理,主框架中只是采用定时器来控制其下落。当然,雪花落到屏幕底后就相当于“死亡”了,为了保持活动雪花总数大致不变,我又开启了一个定时器,用来产生雪花。在用户交互上我做了一个托盘,可以显示提示,右键弹出菜单。还有一个小问题——程序运行之后即隐藏界面,自己试了许多方法,也在网上差了许多,最后还是在消息WM_WINDOWPOSCHANGING响应中添加lpwndpos->flags&=SWP_HIDEWINDOW并且去掉MFC生成的代码这个方法来的彻底。

二.
程序显示

1.
雪花

 
桌面下雪程序的编写

2.
托盘

桌面下雪程序的编写 

三.
雪花snowflake类

主要描述其下落方法。

BOOL CSnowflake::Down()
{
	if (bDie)
		return FALSE;


	CRect rtNewLocation;
	srand((UINT)time(NULL));//随机种子


	if (rand()%2)
		rtNewLocation.left=rtLocation.left+rand()%10;
	else
		rtNewLocation.left=rtLocation.left-rand()%5;


	rtNewLocation.right=rtNewLocation.left+rtLocation.Width();
	rtNewLocation.top=rtLocation.top+iSpeed;
	rtNewLocation.bottom=rtNewLocation.top+rtLocation.Height();


	if (rtNewLocation.bottom>=rtDesktop.bottom)//超出绘制屏幕
	{
		bDie=TRUE;//设置死亡标志
		return FALSE;
	}
	else//下落
	{
		//擦除原雪花
		RedrawWindow(hwndDesktop,&rtLocation,NULL,RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW);


		HDC hDesktopDC=GetDC(hwndDesktop);
		CDC desktopDC;
		desktopDC.Attach(hDesktopDC);//桌面窗口DC


		CBitmap bmp;
		switch(bmpID)
		{
		case 0:
			bmp.LoadBitmap(IDB_BITMAP1);
			break;
		case 1:
			bmp.LoadBitmap(IDB_BITMAP2);
			break;
		case 2:
			bmp.LoadBitmap(IDB_BITMAP3);
			break;
		case 3:
			bmp.LoadBitmap(IDB_BITMAP4);
			break;
		default:
			break;
		}


		//重绘原矩形区域
		CDC bmpDC;
		bmpDC.CreateCompatibleDC(&desktopDC);


		CBitmap *poldbmp=bmpDC.SelectObject(&bmp);
		desktopDC.TransparentBlt(rtNewLocation.left,rtNewLocation.top,rtNewLocation.Width(),rtNewLocation.Height(),
			&bmpDC,0,0,rtNewLocation.Width(),rtNewLocation.Height(),RGB(0,0,0));//将底色白色设为透明


		bmpDC.SelectObject(poldbmp);


		desktopDC.Detach();
		ReleaseDC(hwndDesktop,hDesktopDC);


		rtLocation=rtNewLocation;//赋新位置
		return TRUE;
	}
}

说明:

其中的hwndDesktop是在构造函数中使用以下代码获得的

HWND hProgMan=::FindWindowW(L"ProgMan",NULL);
if(hProgMan)
{
	HWND hShellDefView=::FindWindowEx(hProgMan,NULL,L"SHELLDLL_DefView",NULL);
	if(hShellDefView)
		hwndDesktop=::FindWindowEx(hShellDefView,NULL,L"SysListView32",L"FolderView");
}
if (hwndDesktop==NULL)
	bDie=TRUE;

其中的rtLocation指的是雪花当前矩形位置,rtDesktop指的是绘制屏幕矩形范围。

位图我画了四个,随机选择一个。

四.
主对话框中的处理

1.
定时器处理

void CSnow2Dlg::OnTimer(UINT_PTR nIDEvent)
{
	switch(nIDEvent)
	{
	case 1://控制雪花下落
		{
			if(WAIT_TIMEOUT==WaitForSingleObject(m_handleEvent,100))
				break;
			ResetEvent(m_handleEvent);


			std::vector<CSnowflake> tempflakes;
			for (std::vector<CSnowflake>::iterator iter=snowflakes.begin();iter!=snowflakes.end();++iter)
			{
				if (iter->IsDie()==FALSE)
				{
					iter->Down();
					tempflakes.push_back(*iter);
				}
			}


			snowflakes.clear();
			snowflakes=tempflakes;


			SetEvent(m_handleEvent);
		}
		break;
	case 2://判断雪花死亡状态,产生新雪花
		{
			if(WAIT_TIMEOUT==WaitForSingleObject(m_handleEvent,100))
				break;
			ResetEvent(m_handleEvent);


			if (snowflakes.size()<MAX_COUNT_FLAKES)
			{
				srand(static_cast<UINT>(time(NULL)));
				static int count=1;
				for (int i=0;i!=count;++i)
				{
					CSnowflake flake(rand()%MAX_BMP_COUNT,15,15,rand()%m_iDesktopWidth+1,rand()%5+2,
						CRect(0,0,m_iDesktopWidth,m_iDesktopHeight));
					snowflakes.push_back(flake);
				}
				++count;
				if (count>10)
					count=10;
			}


			SetEvent(m_handleEvent);
		}
		break;
	default:
		break;
	}


	CDialog::OnTimer(nIDEvent);
}

说明:此处有一std::vector<CSnowflake>类型的snowflakes成员变量,这个保存了当前所有活动雪花,若雪花已“死”,将会被移除出此向量,这样“死亡”的雪花就可在屏幕任务栏积累。然而在两个定时器中都会访问这个向量,于是为了防止访问冲突,设置了一个同步事件m_handleEvent。

2.
托盘处理

托盘的添加是在OnInitDialog中的:

m_nid.cbSize=sizeof(NOTIFYICONDATA);
m_nid.hWnd=this->m_hWnd;
m_nid.uID=IDR_MAINFRAME;
m_nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP|NIF_INFO;
m_nid.uCallbackMessage=UM_TRAY;//自定义的消息名称
m_nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
wcscpy_s(m_nid.szTip,L"桌面下雪程序");//信息提示条
wcscpy_s(m_nid.szInfo,L"哦,下雪了");//信息提示条
wcscpy_s(m_nid.szInfoTitle,L"桌面下雪程序提示");//信息提示条
m_nid.dwInfoFlags=NIIF_INFO;
Shell_NotifyIcon(NIM_ADD,&m_nid);//在托盘区添加图标

对其图标的消息处理函数为:

LRESULT CSnow2Dlg::OnTray(WPARAM wParam,LPARAM lParam)
{
	if(wParam!=IDR_MAINFRAME) 
		return 1;


	switch(lParam) 
	{
	case WM_RBUTTONDOWN:
		{
			CPoint pos;
			GetCursorPos(&pos);//得到鼠标位置 
			CMenu menu;
			menu.LoadMenuW(IDR_TRAYMENU);
			CMenu *psubmenu=menu.GetSubMenu(0);
			SetForegroundWindow(); //使在菜单外点击时菜单消失
			psubmenu->TrackPopupMenu(TPM_LEFTALIGN,pos.x,pos.y,this);//确定弹出式菜单的位置
		} 
		break;
	default:
		break;
	} 


	return 0;
}

此处有一个右键弹出菜单。菜单的命令响应就不列出了。

五.
结束语

1.
Bug

点击托盘菜单时,雪花会停止下落。

2.
说明

本程序只适于静态桌面环境下。

3.
奋斗无止境

4.
代码下载地址


点击打开链接

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/37750.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注