VC++中計時器timer的運用

 
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 ;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章