2010-11-19 09:53:00| 分类:MFC| 标签:|字号大中小 订阅
Windows定时器是一种周期性的消息产生装置,它会每隔一段指定时间发送一次定时消息WM_TIMER。它是一个很重要的系统消息,当系统所设置的时间到达以后,系统就会自动发送该消息。与该消息联系密切的函数是SetTimer(),它设置一个系统时钟,当设置的时间到时,系统产生WM_TIMER消息。通过对SetTimer()函数的参数进行设置,可以告诉用户哪一个时钟的时间到了。因此,可以将一些周期性的工作放入WM_TIMER的消息处理函数中。
定时器的使用一般遵循下列步骤:
(1)使用SetTimer()函数设置定时器
SetTimer()函数的原型如下:
UINT SetTimer(UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT*lpfnTimer)(HWND,UINT, UINT, DWORD));
其中,参数nIDEvent为新创建的定时器标识号码(非零),当一个应用程序需要多个定时器时,靠此参数的不同来加以区别;参数nElapse为定时器间隔,以毫秒为单位,当由该参数规定的时间到后,系统发送WM_TIMER消息;参数lpfnTimer为指定处理消息WM_TIMER的函数,通常为NULL时,表示由CWnd对象的OnTimer成员函数来处理该消息,当然也可以超载该函数。
SetTimer(m_hWnd,1,1000,NULL); //一个1秒触发一次的定时器
如果创建成功,则返回新的定时器的号码:否则返回0。
(2)超载OnTimer()函数,完成用户希望的操作
通过第一步设置的定时器会按其设置的时间间隔向应用程序发送WM_TIMER消息,为了接收和处理该消息,应超载消息处理函数OnTimer()(可以由ClassWizard自动产生),其函数原型如下:
afx_msg void OnTimer(UINT nIDEvent);
其中,参数nIDEvent为定时器的标识。若在程序中设置了多个定时器时,靠此参数的不同来加以区别。
(3)撤销定时器
定时器使用完后,可以通过调用KillTimer()函数来清除定时器,其函数原型如下:
BOOL KillTimer(int nIDEvent);
说明:销毁以前调用SetTimer创建的用nIDEvent标识的定时器事件。任何与此定时器有关的未处理的WM_TIMER消息都从消息队列中清除。
其中,参数nIDEvent为准备清除的定时器号码,该参数的值必须在SetTimer()函数中设置过,即不能够清除一个不存在的定时器号码。传递给SetTimer的定时器事件值。
【例9.4】本程序在例9.3程序的基础上增加定时器的功能。当按B键时,启动定时器,屏幕上的图形自动移动;当按S键时,撤销定时器,停止自动移动。
(1)在字符消息映射函数中添加启动和撤销定时器的代码
void CKeyMsgView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
switch(nChar){
…
case 'b':
case 'B':
SetTimer(1,100,NULL); //建立一号定时器,时间间隔为100ms
break;
case 's':
case 'S':
KillTimer(1); //撤销一号定时器
break;
}
…
}
(2)添加WM_TIMER的消息映射函数OnTimer()的实现代码
void CKeyMsgView::OnTimer(UINT nIDEvent)
{
//图形往右下角自动移动
CRect OldRect=m_Rect;
m_Rect.OffsetRect(CPoint(1,1)); //图形往右下角移动一个像素
OldRect.UnionRect(OldRect,m_Rect);
InvalidateRect(OldRect); //将指定矩形区域OldRect的内容刷新
CView::OnTimer(nIDEvent);
}
该TimerProc函数是一个应用程序定义的回调函数,用于处理WM_TIMER消息。
函数原型:
VOID CALLBACK TimerProc(
HWND hwnd,// 定时器消息的窗口句柄
UINT uMsg, // WM_TIMER 消息
UINT idEvent,// 定时器标识符
DWORD dwTime // 当前系统时间
);
参数说明:
hwnd
标识了与定时器进行关联的窗口。
uMsg
指定WM_TIMER消息。
idEvent
指定定时器的标识符。
dwTime
指定自窗口启动开始所经过的毫秒数。这是GetTickCount函数的返回值。
返回值:
这个函数没有返回值。
备注:
TimerProc是一个应用程序定义函数名称的占位符。
1) 不用回调函数
SetTimer(1,1000,NULL);
1:计时器的名称;
1000:时间间隔,单位是毫秒;
NULL:使用onTime函数。
当不需要计时器的时候调用KillTimer(nIDEvent);
例如:KillTimer(1);
2) 调用回调函数
此方法首先写一个如下格式的回调函数
void CALLBACK TimerProc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime);
然后再用SetTimer(1,100,TimerProc)函数来建一个定时器,第三个参数就是回调函数地址。
或许你会问,如果我要加入两个或者两个以上的 timer怎么办?
继续用SetTimer函数吧,上次的timer的ID是1,这次可以是2,3,4。。。。
SetTimer(2,1000,NULL);
SetTimer(3,500,NULL);
嗯,WINDOWS会协调他们的。当然onTimer函数体也要发生变化,要在函数体内添加每一个timer的处理代码:
onTimer(nIDEvent)
{
switch(nIDEvent)
{
case 1:........;
break;
case 2:.......;
break;
case 3:......;
break;
}
}
例3:
1. 每隔1s刷新当前启动的时间,按开始测试按钮,开始计时并且显示测试所用时间,停止按钮停止测试,再次点击开始按钮,从0开始记录。
OnBnClickedBtnStart()函数
TestStartTime = CTime::GetCurrentTime();
SetTimer(TEST_TOTAL_TIME, 1000, NULL);
GetDlgItem(IDC_STC_TEST_TOTAL_TIME)->SetWindowText("00:00:00");
void CCLMemTestDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CTimeSpan TestTime; //可用于显示时间差
CTime CurrentTime = CTime::GetCurrentTime();
TestTime = CurrentTime - TestStartTime; //测试时间
CString Str,Str_Start,Str_Current;
Str_Current = CurrentTime.Format("%H:%M:%S");
Str_Start = TestStartTime.Format("%H:%M:%S");
Str = TestTime.Format("%H:%M:%S");
GetDlgItem(IDC_STC_TEST_TOTAL_TIME)->SetWindowText(Str);
CDialog::OnTimer(nIDEvent);
}按停止测试按钮,停止计时显示时间
KillTimer(1)
再按下开始测试按钮,重新归零开始计时并且显示时间