MFC中定时器的使用

在MFC中和定时器相关的有三个函数:
UINT SetTimer( UINT nIDEvent, UINT nElapse,
void (CALLBACK EXPORT* lpfnTimer)( HWND, UINT, UINT, DWORD) );
afx_msg void OnTimer( UINT nIDEvent );
BOOL KillTimer( int nIDEvent );
参数说明:
UINT nIDEvent:定时器的ID,给定时器唯一的身份验证,如果在一个/doc/">程序中有多个定时器可以用这个ID来确定是那个定时器发送的消息。
UINT nElapse: 定义刷新时间,即间隔多长时间刷新一次,单位是毫秒。
void (CALLBACK EXPORT* lpfnTimer)( HWND, UINT, UINT, DWORD):
这个回调函数中实现刷新时所做的操作,如在数据库中读取数据。但是我们大多数时候不在这里实现,而是在OnTimer中。
函数功能:
SetTimer用来定义一个定时器的属性,如改定时器的ID,刷新时间,处理函数。
OnTimer实际时系统定义消息用来响应WM_TIMER消息,在这里可以实现对多定时器中的各个定时器分别响应,这里才时定时/doc/">程序大展宏图的地方。
字串2
KillTimer用来结束一个定时器。 字串1
下面我们用一个例子来说明定时器的使用:

这个例子用来实现一个简单的功能,就是在一个单/doc/">文档/doc/">程序中,每间隔5秒弹出一个消息框提示“定时器1”,每隔7秒弹出一个消息框提示“定时器2”。
建立单/doc/">文档/doc/">程序略,一路Next。
(1)在resource.h中定义两个定时器的ID
#define IDTIMER1 1
#define IDTIMER2 2
(2)在CMainFrame的OnCreate函数中定义两个定时器的属性。
SetTimer(TIMEID1,5000,0);
SetTimer(TIMEID2,7000,0);
(3) CMainFrame中对WM_TIMER进行响应。
void CMainFrame::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
switch(nIDEvent) {
case TIMEID1:
{
AfxMessageBox("定时器1!");
break;
} 字串1
case TIMEID2:
{
AfxMessageBox("定时器2!");
break;
}
default:
;
}

CFrameWnd::OnTimer(nIDEvent);
}
(4)在CMainFrame的析构函数中添加
KillTimer(IDTIMER1);
KillTimer(IDTIMER2);
本篇文章来源于 忒好程序员|https://www.360docs.net/doc/0814128670.html,
原文链接:https://www.360docs.net/doc/0814128670.html,/html/doc/kfyy/20071226/1105.html

Timer事件,即定时器事件,是在游戏编程中,经常使用的一个事件。借助它可以产生定时执行动作的效果。这篇文章,就和大家一起探讨一下如何使用SetTimer()函数。
1、SetTimer定义在那里?
SetTimer表示的是定义个定时器。根据定义指定的窗口,在指定的窗口(CWnd)中实现OnTimer事件,这样,就可以相应事件了。
SetTimer有两个函数。一个是全局的函数::SetTimer()
UINT SetTimer(
HWND hWnd, // handle of window for timer messages
UINT nIDEvent,

// timer identifier
UINT uElapse, // time-out value
TIMERPROC lpTimerFunc // address of timer procedure
);
其中hWnd 是指向CWnd的指针,即处理Timer事件的窗口类。说道窗口类(CWnd),我们有必要来看一下CWnd的继承情况:CWnd有以下子
类:CFrameWnd,CDialog,CView,CControlBar等类。这也意味这些类中都可以定义SetTimer事件。
同时,SetTimer()在CWnd中也有定义,即SetTimer()是CWnd的一个成员函数。CWnd的子类可以调用该函数,来设置触发器。
UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT*
lpfnTimer)(HWND, UINT, UINT, DWORD) );
参数含义:
nIDEvent:是指设置这个定时器的iD,即身份标志,这样在OnTimer()事件中,才能根据不同的定时器,来做不同的事件响应。这个ID是一个无符号的整型。
nElapse
是指时间延迟。单位是毫秒。这意味着,每隔nElapse毫秒系统调用一次Ontimer()。
void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD)
Specifies the address of the application-supplied
TimerProc
callback function that processes the WM_TIMER messages. If this parameter is
NULL, the WM_TIMER messages are placed in the application’s message queue and
handled by the CWnd object。
意思是,指定应用程序提供的TimerProc回调函数的地址,来处里这个Timer事件。如果是NULL,处理这个Timer事件的定义这个Timer的CWnd对象。他将WM_TIMER消息传递给这个对象,通过实现这个对象的OnTimer()事件来处理这个Timer事件。
所以,一般情况下,我们将这个值设为NULL,有设置该定时器的对象中的OnTimer()函数来处理这个事件。
同样的,我们再看看KillTimer()和OnTimer()的定义:
KillTimer同SetTimer()一样,他也有两个,一个是全局的::KillTimer(),另一个是CWnd的一个函数。他的声明如下:
//全局函数
BOOL KillTimer(
HWND hWnd, // handle of window that installed timer
UINT uIDEvent // timer identifier
);
//CWnd函数
BOOL KillTimer( int nIDEvent );
这两个函数表示的意思是将iD为nIDEVENT的定时器移走。使其不再作用。其用法如同SetTimer()一样。
再看看OnTimer()
afx_msg void OnTimer( UINT nIDEvent );
ontimer()是响应CWnd对象产生的WM_Timer消息。nIDEvent表示要响应TIMER事件的ID。
二、Timer事件的使用:
由以上的分析,我们应该很清楚,如何来使用Timer事件。假定我们在视图上画一个渐变的动画。我们首先在菜单栏上添加一个菜单项,给这个菜单添加命令响应:
pView->SetTimer(1,1000,NULL);//pView是视图类的指针,这里是在视图类当中设置一个定时器。
添加完毕,再给视图类添加一个WM_Timer事件的相应。在OnTimer()函数中编写汉书,进行相应。
如此,就能做出动画。




多媒体定时器

微软公司在其多媒体Windows中提供了精确定时器的底层API支持。利用多媒体定时器可以很精确地读出系统的当前时间,并且能在非常精确的时间间隔内完成一个事件、函数或过程的调用。利用多媒体定时器的基本功能,可以通过两种方法实现精确定时。


1.使用timeGetTime()函数

该函数定时精度为ms级,返回从Windows启动开始所经过的时间。由于使用该函数是通过查询的方式进行定时控制的,所以,应该建立定时循环来进行定时事件的控制。


2. 使用timeSetEvent()函数

利用该函数可以实现周期性的函数调用。函数的参数说明如下:

uDelay:延迟时间;

uResolution:时间精度,在Windows中缺省值为1ms;

lpFunction:回调函数,为用户自定义函数,定时调用;

dwUser:用户参数;

uFlags:标志参数;

TIME_ONESHOT:执行一次;

TIME_PERIODIC:周期性执行。

具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在lpFunction回调函数中(如:定时采样、控制
等),从而完成所需处理的事件。需要注意的是:任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后,应及时调用 timeKillEvent()将之释放。


下面这段代码的主要功能是设置两个时钟定时器,一个间隔是1ms,一个间隔是2s。每执行一次,把当前系统时钟值输入文件“cure.out”中,以比较该定时器的精确度。


//定义1ms和2s时钟间隔,以ms为单位

# define ONE_MILLI_SECOND 1

# define TWO_SECOND 2000

//定义时钟分辨率,以ms为单位

# define TIMER_ACCURACY 1

//定义时间间隔

UINT wTimerRes_1ms,wTimerRes_2s;

//定义分辨率

UINT wAccuracy;

//定义定时器句柄

UINT TimerID_1ms,TimerID_2s;

//打开输出文件“cure.out”

CCureApp::CCureApp():fout(“cure.out”, ios::out)

{

// 给时间间隔变量赋值

wTimerRes_1ms = ONE_MILLI_SECOND;

wTimerRes_2s = TWO_SECOND;

TIMECAPS tc;

//利用函数timeGetDevCaps取出系统分辨率的取值范围,如果无错则继续

if(timeGetDevCaps(&tc,sizeof(TIMECAPS))==TIMERR_NOERROR)

{

//分辨率的值不能超出系统的取值范围

wAccuracy=min(max(tc.wPeriodMin,

TIMER_ACCURACY),tc.wPeriodMax);

//调用timeBeginPeriod函数设置定时器的分辨率

timeBeginPeriod(wAccuracy);

//设置定时器

InitializeTimer();

}

}

CCureApp:: ~CCureApp()

{

//结束时钟

fout <<“结束时钟”<< endl;

// 删除两

个定时器

timeKillEvent(TimerID_1ms);
timeKillEvent(TimerID_2s);

// 删除设置的分辨率

timeEndPeriod(wAccuracy);

}

void CCureApp::InitializeTimer()

{

StartOneMilliSecondTimer();

StartTwoSecondTimer();

}

// 1ms定时器的回调函数,类似于中断处理程序,一定要声明为全局PASCAL函数,否则编译会有问题

void PASCAL OneMilliSecondProc(UINT wTimerID, UINT msg,DWORD
dwUser,DWORD dwl,DWORD dw2)

{

// 定义计数器

static int ms = 0;

CCureApp *app = (CCureApp *)dwUser;

// 取得系统时间,以ms为单位

DWORD osBinaryTime = GetTickCount();

//输出计数器值和当前系统时间

app->fout<<++ms<<“:1ms:”

<
}

// 加装1ms定时器

void CCureApp::StartOneMilliSecondTimer()

{

if((TimerID_1ms = timeSetEvent(wTimerRes_1ms,

wAccuracy,

// 回调函数

(LPTIMECALBACK) OneMil liSecondProc,

// 用户传送到回调函数的数据

(DWORD)this,

/ *周期调用,只使用一次,用TIME_ONESHOT*/

TIME_PERIODIC)) == 0)

{

AfxMessageBox(“不能进行定时!”, MB_OK | MB_ICONASTERISK);

}

else //不等于0表明加装成功,返回此定时器的句柄

fout << “16ms 计 时:” << endl;

}

相关文档
最新文档