Windows定時器是一種周期性的消息產(chǎn)生裝置,,它會每隔一段指定時間發(fā)送一次定時消息WM_TIMER。它是一個很重要的系統(tǒng)消息,,當(dāng)系統(tǒng)所設(shè)置的時間到達(dá)以后,,系統(tǒng)就會自動發(fā)送該消息。與該消息聯(lián)系密切的函數(shù)是SetTimer(),,它設(shè)置一個系統(tǒng)時鐘,,當(dāng)設(shè)置的時間到時,系統(tǒng)產(chǎn)生WM_TIMER消息,。通過對SetTimer()函數(shù)的參數(shù)進(jìn)行設(shè)置,,可以告訴用戶哪一個時鐘的時間到了。因此,,可以將一些周期性的工作放入WM_TIMER的消息處理函數(shù)中,。 定時器的使用一般遵循下列步驟: (1)使用SetTimer()函數(shù)設(shè)置定時器 SetTimer()函數(shù)的原型如下:
UINT SetTimer(UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT*lpfnTimer)(HWND,UINT, UINT, DWORD));
其中,,參數(shù)nIDEvent為新創(chuàng)建的定時器標(biāo)識號碼(非零),,當(dāng)一個應(yīng)用程序需要多個定時器時,靠此參數(shù)的不同來加以區(qū)別,;參數(shù)nElapse為定時器間隔,,以毫秒為單位,當(dāng)由該參數(shù)規(guī)定的時間到后,,系統(tǒng)發(fā)送WM_TIMER消息,;參數(shù)lpfnTimer為指定處理消息WM_TIMER的函數(shù),通常為NULL時,,表示由CWnd對象的OnTimer成員函數(shù)來處理該消息,,當(dāng)然也可以超載該函數(shù)。 如果創(chuàng)建成功,,則返回新的定時器的號碼:否則返回0,。 (2)超載OnTimer()函數(shù),完成用戶希望的操作 通過第一步設(shè)置的定時器會按其設(shè)置的時間間隔向應(yīng)用程序發(fā)送WM_TIMER消息,,為了接收和處理該消息,,應(yīng)超載消息處理函數(shù)OnTimer()(可以由ClassWizard自動產(chǎn)生),,其函數(shù)原型如下:
afx_msg void OnTimer(UINT nIDEvent);
其中,參數(shù)nIDEvent為定時器的標(biāo)識,。若在程序中設(shè)置了多個定時器時,,靠此參數(shù)的不同來加以區(qū)別。 (3)撤銷定時器 CWnd::KillTimer
定時器使用完后,,可以通過調(diào)用KillTimer()函數(shù)來清除定時器,,其函數(shù)原型如下:
BOOL KillTimer(int nIDEvent);
其中,參數(shù)nIDEvent為準(zhǔn)備清除的定時器號碼,,該參數(shù)的值必須在SetTimer()函數(shù)中設(shè)置過,,即不能夠清除一個不存在的定時器號碼。 【例9.4】 本程序在例9.3程序的基礎(chǔ)上增加定時器的功能,。當(dāng)按B鍵時,,啟動定時器,屏幕上的圖形自動移動,;當(dāng)按S鍵時,,撤銷定時器,停止自動移動,。 程序演示 (1)在字符消息映射函數(shù)中添加啟動和撤銷定時器的代碼
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的消息映射函數(shù)OnTimer()的實現(xiàn)代碼
void CKeyMsgView::OnTimer(UINT nIDEvent) { //圖形往右下角自動移動 CRect OldRect=m_Rect; m_Rect.OffsetRect(CPoint(1,1)); //圖形往右下角移動一個像素 OldRect.UnionRect(OldRect,m_Rect); InvalidateRect(OldRect); //將指定矩形區(qū)域OldRect的內(nèi)容刷新 CView::OnTimer(nIDEvent); }
該TimerProc函數(shù)是一個應(yīng)用程序定義的回調(diào)函數(shù),用于處理WM_TIMER消息,。
函數(shù)原型: VOID CALLBACK TimerProc( HWND hwnd, // 定時器消息的窗口句柄 UINT uMsg, // WM_TIMER 消息 UINT idEvent, // 定時器標(biāo)識符 DWORD dwTime // 當(dāng)前系統(tǒng)時間 );
參數(shù)說明: hwnd 標(biāo)識了與定時器進(jìn)行關(guān)聯(lián)的窗口,。 uMsg 指定WM_TIMER消息。 idEvent 指定定時器的標(biāo)識符,。 dwTime 指定自窗口啟動開始所經(jīng)過的毫秒數(shù),。這是GetTickCount函數(shù)的返回值。 返回值: 這個函數(shù)沒有返回值,。 備注: TimerProc是一個應(yīng)用程序定義函數(shù)名稱的占位符,。
百度知道: SetTimer函數(shù)的用法 1 )用WM_TIMER來設(shè)置定時器 先請看SetTimer這個API函數(shù)的原型 UINT_PTR SetTimer( HWND hWnd, // 窗口句柄 UINT_PTR nIDEvent, // 定時器ID,多個定時器時,,可以通過該ID判斷是哪個定時器 UINT uElapse, // 時間間隔,單位為毫秒 TIMERPROC lpTimerFunc // 回調(diào)函數(shù) ); 例如 SetTimer(m_hWnd,1,1000,NULL); //一個1秒觸發(fā)一次的定時器 在MFC程序中SetTimer被封裝在CWnd類中,,調(diào)用就不用指定窗口句柄了 于是SetTimer函數(shù)的原型變?yōu)椋?/font> UINT SetTimer(UINT nIDEvent,UINT nElapse,void(CALLBACK EXPORT *lpfnTimer)(HWND,UINT ,UINT ,DWORD)) 當(dāng)使用SetTimer函數(shù)的時候,就會生成一個計時器,。函數(shù)中nIDEvent指的是計時器的標(biāo)識,,也就是名字。nElapse指的是時間間隔,, 也就是每隔多長時間觸發(fā)一次事件,。第三個參數(shù)是一個回調(diào)函數(shù),在這個函數(shù)里,,放入你想要做的事情的代碼,,你可以將它設(shè)定為NULL, 也就是使用系統(tǒng)默認(rèn)的回調(diào)函數(shù),,系統(tǒng)默認(rèn)認(rèn)的是onTime函數(shù),。這個函數(shù)怎么生成的呢?你需要在需要計時器的類的生成onTime函數(shù): 在ClassWizard里,,選擇需要計時器的類,,添加WM_TIME消息映射,就自動生成onTime函數(shù)了,。然后在函數(shù)里添加代碼,,讓代碼實現(xiàn)功能。 每隔一段時間就會自動執(zhí)行一次,。 SetTimer計時器是系統(tǒng)資源,,使用完畢應(yīng)及時用KillTimer銷毀,關(guān)于SetTimer的返回值:如果hWnd為NULL,,返回值為新建立的timer的ID,,如果hWnd非NULL,返回一個非0整數(shù),,如果SetTimer調(diào)用失敗則返回0 ,,簡言之,SetTimer的返回值用于將來的銷毀,。 改變計時器的時間間隔 如果想將一個已經(jīng)存在的計時器設(shè)定為不同的時間間隔,,可以簡單地用不同的時間值再次調(diào)用SetTimer。 計時器精確嗎,? 計時器并不精確,。有兩個原因: 原因一:Windows計時器是硬件和ROM BIOS架構(gòu)下之計時器一種相對簡單的擴充?;氐絎indows以前的MS-DOS程序?qū)懽鳝h(huán)境下,,應(yīng)用程式能夠通過攔截者稱為timer tick的BIOS中斷來實現(xiàn)時鐘或計時器。一些為MS-DOS編寫的程序自己攔截這個硬件中斷以實現(xiàn)時鐘和計時器,。這些中斷每54.915毫秒產(chǎn)生一次,,或者大約每秒18.2次,。這是原始的IBM PC的微處理器頻率值4.772720 MHz被218所除而得出的結(jié)果。在Windows 98中,,計時器與其下的PC計時器一樣具有55毫秒的解析度,。在Microsoft Windows NT中,計時器的解析度為10毫秒,。Windows應(yīng)用程式不能以高于這些解析度的頻率(在Windows 98下,,每秒18.2次,在Windows NT下,,每秒大約100次)接收WM_TIMER消息,。在SetTimer中指定的時間間隔總是截尾后tick數(shù)的整數(shù)倍。例如,,1000毫秒的間隔除以54.925毫秒,,得到18.207個tick,截尾后是18個tick,,它實際上是989毫秒,。對每個小于55毫秒的間隔,每個tick都會產(chǎn)生一個WM_TIMER消息,。 可見,,計時器并不能嚴(yán)格按照指定的時間間隔發(fā)送WM_TIMER消息,它總要相差那么幾毫秒,。 即使忽略這幾個毫秒的差別,,計時器仍然不精確。請看原因二: WM_TIMER消息放在正常的消息隊列之中,,和其他消息排列在一起,,因此,如果在SetTimer中指定間隔為1000毫秒,,那么不能保證程序每1000毫秒或者989毫秒就會收到一個WM_TIMER消息,。如果其他程序的執(zhí)行事件超過一秒,在此期間內(nèi),,您的程式將收不到任何WM_TIMER訊息,。事實上, Windows對WM_TIMER消息的處理非常類似于對WM_PAINT消息的處理,,這兩個消息都是低優(yōu)先級的,,程序只有在消息隊列中沒有其他消息時才接收它們。 WM_TIMER還在另一方面和WM_PAINT相似:Windows不能持續(xù)向消息隊列中放入多個WM_TIMER訊息,,而是將多余的WM_TIMER消息組合成一個消息,。因此,應(yīng)用程序不會一次收到多個這樣的消息,盡管可能在短時間內(nèi)得到兩個WM_TIMER消息,。應(yīng)用程序不能確定這種處理方式所導(dǎo)致的WM_TIMER消息「遺漏」的數(shù)目,。 可見,WM_TIMER消息并不能及時被應(yīng)用程序所處理,,WM_TIMER在消息隊列中的延誤可能就不能用毫秒來計算了,。 由以上兩點,你不能通過在處理WM_TIMER時一秒一秒計數(shù)的方法來計時,。如果要實現(xiàn)一個時鐘程序,,可以使用系統(tǒng)的時間函數(shù)如GetLocalTime ,,而在時鐘程序中,,計時器的作用是定時調(diào)用GetLocalTime獲得新的時間并刷新時鐘畫面,當(dāng)然這個刷新的間隔要等于或小于1秒,。 例:1) 不用回調(diào)函數(shù) SetTimer(1,1000,NULL); 1:計時器的名稱,; 1000:時間間隔,單位是毫秒,; NULL:使用onTime函數(shù),。 當(dāng)不需要計時器的時候調(diào)用KillTimer(nIDEvent); 例如:KillTimer(1); 2) 調(diào)用回調(diào)函數(shù) 此方法首先寫一個如下格式的回調(diào)函數(shù) void CALLBACK TimerProc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime); 然后再用SetTimer(1,100,TimerProc)函數(shù)來建一個定時器,第三個參數(shù)就是回調(diào)函數(shù)地址,。 或許你會問,,如果我要加入兩個或者兩個以上的 timer怎么辦? 繼續(xù)用SetTimer函數(shù)吧,,上次的timer的ID是1,,這次可以是2,3,,4,。。,。,。 SetTimer(2,1000,NULL); SetTimer(3,500,NULL); 嗯,WINDOWS會協(xié)調(diào)他們的,。當(dāng)然onTimer函數(shù)體也要發(fā)生變化,,要在函數(shù)體內(nèi)添加每一個timer的處理代碼: onTimer(nIDEvent) { switch(nIDEvent) { case 1:........; break; case 2:.......; break; case 3:......; break; } } |
|
來自: VoidOc > 《VC VC6.0》