VC++中计时器的运用

 
1、MFC中的计时原理:
当你需要每隔一段时间执行一件事的的时候就需要使用 SetTimer()函数了。 让我们先来看看SetTimer函数的原型:
    UINT SetTimer(UINT nIDEvent,UINT nElapse,void(CALLBACK EXPORT *lpfnTimer)(HWND,UINT ,YINT ,DWORD))
当使用 SetTimer函数的时候,就会生成一个计时器。函数中nIDEvent指的是计时器的标识,也就是名字。nElapse指的是时间间隔,也就是每隔多长时间触发一次事件。第三个参数是一个回调函数,在这个函数里,放入你想要做的事情的代码,你可以将它设定为NULL,也就是使用系统默认的回调函数,系统默认认的是onTime()函数。这个函数怎么生成的呢?你需要在需要计时器的类的生成onTime函数:在ClassWizard里,选择需要计时器的类,添加WM_TIME消息映射,就自动生成onTime函数了。然后在函数里添加代码,让代码实现功能。每隔一段时间就会自动执行一次。例: SetTimer(1,1000,NULL); 其中,1为计时器的名称; 1000为时间间隔,单位是毫秒; NULL指使用onTime函数。
如果最后一个参数不是 NULL,就调用 TimerProc () ,原型为:
void CALLBACK EXPORT TimerProc(
   HWND hWnd,      // handle of CWnd that called SetTimer
   UINT nMsg,      // WM_TIMER
   UINT nIDEvent   // timer identification
   DWORD dwTime    // system time
){}
 
 当不需要计时器的时候调用KillTimer(nIDEvent); 例如:KillTimer(1); 或许你会问,如果我要加入两个或者两个以上的 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; } }
小技巧:可以使用#define定义不同的计时器ID值。
#define TIME_SEC 1
#define TIME_MIN 2
然后调用SetTimer设定两个计时器
SetTimer (hwnd, TIMER_SEC, 1000, NULL) ;SetTimer (hwnd, TIMER_MIN, 600, NULL)
2、API函数
(1)、SetTimer函数用于创建一个计时器,KillTimer函数用于销毁一个计时器。计时器属于系统资源,使用完应及时销毁。
SetTimer的函数原型如下:
UINT_PTR SetTimer( HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc ) ;
  其中
  hWnd是和timer关联的窗口句柄,此窗口必须为调用SetTimer的线程所有;如果hWnd为NULL,没有窗口和timer相关联并且nIDEvent参数被忽略
  nIDEvent是timer的标识,为非零值;如果hWnd为NULL则被忽略;如果hWnd非NULL而且与timer相关联的窗口已经存在一个为此标识的timer,则此次SetTimer调用将用新的timer代替原来的timer。timer标识和窗口相关,两个不同的窗口可以拥有nIDEvent相同的timer
  uElapse是以毫秒指定的计时间隔值,范围为1毫秒到4,294,967,295毫秒(将近50天),这个值指示Windows每隔多久时间给程序发送WM_TIMER消息。
  lpTimerFunc是一个回调函数的指针,俗称TimerFunc;如果lpTimerFunc为NULL,系统将向应用程序队列发送WM_TIMER消息;如果lpTimerFunc指定了一个值,DefWindowProc将在处理WM_TIMER消息时调用这个lpTimerFunc所指向的回调函数,因此即使使用TimerProc代替处理WM_TIMER也需要向窗口分发消息。
关于 SetTimer的返回值:如果hWnd为NULL,返回值为新建立的timer的ID,如果hWnd非NULL,返回一个非0整数,如果SetTimer调用失败则返回0
KillTimer的函数原型为: BOOL KillTimer( HWND hWnd, UINT_PTR uIDEvent ) ; 参数意义同SetTimer。
  关于KillTimer对消息队列中剩余未处理的WM_TIMER消息的影响,MSDN和Programming Windows上的说法完全相反。MSDN的说法很干脆:The KillTimer function does not remove WM_TIMER messages already posted to the message queue. 而petzold则说 The KillTimer call purges the message queue of any pending WM_TIMER messages. Your program will never receive a stray WM_TIMER message following a KillTimer call.(KillTimer消除消息队列中任何未处理的WM_TIMER消息,调用KillTimer后你的程序永远不会收到一条“漂泊游荡”的WM_TIMER消息)
2)、关于WM_TIMER消息
wParam为计时器的ID;如果需要设定多个计时器,那么对每个计时器都使用不同的计时器ID。wParam的值将随传递到窗口过程中的WM_TIMER消息的不同而不同。
  lParam为指向TimerProc的指针,如果调用SetTimer时没有指定TimerProc(参数值为NULL),则lParam为0(即NULL)。
  可以通过在窗口过程中提供一个WM_TIMER case处理这个消息,或者,默认窗口过程会调用SetTimer中指定的TimerProc来处理WM_TIMER消息
(3)、 使用计时器的三种方法
如果在程序的整个执行过程中使用计时器,一般在处理 WM_CREATE消息时或WinMain中消息循环前调用SetTimer,在处理WM_DESTROY消息时或在WinMain中消息循环后return前调用KillTimer。根据SetTimer中的参数不同,有三种方法使用计时器。
方法一:调用SetTimer时指定窗口句柄hWnd,nIDEvent中指定计时器ID,将lpTimerFunc置NULL从而不使用TimerProc;在窗口过程中处理WM_TIMER消息。调用KillTimer时,使用SetTimer中指定的hWnd和id。最好使用#define定义timer的id,例如:
#define ID_TIMER 1
SetTimer(hWnd,ID_TIMER,1000,NULL) ;
KillTimer(hWnd,ID_TIMER) ;
方法二:调用SetTimer时指定窗口句柄hWnd,nIDEvent中指定计时器ID,lpTimerFunc参数不为NULL而指定为TimerProc函数的指针。这种方法使用TimerProc函数(名字可自定)处理WM_TIMER消息:
VOID CALLBACK TimerProc ( HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
{
 //处理WM_TIMER讯息
}
TimerProc的参数hwnd是在调用SetTimer时指定的窗口句柄。Windows只把WM_TIMER消息送给TimerProc,因此消息参数总是等于WM_TIMER。iTimerID值是计时器ID,dwTimer值是与从GetTickCount函数的返回值相容的值。这是自Windows启动后所经过的毫秒数。使用这种方法时,相关函数调用的形式为:
SetTimer(hWnd,ID_TIMER,1000,TimerProc) ;
KillTimer(hWnd,ID_TIMER) ;
方法三:调用SetTimer时不指定窗口句柄(为NULL),iTimerID参数自然被忽略,lpTimerFunc不为NULL而指定为TimerProc的指针。正如上面SetTimer的讨论中所说的,此时SetTimer的返回值正是新建立的计时器的ID,需将这个ID保存以供KillTimer销毁计时器时所用。当然,KillTimer的hWnd参数也置为NULL。这种方法同样用TimerProc处理WM_TIMER消息
UINT_PTR iTimerID ;
iTimerID = SetTimer(NULL,0,1000,TimerProc) ;
KillTimer(NULL,iTimerID) ;
使用这种方法的好处是不必自己指定计时器 ID,这样就不必担心用错ID。
(4)、 使用多个计时器
使用多个计时器只要在建立计时器时指定不同的ID。比如用上面所述方法一时的情况:
#define TIMER_SEC 1
#define TIMER_MIN 2

然后使用两个 SetTimer 来设定两个计时器:
SetTimer (hwnd, TIMER_SEC, 1000, NULL) ;
SetTimer (hwnd, TIMER_MIN, 60000, NULL) ;

WM_TIMER
的处理如下所示:
case WM_TIMER:
  switch (wParam)
  {
   case TIMER_SEC:
    // 每秒一次的处理
    break ;
   case TIMER_MIN:
    // 每分钟一次的处理
    break ;
  }
  return 0 ;
 

你可能感兴趣的:(VC++中计时器的运用)