桌面下雪程式的編寫
一. 綜述
考慮到雪花將會很多,並且每個雪花都有自己的行為路徑,統一處理比較麻煩,因此自定義一個類CSnowflake,它所呈現的主要介面有兩個:下落和“死亡”判斷。下落路徑由雪花物件自身處理,主框架中只是採用定時器來控制其下落。當然,雪花落到螢幕底後就相當於“死亡”了,為了保持活動雪花總數大致不變,我又開啟了一個定時器,用來產生雪花。在使用者互動上我做了一個托盤,可以顯示提示,右鍵彈出選單。還有一個小問題——程式執行之後即隱藏介面,自己試了許多方法,也在網上差了許多,最後還是在訊息WM_WINDOWPOSCHANGING響應中新增lpwndpos->flags&=SWP_HIDEWINDOW並且去掉MFC生成的程式碼這個方法來的徹底。
二. 程式顯示
1. 雪花
2. 托盤
主要描述其下落方法。
說明:
其中的hwndDesktop是在建構函式中使用以下程式碼獲得的
其中的rtLocation指的是雪花當前矩形位置,rtDesktop指的是繪製螢幕矩形範圍。
點陣圖我畫了四個,隨機選擇一個。
四. 主對話方塊中的處理
1. 定時器處理
托盤的新增是在OnInitDialog中的:
對其圖示的訊息處理函式為:
1. Bug
點選托盤選單時,雪花會停止下落。
2. 說明
本程式只適於靜態桌面環境下。
3. 奮鬥無止境
4. 程式碼下載地址
點選開啟連結
考慮到雪花將會很多,並且每個雪花都有自己的行為路徑,統一處理比較麻煩,因此自定義一個類CSnowflake,它所呈現的主要介面有兩個:下落和“死亡”判斷。下落路徑由雪花物件自身處理,主框架中只是採用定時器來控制其下落。當然,雪花落到螢幕底後就相當於“死亡”了,為了保持活動雪花總數大致不變,我又開啟了一個定時器,用來產生雪花。在使用者互動上我做了一個托盤,可以顯示提示,右鍵彈出選單。還有一個小問題——程式執行之後即隱藏介面,自己試了許多方法,也在網上差了許多,最後還是在訊息WM_WINDOWPOSCHANGING響應中新增lpwndpos->flags&=SWP_HIDEWINDOW並且去掉MFC生成的程式碼這個方法來的徹底。
二. 程式顯示
1. 雪花
2. 托盤
主要描述其下落方法。
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。
托盤的新增是在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. 程式碼下載地址
點選開啟連結
相關文章
- 聖誕節到了!!你的桌面下雪了嗎?? - Qt趣味開發之讓你的桌面下雪QT
- 用Java編寫一個最簡單的桌面程式Java
- Python3結合Sciter編寫桌面程式第三節Python
- Java程式編寫Java
- PHP 編寫基本的 Socket 程式PHP
- Python編寫守護程式程式Python
- Sublime 編寫編譯 swift程式碼編譯Swift
- 使用JavaScript編寫的爬蟲程式JavaScript爬蟲
- 如何編寫高效的Android程式碼Android
- 如何編寫簡潔的程式碼?
- PEP 8 程式程式碼的編寫風格指南
- Python編寫shellcode注入程式Python
- PHP 編寫守護程式PHP
- C# 編寫一個小巧快速的 Windows 動態桌面軟體C#Windows
- 編寫簡單的Java程式碼:HelloWoridJava
- 編寫友好的命令列應用程式命令列
- 編寫高效能的Java程式碼Java
- IEDA編寫程式碼常用的快捷鍵
- Storm的wordcount程式碼編寫與分析ORM
- 編寫更優雅的 JavaScript 程式碼JavaScript
- C# 編寫 Windows 動態桌面軟體實現(一)之桌面互動功能C#Windows
- ekzhang/rustpad:使用Rust編寫的高效程式碼編輯器Rust
- 【IDL〕編寫程式啟動介面
- Hbuilder快速程式碼編寫技巧UI
- vue3程式碼編寫Vue
- Model 編寫程式碼智慧提醒
- 02 | 編寫Model層程式碼
- 編寫第一個Qt程式QT
- 使用Python編寫猜拳小程式Python
- 編寫可擴充套件程式套件
- 用Rust編寫的快如閃電的程式碼編輯器:lapceRust
- 使用 Typhoeus 和 Ruby 編寫的爬蟲程式爬蟲
- Linux下的 sniff-andthen-spoof程式編寫Linux
- C# Windows Service 服務程式的編寫C#Windows
- JAVA編寫的斷點續傳小程式Java斷點
- 編寫優雅程式碼的最佳實踐
- 【保姆級教程】如何用Rust編寫一個ChatGPT桌面應用RustChatGPT
- 在VS2019使用MASM編寫彙編程式ASM
- 使用ASP.NET Blazor Server 寫混合桌面程式的瘋狂想法ASP.NETBlazorServer