MFC的定時器OnTimer

本文總結來源出自雞啄米,感謝雞啄米。來源:http://www.jizhuomi.com/software/232.htmlhtml

定時器簡介編程

       定時器,能夠幫助開發者或者用戶定時完成某項任務。在使用定時器時,咱們能夠給系統傳入一個時間間隔數據,而後系統就會在每一個此時間間隔後觸發定時處理程序,實現週期性的自動操做。例如,咱們能夠在數據採集系統中,爲定時器設置定時採集時間間隔爲1個小時,那麼每隔1個小時系統就會採集一次數據,這樣就能夠在無人操做的狀況下準確的進行操做。ide

       MFC定時器函數

       VS2010編程中,咱們可使用MFC的CWnd類提供的成員函數SetTimer實現定時器功能,也可使用Windows API函數SetTimer來實現。二者使用方法實際上很相似,但也有不一樣。工具

       CWnd類的SetTimer成員函數只能在CWnd類或其派生類中調用,而API函數SetTimer則沒有這個限制,這是一個很重要的區別。由於本教程主要是講解MFC編程,因此這裏就先重點講解MFC定時器的用法,關於API函數SetTimer的用法雞啄米會在MFC定時器講解的基礎上進行延伸。spa

       雞啄米下面分步驟給出使用MFC定時器的方法。指針

       一、啓動定時器。code

       啓動定時器就須要使用CWnd類的成員函數SetTimer。CWnd::SetTimer的原型以下:htm

       UINT_PTR SetTimer(
             UINT_PTR nIDEvent,
             UINT nElapse,
             void (CALLBACK* lpfnTimer
       )(HWND,
          UINT,
          UINT_PTR,
          DWORD
       ) 
       );對象

       參數nIDEvent指定一個非零的定時器ID;參數nElapse指定間隔時間,單位爲毫秒;參數lpfnTimer指定一個回調函數的地址,若是該參數爲NULL,則WM_TIMER消息被髮送到應用程序的消息隊列,並被CWnd對象處理。若是此函數成功則返回一個新的定時器的ID,咱們可使用此ID經過KillTimer成員函數來銷燬該定時器,若是函數失敗則返回0。

       經過SetTimer成員函數咱們能夠看出,處理定時事件能夠有兩種方式,一種是經過WM_TIMER消息的消息響應函數,一種是經過回調函數

       若是要啓動多個定時器就屢次調用SetTimer成員函數。另外,在不一樣的CWnd中能夠有ID相同的定時器,並不衝突。

       二、爲WM_TIMER消息添加消息處理函數,或者定義回調函數。

       若是調用CWnd::SetTimer函數時最後一個參數爲NULL,則經過WM_TIMER的消息處理函數來處理定時事件。添加WM_TIMER消息的處理函數的方法是,在VS2010工程的Class View類視圖中找到要添加定時器的類,點擊右鍵,選擇Properties,顯示其屬性頁,而後在屬性頁工具欄上點擊Messages按鈕,下面列表就列出了全部消息,找到WM_TIMER消息,添加消息處理函數。添加後,cpp文件中會出現相似以下內容:

C++代碼
  1. BEGIN_MESSAGE_MAP(CExample44Dlg, CDialogEx)   
  2.     ......   
  3.     ON_WM_TIMER()   
  4. END_MESSAGE_MAP()   
  5.   
  6. void CExample44Dlg::OnTimer(UINT_PTR nIDEvent)   
  7. {   
  8.     // TODO: Add your message handler code here and/or call default   
  9.   
  10.     CDialogEx::OnTimer(nIDEvent);   
  11. }  

       以後就能夠在OnTimer函數中進行相應的處理了。OnTimer的參數nIDEvent爲定時器ID,即在SetTimer成員函數中指定的定時器ID,若是有多個定時器,咱們能夠像下面這樣處理:

C++代碼
  1. void CExample44Dlg::OnTimer(UINT_PTR nIDEvent)      
  2. {      
  3.     // TODO: Add your message handler code here and/or call default      
  4.     switch (nIDEvent)      
  5.     {      
  6.     case 1:      
  7.         // 若是收到ID爲1的定時器的消息則調用func1函數      
  8.         func1();      
  9.         break;      
  10.     case 2:      
  11.         // 若是收到ID爲2的定時器的消息則調用func2函數      
  12.         fun2();    
  13.        break;     
  14.     ......      
  15.     default:      
  16.         break;      
  17.     }      
  18.      
  19.     CDialogEx::OnTimer(nIDEvent);      
  20. }     

       若是調用CWnd::SetTimer函數時最後一個參數不爲NULL,則須要定義回調函數。回調函數的形式以下:

C++代碼
  1. void CALLBACK EXPORT TimerProc(   
  2.   
  3. HWND hWnd, // handle of CWnd that called SetTimer   
  4.   
  5. UINT nMsg, // WM_TIMER   
  6.   
  7. UINT nIDEvent // timer identification   
  8.   
  9. DWORD dwTime // system time   
  10.   
  11. );  

       參數hWnd爲調用SetTimer成員函數的CWnd對象的句柄,即擁有此定時器的窗口的句柄;參數nMsg爲WM_TIMER,並且老是爲WM_TIMER;參數nIDEvent爲定時器ID;參數dwTime爲系統啓動以來的毫秒數,即GetTickCount函數的返回值。

       這樣CWnd::SetTimer函數最後一個參數就能夠爲TimerProc。

       這裏注意下,回調函數的名稱不必定爲TimerProc,能夠取其餘名字,但返回值類型、參數的類型和個數不能改變。

       雞啄米給出一個回調函數的例子:

C++代碼
  1. void CALLBACK EXPORT TimerProc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime)      
  2. {      
  3.    switch(nTimerid)      
  4.    {      
  5.    case 1:       
  6.          // 處理ID爲1的定時器的事件      
  7.          func1();      
  8.          break;      
  9.    case 2:       
  10.          // 處理ID爲2的定時器的事件      
  11.          func2();      
  12.          break;    
  13.    ......   
  14.    default:   
  15.         break;     
  16.    }      
  17. }     

       回調函數爲全局函數,須要寫在使用它的位置的前面,或者寫在後面而後在使用以前聲明。

       三、銷燬定時器。

       再也不使用定時器時,能夠銷燬它。銷燬定時器需使用CWnd類的KillTimer成員函數,CWnd::KillTimer函數的原型以下:

C++代碼
  1. BOOL KillTimer(UINT_PTR nIDEvent);  

       參數nIDEvent爲要銷燬的定時器的ID,是調用CWnd::SetTimer函數時設置的定時器ID。若是定時器被銷燬則返回TRUE,而若是沒有找到指定的定時器則返回FALSE。

       若是要銷燬多個定時器,則屢次調用KillTimer函數並分別傳入要銷燬的定時器的ID。

       經過Windows API函數使用定時器

       若是咱們不使用MFC定時器,而經過Windows API函數使用定時器,實際上是很相似的。下面雞啄米簡單說下步驟吧。

       一、啓動定時器。

       使用API函數SetTimer啓動定時器,SetTimer函數的原型以下:

C++代碼
  1. UINT_PTR SetTimer(         
  2.     HWND    
  3.             hWnd,   
  4.     UINT_PTR    
  5.             nIDEvent,   
  6.     UINT    
  7.             uElapse,   
  8.     TIMERPROC    
  9.             lpTimerFunc   
  10. );  

       參數hWnd爲與定時器關聯的窗口的句柄;參數nIDEvent爲非零的定時器ID,若是hWnd等於NULL,且還不存在ID爲nIDEvent的定時器,那麼nIDEvent參數被忽略,而後生成一個新ID的定時器,而若是hWnd不爲NULL,且hWnd指定的窗口已存在ID爲nIDEvent的定時器,那麼這個已存在的定時器被新定時器所取代。參數uElapse和lpTimerFunc同CWnd::SetTimer函數。

       二、爲WM_TIMER消息添加消息處理函數,或者定義回調函數。

       若是調用SetTimer函數時最後一個參數爲NULL,咱們須要本身爲WM_TIMER消息添加處理函數,要注意的是,WM_TIMER消息的附加數據wParam爲定時器ID,lParam爲回調函數的指針,若是調用SetTimer時回調函數爲NULL,那麼lParam也爲NULL。

       而若是調用SetTimer函數時最後一個參數不爲NULL,咱們就須要定義回調函數。回調函數的定義同MFC定時器。

       三、銷燬定時器。

       銷燬定時器使用KillTimer API函數,原型以下:

C++代碼
  1. BOOL KillTimer(HWND hWnd,UINT_PTR uIDEvent);   

       參數hWnd爲與定時器關聯的窗口的句柄,與啓動定時器時SetTimer函數的hWnd參數值相同;參數uIDEvent爲要銷燬的定時器的ID,若是傳遞給SetTimer的參數hWnd有效,則uIDEvent應與傳遞給SetTimer的參數nIDEvent相同,而若是SetTimer的參數hWnd爲NULL,則uIDEvent應爲SetTimer返回的定時器ID。該函數成功則返回TRUE,不然返回FALSE。

       MFC定時器應用實例

       雞啄米給你們演示一個定時器的例子,該實例功能很簡單,就是使用兩個定時器,定時更新兩個編輯框中的顯示內容,第一個編輯框每秒刷新一次,從1刷新到10,而後銷燬定時器,第二個編輯框每兩秒刷新一次,從1刷新到5,而後銷燬定時器。下面簡單說下步驟:

       一、建立基於對話框的工程,名稱設爲「Example44」。

       二、在自動生成的對話框模板IDD_EXAMPLE44_DIALOG中,刪除「TODO: Place dialog controls here.」靜態文本控件。添加兩個靜態文本框控件,Caption分別設爲「1秒鐘刷新一次」和「2秒鐘刷新一次」,再添加兩個個Edit Control控件,ID使用默認的IDC_EDIT1和IDC_EDIT2,二者的Read Only屬性都設爲True。此時的對話框模板以下圖:

MFC定時器對話框模板

       三、爲CExample44Dlg類添加兩個成員變量,分別爲m_nData一、m_nData2,並在CExample44Dlg類的構造函數中初始化:

C++代碼
  1. CExample44Dlg::CExample44Dlg(CWnd* pParent /*=NULL*/)   
  2.     : CDialogEx(CExample44Dlg::IDD, pParent)   
  3. {   
  4.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);   
  5.     // 兩個數據初始化爲0   
  6.     m_nData1 = 0;   
  7.     m_nData2 = 0;   
  8. }  

       四、在對話框模板上雙擊OK按鈕,添加點擊消息的處理函數,並修改以下:

C++代碼
  1. void CExample44Dlg::OnBnClickedOk()   
  2. {   
  3.     // TODO: Add your control notification handler code here   
  4.     // 啓動ID爲1的定時器,定時時間爲1秒   
  5.     SetTimer(1, 1000, NULL);   
  6.     // 啓動ID爲2的定時器,定時時間爲2秒   
  7.     SetTimer(2, 2000, NULL);   
  8.   
  9.     //CDialogEx::OnOK();   
  10. }  

       這樣,點擊OK按鈕時就不會退出,而是啓動兩個定時器。

       五、根據上面MFC定時器講解中爲WM_TIMER消息添加處理函數的方法,添加WM_TIMER的消息處理函數OnTimer,並修改其實現以下:

C++代碼
  1. void CExample44Dlg::OnTimer(UINT_PTR nIDEvent)   
  2. {   
  3.     // TODO: Add your message handler code here and/or call default   
  4.     switch (nIDEvent)   
  5.     {   
  6.     case 1:   
  7.         // 若是m_nData1已經達到10,則銷燬ID爲1的定時器   
  8.         if (10 == m_nData1)   
  9.         {   
  10.             KillTimer(1);   
  11.             break;   
  12.         }   
  13.         // 刷新編輯框IDC_EDIT1的顯示   
  14.         SetDlgItemInt(IDC_EDIT1, ++m_nData1);   
  15.         break;   
  16.     case 2:   
  17.         // 若是m_nData2已經達到5,則銷燬ID爲2的定時器   
  18.         if (5 == m_nData2)   
  19.         {   
  20.             KillTimer(2);   
  21.             break;   
  22.         }   
  23.         // 刷新編輯框IDC_EDIT2的顯示   
  24.         SetDlgItemInt(IDC_EDIT2, ++m_nData2);   
  25.     default:   
  26.         break;   
  27.     }   
  28.   
  29.     CDialogEx::OnTimer(nIDEvent);   
  30. }  

       六、運行程序,點擊OK按鈕,查看效果。

MFC定時器實例

 、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

一、在類中定義

afx_msg void OnTimer(UINT nIDEvent);

二、在CPP中添加

BEGIN_MESSAGE_MAP(YuJingDlg, CDialog)
ON_WM_CTLCOLOR() //顏色消息
//ON_WM_PAINT()
ON_WM_TIMER
ON_BN_CLICKED(IDCANCEL, &YuJingDlg::OnBnClickedCancel)
END_MESSAGE_MAP()

三、在初始話函數或其餘按鈕響應中添加

SetTimer(1,50,NULL);     //定時器1,50ms刷新一次,使用OnTimer函數

四、寫OnTimer函數  

void YuJingDlg::OnTimer(UINT nIDEvent) { th+=0.157; if(th>6.28) th-=6.28; //Invalidate(); InvalidateRect(CRect(0,0,500,500));        //刷新區域 CDialog::OnTimer(nIDEvent);}

相關文章
相關標籤/搜索