最近在學習MFC的過程中,看到一個窗口動畫特效例子,不過它是在一個對話框里面嵌入效果,我想如果能把它的代碼提取出來再寫成一個窗口動畫類就好了。於是便着手寫了這個類,你可以去CSND下載(http://download.csdn.net/source/2196359)這個代碼運行看看。
閑話少說,先看看這個類的聲明:
/******************************************
//************CDlgFlash.h*******************
//************ Author:Arlin *****************
//************ 2010.4.1********************
******************************************/
// DlgFlash.h: interface for the CDlgFlash class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_DLGFLASH_H__FC9C5DF7_7144_4F99_9B5A_0C5451DEA813__INCLUDED_)
#define AFX_DLGFLASH_H__FC9C5DF7_7144_4F99_9B5A_0C5451DEA813__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CDlgFlash
{
public:
CDlgFlash(CDialog* Dlg); //參數為將要實現動畫效果的對話框
CDlgFlash(CDialog* Dlg,int Timer1_ID,int Timer2_ID); //參數1為將要實現動畫效果的對話框,參數二三分別為定時器1和定時器2的ID
virtual ~CDlgFlash();
void StartFlashDestroyDlg(); //開始啟動銷毀效果
void OnTimer(UINT nIDEvent); //處理對應定時器的任務,在后面設置時鍾時為SetTimer(TimerID,10,NULL)
//沒有設置為自定義執行函數的原因是一定要在需要動畫效果的窗口中重寫從CDialog中繼承的OnClose()函數用於映射銷毀窗口效果用之
//
void SetFlashCreateSpeed(int x,int y); //設置創建窗口變化速度
//參數x表示窗口寬度的變化速度
//參數y表示窗口高度的變化速度
void SetFlashDestroySpeed(int y); //設置銷毀窗口變化速度
//參數y表示窗口高度的變化速度
protected:
int xCreateSpeed; //創建窗口時窗口寬度的變化速度
int yCreateSpeed; //創建窗口時窗口高度的變化速度
int xDestorySpeed; //銷毀窗口時窗口寬度的變化速度
int yDestorySpeed; //創建窗口時窗口寬度的變化速度
int OriginalWidth,OriginalHeight; //窗口的原始大小
int DestoryPosX; //銷毀窗口時窗口的左上角x軸位置
int DestoryPosY; //銷毀窗口時窗口的左上角y軸位置
int Timer1_ID; //定時器1ID,創建窗口時用之
int Timer2_ID; //定時器2ID,銷毀窗口時用之
CDialog* flashDlg; //指向需要動畫效果的窗口指針
void InitCDlg(); //初始化,內部使用
};
#endif // !defined(AFX_DLGFLASH_H__FC9C5DF7_7144_4F99_9B5A_0C5451DEA813__INCLUDED_)
這個類沒有基類,用到了MFC里面的一些類,各個成員函數和數據成員的功能已經在上面的類聲明中寫清楚了,下面看看這個類的實現:
/******************************************
//************CDlgFlash.CPP*******************
//************ Author:Arlin*****************
//************ 2010.4.1********************
******************************************/
// DlgFlash.cpp: implementation of the CDlgFlash class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CDlgFlash.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CDlgFlash::CDlgFlash(CDialog* Dlg)
{
flashDlg=Dlg;
Timer1_ID=9;
Timer2_ID=10;
InitCDlg();
}
CDlgFlash::CDlgFlash(CDialog* Dlg,int Timer1_ID,int Timer2_ID)
{
flashDlg=Dlg;
this->Timer1_ID=Timer1_ID;
this->Timer2_ID=Timer2_ID;
InitCDlg();
}
CDlgFlash::~CDlgFlash()
{
}
void CDlgFlash::InitCDlg(){
//獲得窗口預設的大小
CRect dlgRect;
flashDlg->GetWindowRect(dlgRect);
//獲取屏幕大小
CRect desktopRect;
flashDlg->GetDesktopWindow()->GetWindowRect(desktopRect);
//將窗口開始大小設為0,居中
flashDlg->MoveWindow(dlgRect.left + dlgRect.Width() / 2,
dlgRect.top + dlgRect.Height() / 2,
0,
0
);
//數據成員初始化
OriginalWidth=dlgRect.Width();
OriginalHeight=dlgRect.Height();
xCreateSpeed=2;
yCreateSpeed=3;
xDestorySpeed=2;
yDestorySpeed=3;
//設定定時器Timer1_ID
flashDlg->SetTimer(Timer1_ID,10,NULL);
}
void CDlgFlash::OnTimer(UINT nIDEvent){
{
//獲得此時窗口的實際大小
CRect dlgRect;
flashDlg->GetWindowRect(&dlgRect);
//獲得桌面的大小
CRect desktopRect;
flashDlg->GetDesktopWindow()->GetWindowRect(desktopRect);
//如果是窗口彈出過程,窗口居中,逐漸增大窗口
if(nIDEvent ==Timer1_ID)
{
flashDlg->MoveWindow(
(desktopRect.Width() - dlgRect.Width()) / 2,
(desktopRect.Height() - dlgRect.Height()) / 2,
xCreateSpeed+dlgRect.Width(),
yCreateSpeed+dlgRect.Height()
);
//不要超過窗口預設的寬度
if(dlgRect.Width() >=OriginalWidth)
xCreateSpeed=0;
//不要超過窗口預設的高度
if(dlgRect.Height() >=OriginalHeight)
yCreateSpeed=0;
//停止變化,關閉定時器Timer1_ID
if((dlgRect.Width() >=OriginalWidth) && (dlgRect.Height() >=OriginalHeight))
flashDlg->KillTimer(Timer1_ID);
}
//如果是窗口關閉過程,則逐漸縮小窗口
if(nIDEvent == Timer2_ID)
{
flashDlg->MoveWindow(DestoryPosX,
DestoryPosY ,
dlgRect.Width(),
dlgRect.Height()-yDestorySpeed
);
//當高度等於零后高度就不在變化
//if(dlgRect.Height() <=0)
//停止變化,關閉定時器Timer2_ID,並且關閉窗口
if(dlgRect.Height() <=0)
{
yDestorySpeed=0;
flashDlg->KillTimer(Timer1_ID);
flashDlg->DestroyWindow();
}
}
}
}
void CDlgFlash::StartFlashDestroyDlg(){
CRect dlgRect;
//獲取窗口當前的位置並保存
flashDlg->GetWindowRect(&dlgRect);
DestoryPosX=dlgRect.left;
DestoryPosY=dlgRect.top;
//開始啟動定時器Timer2_ID
flashDlg->SetTimer(Timer2_ID,10,NULL);
}
void CDlgFlash::SetFlashCreateSpeed(int x,int y){
xCreateSpeed=x;
xCreateSpeed=y;
}
void CDlgFlash::SetFlashDestroySpeed(int y){
yDestorySpeed=y;
}
這個類就這么簡單,實現的方法也很容易,將要實現動畫的對話框指針傳進來,在對話框顯示之前獲取對話框的原本大小並且保存起來,然后設置對話框的大小為0,然后通過定時器1不斷的改變對話框的左上角位置以及增加長寬,直到對話框的長寬都和原來的大小一樣即停止變化。而在對話框關閉的時候,先獲得對話框當前的位置和大小,然后不斷的改變對話框左上角的位置和減少長寬,直到窗口的長寬都為0,停止變化,銷毀對話框。在代碼中的注釋已經說得比較清楚了,我這里一而不打算解釋代碼,下面說一下怎么使用這個類。
使用方法:
1、 首先在對話框的聲明頭文件中添加一個變量 CDlgFlash *myFlash,包含頭文件”CDlgFlash.h”;
2、 在聲明頭文件里添加定時器消息映射函數afx_msg void OnTimer(UINT nIDEvent);因為需要處理定時器發來的消息,再添加窗口關閉消息映射函數afx_msg void OnClose();覆蓋原對話框對窗口關閉的默認處理,這樣才能啟動對話框關閉時的動畫效果
3、 由於需要在對話框未顯示之前調用這個類將效果加在對話框上面,所以需要在對話框實現文件的OnInitDialog()函數中就new一個CDlgFlash對象,它有兩個構造函數,第一個只有一個參數,一般填this即可,它默認的定時器ID為9和10,還有一個構造函數是有三個參數,第一個參數和上面一樣,第二設置定時器1的ID,第三個參數設置定時器的ID。還有設置變化速度的方法,例如
myFlash=new CDlgFlash(this);
//or you can choose : myFlash=new CDlgFlash(this,9,10);
myFlash-> SetFlashCreateSpeed(5,6);
myFlash-> SetFlashDestroySpeed(5);
這些語句最好放在OnInitDialog()最后面。
4、 在對話框實現文件中填寫消息映射表,即在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之間添加:ON_WM_TIMER()和ON_WM_CLOSE()。如下:
BEGIN_MESSAGE_MAP(CMy2Dlg, CDialog)
//{{AFX_MSG_MAP(CMy2Dlg)
ON_WM_TIMER()
ON_WM_CLOSE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
5、 在實現文件中編OnTimer()的實現,如下:
Void MyDlg::OnTimer(UINT nIDEvent){
If(nIDEvent= = MyID1) //這里的MyID1是自己定義的計時器,與對話框
{ //動畫實現效果的兩個定時器無關的處理
………….
} If(nIDEvent= = MyID2)
{
…………….. //同前面MyID1
}
……………..
}else { //處理窗口動畫定時器
myFlash->OnTimer(nIDEvent);
}
CDialog::OnTimer(nIDEvent); //這句別忘了,把不能處理的交給上級
}
如果你在對話框中沒有實現其他定時器,那么更容易,你只需要下面的代碼:
void MyDlg::OnTimer(UINT nIDEvent){
myFlash->OnTimer(nIDEvent); //處理窗口動畫定時器
CDialog::OnTimer(nIDEvent); //這句別忘了,把不能處理的交給上級
}
這樣我們就把啟動的效果給做出來了,剩下的就是編寫OnClose()函數的實現,用於窗口的關閉
6、 OnClose()的實現,代碼如下:
void MyDlg::OnClose(){
…………………………… //添加你自己需要處理WM_CLOSE的代碼,
//沒有則可省略
myFlash-> StartFlashDestroyDlg(); //開始動畫關閉對話框
}
這里由一個需要注意的是,如果你添加了其他退出的按鈕或者退出菜單,那么不要在他們對應的實現中發送WM_QUIT等消息,只需要把myFlash-> StartFlashDestroyDlg();語句添加到該函數實現即可,因為在這條語句中在動畫結束時會調用對話框的DestroyWindow()函數。
搞定,讓我們來看看效果如何:
雙擊可執行程序,啟動對話框截圖如下:
關閉窗口效果截圖如下:
很簡單吧?,你也可以利用這個類做些修改來創建自己的動畫效果,我相信你有這個能力的。
存在問題:
1、 如果對話框大小是可變的,也即可以拖動改變大小,那么當對話框關閉時會只剩下一條標題欄,然后就不再改變了,需要用任務管理器才能關閉它,啟動功能正常。
2、 如果對話框大小不可變,但有最大化按鈕,可以最大化,當最大化時關閉,如果之前沒有修改關閉對話框的變化速度,則窗口沒有反應,除非你把窗口還原才能關閉,此時出現的效果也不是預期的效果。而如果在此之前修改了變化速度,加快它(例如變為20),那么又一切正常了,奇,怪。
3、 想了挺久,未果,如果你知道,請留言大家交流一下。