程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> VC 多個定時器實現教程

VC 多個定時器實現教程

編輯:關於C語言
 

SetTimer函數的原型:

UINT_PTR SetTimer(

HWND hWnd, // 窗口句柄

UINT_PTR nIDEvent, // 定時器ID,多個定時器時,可以通過該ID判斷是哪個定時器

UINT uElapse, // 時間間隔,單位為毫秒

TIMERPROC lpTimerFunc // 回調函數

);在MFC程序中SetTimer被封裝在CWnd類中,調用就不用指定窗口句柄了,例如:SetTimer(1,100,NULL); //1為ID號.100為時間例如:
// 添加兩個定時器SetTimer(1,500,NULL);SetTimer(2,1000,NULL);//停止定時器KillTimer(1);//停止ID為1的定時器KillTimer(2);//停止ID為2的定時器 定時器:void CTimerTestDlg::OnTimer(UINT nIDEvent) {switch (nIDEvent){case 1: ///處理ID為1的定時器... break;case 2: ///處理ID為2的定時器...break;}

很多應用程序都需要使用定時器,以便定期檢查狀態,並重新繪圖。學過VB的朋友知道,VB中的定時器是一個控件,我們只需要放置一個定時器控件到窗體之上,然後設置其屬性,並在程序中處理該控件產生的定時事件就行了。不過在VC中並沒有定時器控件,我們可以通過兩種方法來使用定時器:一種是直接調用WIN32函數SetTimer(),另一種則是調用CWnd::SetTimer(),實際上這兩種方法的本質是一樣的,下面我們就來看看後者的使用方法。

l 設置和釋放定時器

CWnd::SetTimer()的功能是給當前窗口設置一個定時器,該函數的原型為:

UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );

由於一個窗口可以同時設置幾個定時器,SetTimer()的第一個參數nIDEvent起標識不同定時器的作用,我們可以任意取值,只要不與其它定時器的標識重復就行了,以便將來能正確分辨出是哪個定時器發出的定時消息。nElapse表示每隔多少毫秒產生一次定時消息。lpfnTimer是一個函數指針,如果傳遞一個NULL指針,那麼在產生定時中斷時,Windows會把一條WM_TIMER消息放入到程序的消息隊列之中,最終由CWnd對象相應的處理函數來處理該消息;如果傳遞了一個真正的函數指針,那麼在產生定時中斷時,Windows將直接調用該函數,由該函數來處理定時消息。這也就是說,我們可以使用兩種方式來處理定時消息,它們有什麼區別呢?

首先,WM_TIMER是一條低優先級的消息。如果消息隊列之中還有其它高優先級的消息,那麼WM_TIMER將被堵塞,直到最後才會被處理。其次,WM_TIMER被程序從消息隊列中取回之後,還要經過一系列的過程才能被傳遞到它的處理函數。把這兩點結合起來可以看出,在第一種方式下,定時消息有可能要拖延一段時間才會被處理,而第二種方式則不同,由於Windows將直接調用指定的函數,所以延遲時間要短得多。

由於Schedule對實時性要求並不苛刻,只要能精確到分鐘左右就可以了,另外Schedule內部要進行的運算和處理也不多,所以心鈴決定選用第一種方式,准備在視類中處理定時消息。在第十二講給出的CScheduleView::OnInitialUpdate()的最後一行語句便是設置定時器的代碼,現在我們可以把它前面的注釋符號刪掉了,這個定時器將使Schedule在每過20秒左右的時間得到一次重新檢查各事件狀態的機會。

定時器是一種有限的系統資源,如果多個程序都需要使用定時器,那麼有可能會出現設置不成功的情況,因此我們應在調用SetTimer()函數時檢查它的返回值,如果返回值是0,就表示系統中已經沒有可用的定時器了。Schedule沒有進行這步檢查,心鈴想請大家自己添上,並決定在出現這種情況時應該怎麼辦。

SetTimer()還有一個作用是它能夠重新設置已分配的定時器的定時間隔,只要在nIDEvent中傳遞已分配的定時器的標識,那麼該定時器的定時間隔就會改變成nElapse中指定的新值。

在程序退出時,我們應該將已分配的定時器釋放掉。為此我們利用ClassWizard為視類添加一個處理WM_DESTROY消息的函數OnDestroy(),並編寫以下代碼:

void CScheduleView::OnDestroy() {

KillTimer(1);

CListCtrl & lst=(this->GetListCtrl());

CImageList *pImageList=lst.GetImageList(LVSIL_SMALL);

delete pImageList;

CListView::OnDestroy();

}

KillTimer()用於釋放定時器,其參數應等於SetTimer()的nIDEvent。如果程序分配了多個定時器,那麼應調用多次KillTimer()。OnDestroy()同時也把與CListView內部的List控件關聯的圖象列表釋放了。

l 編寫消息處理函數

使用定時器的第一種方式需要用到一個回調函數,該函數必須具有以下原型:

void CALLBACK EXPORT TimerProc( HWND hWnd, UINT nMsg, UINT nIDEvent,

DWORD dwTime );

由於我們不使用這種方式,所以TimerProc各參數的含義請大家自己查閱MSDN庫,下面我們來看看如何為第二種方式編寫消息處理函數。

首先我們利用ClassWizard為視類添加一個處理WM_TIMER消息的函數OnTimer()。它只有一個參數nIDEvent,檢查這個值便可以知道WM_TIMER消息是由哪個定時器發出的。下面便是OnTimer()的實現代碼:

void CScheduleView::OnTimer(UINT nIDEvent) {

CTime tiNow=CTime::GetCurrentTime();

CTimeSpan tdif(0,0,15,0);

CScheduleDoc * pDoc=GetDocument();

CString Message;

struct ScheduleItem* pUp,*pDown;

pUp=pDoc->m_pNearestTaskUp;

pDown=pDoc->m_pNearestTaskDown;

if(nIDEvent==1) {

if( ( (pUp!=NULL) && (pUp->ti<tiNow-tdif) ) ||

( (pDown!=NULL) && (pDown->ti<=tiNow+tdif) ) ) {

pDoc->SearchNearestTask();

//更新事件條目的狀態

pDoc->UpdateState();

pDoc->UpdateAllViews(NULL,0,NULL);

//更新顯示

if((pDown!=NULL) && ( pDown->ti <= (tiNow+tdif) )) {

AfxGetMainWnd()->ShowWindow(SW_NORMAL);

SetForegroundWindow(); //把窗口顯示在前台

Message="請注意:\""; //准備提示信息

Message += pDown->des;

Message += "\" 的時間很快就要到了!";  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved