最近在学习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、 想了挺久,未果,如果你知道,请留言大家交流一下。