一.
综述
考虑到雪花将会很多,并且每个雪花都有自己的行为路径,统一处理比较麻烦,因此自定义一个类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