一、定时器Timer
1.MFC方式
(a)创建方法:
资源视图->类向导->消息->WM_TIMER->添加处理程序,即可自动生成相应的函数
xx.h 中自动生成:
afx_msg void OnTimer(UINT_PTR nIDEvent);
xx.cpp中如下所示
- 消息映射(宏定义)自动新增一条ON_WM_TIMER():
BEGIN_MESSAGE_MAP(CPannelTransBill, CDialogEx) xxx ON_WM_TIMER() END_MESSAGE_MAP()
- 功能函数自动构建:
void CExample::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CDialogEx::OnTimer(nIDEvent); }
(b)使用方法:
如需在BeginTimer函数中调用本对话框中的定时器,使用SetTimer(UINT_PTR nIDEvent, UINT nElapse,
void (CALLBACK* lpfnTimer)(HWND, UINT, UINT_PTR, DWORD))
方法即可:
void CExample::BeginTimer()
{
//启动ID为1的定时器,定时1000ms(1s)
SetTimer(1,1000,null);
}
使用到此结束
SetTimer(x,x,x)
函数原型:
启动定时器就需要使用CWnd类的成员函数SetTimer。CWnd::SetTimer的原型如下:UINT_PTR SetTimer( UINT_PTR nIDEvent, //定时器ID UINT nElapse, //定时时间(ms) void (CALLBACK* lpfnTimer)(HWND, UINT, UINT_PTR, DWORD)//回调函数,没有可设为NULL );
-
参数nIDEvent指定一个非零的定时器ID;参数nElapse指定间隔时间,单位为毫秒;参数lpfnTimer指定一个回调函数的地址,如果该参数为NULL,则WM_TIMER消息被发送到应用程序的消息队列,并被CWnd对象处理。如果此函数成功则返回一个新的定时器的ID,我们可以使用此ID通过KillTimer成员函数来销毁该定时器,如果函数失败则返回0。
-
通过SetTimer成员函数我们可以看出,处理定时事件可以有两种方式,一种是通过WM_TIMER消息的消息响应函数,一种是通过回调函数。
-
如果要启动多个定时器就多次调用SetTimer成员函数。另外,在不同的CWnd中可以有ID相同的定时器,并不冲突。
-
KillTimer(nIDEvent)
函数原型:BOOL KillTimer(UINT_PTR nIDEvent) { UINT_PTR nIDEvent, //定时器ID }
- 多个定时器的例子:
void CExample::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 switch(nIDEvent) { case 1: //ID为1的定时器 doFuncOne; break; case 2: //ID为2的定时器 doFuncTwo; break; default: break; } CDialogEx::OnTimer(nIDEvent); }
*(重点)通过回调函数设置定时器的例子:
注:回调函数为全局函数,需要写在使用它的位置的前面,或者写在后面然后在使用之前声明。- xx.h无需定义内容
- xx.cpp:
- 定义一个显示当前时间的对话框(写在cpp#include之后):
void MyTimer() { // TODO: 在此添加消息处理程序代码和/或调用默认值 CTime t = CTime::GetCurrentTime(); CString str; str.Format("当前时间: %04d/%02d/%02d %02d:%02d:%02d", t.GetYear(), t.GetMonth(), t.GetDay(), t.GetHour(), t.GetMinute(), t.GetSecond()); Util::ShowSysMsg(str); }
- 定义一个回调函数,调用之前的方法(写在MyTimer()之后,其中
CALLBACK EXPORT
为关键字,函数名可自定义,但返回值类型、参数的类型和个数不能改变。)void CALLBACK EXPORT TimerProc(HWND hWnd, UINT nMsg, UINT nTimerid, DWORD dwTime) { switch (nTimerid) { case 1: MyTimer(); break; default: break; } }
- 通过SetTimer()调用回调函数
SetTimer(1, 1000, TimerProc);
//1进入case = 1的控制,1000ms,TimerProc为回调函数名称,不加()
- 定义一个显示当前时间的对话框(写在cpp#include之后):
2.Windows API方式
- SetTimer函数原型:
UINT_PTR SetTimer( HWND hWnd, //窗口句柄 UINT_PTR nIDEvent, //定时器ID UINT uElapse, //定时间隔 TIMERPROC lpTimerFunc //回调函数 );
-
参数hWnd为与定时器关联的窗口的句柄;参数nIDEvent为非零的定时器ID,如果hWnd等于NULL,且还不存在ID为nIDEvent的定时器,那么nIDEvent参数被忽略,然后生成一个新ID的定时器,而如果hWnd不为NULL,且hWnd指定的窗口已存在ID为nIDEvent的定时器,那么这个已存在的定时器被新定时器所取代。参数uElapse和lpTimerFunc同CWnd::SetTimer函数。
-
如果调用SetTimer函数时最后一个参数为NULL,我们需要自己为WM_TIMER消息添加处理函数,要注意的是,WM_TIMER消息的附加数据wParam为定时器ID,lParam为回调函数的指针,如果调用SetTimer时回调函数为NULL,那么lParam也为NULL。
-
而如果调用SetTimer函数时最后一个参数不为NULL,我们就需要定义回调函数。回调函数的定义同MFC定时器。
-
- 销毁定时器KillTimer API函数:
BOOL KillTimer(HWND hWnd,UINT_PTR uIDEvent);
- 参数hWnd为与定时器关联的窗口的句柄,与启动定时器时SetTimer函数的hWnd参数值相同;参数uIDEvent为要销毁的定时器的ID,如果传递给SetTimer的参数hWnd有效,则uIDEvent应与传递给SetTimer的参数nIDEvent相同,而如果SetTimer的参数hWnd为NULL,则uIDEvent应为SetTimer返回的定时器ID。该函数成功则返回TRUE,否则返回FALSE。
3.区别总结
- CWnd类的SetTimer成员函数只能在CWnd类或其派生类中调用,而API函数SetTimer则没有这个限制,这是一个很重要的区别。因为本教程主要是讲解MFC编程,所以这里就先重点讲解MFC定时器的用法,关于API函数SetTimer的用法鸡啄米会在MFC定时器讲解的基础上进行延伸。