轉(zhuǎn)帖|使用教程|編輯:鮑佳佳|2021-06-22 10:49:34.937|閱讀 1126 次
概述:Visual Studio編程中,我們可以使用MFC的CWnd類提供的成員函數(shù)SetTimer實(shí)現(xiàn)定時(shí)器功能,也可以使用Windows API函數(shù)SetTimer來實(shí)現(xiàn)。兩者使用方法實(shí)際上很類似,但也有不同。CWnd類的SetTimer成員函數(shù)只能在CWnd類或其派生類中調(diào)用,而API函數(shù)SetTimer則沒有這個(gè)限制,這是一個(gè)很重要的區(qū)別。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關(guān)鏈接:
上一節(jié)中講了的用法,本節(jié)繼續(xù)講另外兩個(gè)常用類-日期和時(shí)間類CTime類和CTimeSpan類。在內(nèi)容開始前為大家介紹一款MFC界面開發(fā)控件:
前面一節(jié)講了CTime類和CTimeSpan類的使用,本節(jié)繼續(xù)講與時(shí)間有關(guān)的定時(shí)器。定時(shí)器并不是一個(gè)類,主要考慮到,提起時(shí)間的話就不能不說定時(shí)器,所以就把它放到CTime和CTimeSpan之后講解。
定時(shí)器簡(jiǎn)介
定時(shí)器,可以幫助開發(fā)者或者用戶定時(shí)完成某項(xiàng)任務(wù)。在使用定時(shí)器時(shí),我們可以給系統(tǒng)傳入一個(gè)時(shí)間間隔數(shù)據(jù),然后系統(tǒng)就會(huì)在每個(gè)此時(shí)間間隔后觸發(fā)定時(shí)處理程序,實(shí)現(xiàn)周期性的自動(dòng)操作。例如,我們可以在數(shù)據(jù)采集系統(tǒng)中,為定時(shí)器設(shè)置定時(shí)采集時(shí)間間隔為1個(gè)小時(shí),那么每隔1個(gè)小時(shí)系統(tǒng)就會(huì)采集一次數(shù)據(jù),這樣就可以在無人操作的情況下準(zhǔn)確的進(jìn)行操作。
MFC定時(shí)器
VS2010編程中,我們可以使用MFC的CWnd類提供的成員函數(shù)SetTimer實(shí)現(xiàn)定時(shí)器功能,也可以使用Windows API函數(shù)SetTimer來實(shí)現(xiàn)。兩者使用方法實(shí)際上很類似,但也有不同。
CWnd類的SetTimer成員函數(shù)只能在CWnd類或其派生類中調(diào)用,而API函數(shù)SetTimer則沒有這個(gè)限制,這是一個(gè)很重要的區(qū)別。因?yàn)楸窘坛讨饕侵v解MFC編程,所以這里就先重點(diǎn)講解MFC定時(shí)器的用法,關(guān)于API函數(shù)SetTimer的用法雞啄米會(huì)在MFC定時(shí)器講解的基礎(chǔ)上進(jìn)行延伸。
雞啄米下面分步驟給出使用MFC定時(shí)器的方法。
1、啟動(dòng)定時(shí)器。
啟動(dòng)定時(shí)器就需要使用CWnd類的成員函數(shù)SetTimer。CWnd::SetTimer的原型如下:
UINT_PTR SetTimer( UINT_PTR nIDEvent, UINT nElapse, void (CALLBACK* lpfnTimer )(HWND, UINT, UINT_PTR, DWORD ) );
參數(shù)nIDEvent指定一個(gè)非零的定時(shí)器ID;參數(shù)nElapse指定間隔時(shí)間,單位為毫秒;參數(shù)lpfnTimer指定一個(gè)回調(diào)函數(shù)的地址,如果該參數(shù)為NULL,則WM_TIMER消息被發(fā)送到應(yīng)用程序的消息隊(duì)列,并被CWnd對(duì)象處理。如果此函數(shù)成功則返回一個(gè)新的定時(shí)器的ID,我們可以使用此ID通過KillTimer成員函數(shù)來銷毀該定時(shí)器,如果函數(shù)失敗則返回0。
通過SetTimer成員函數(shù)我們可以看出,處理定時(shí)事件可以有兩種方式,一種是通過WM_TIMER消息的消息響應(yīng)函數(shù),一種是通過回調(diào)函數(shù)。
如果要啟動(dòng)多個(gè)定時(shí)器就多次調(diào)用SetTimer成員函數(shù)。另外,在不同的CWnd中可以有ID相同的定時(shí)器,并不沖突。
2、為WM_TIMER消息添加消息處理函數(shù),或者定義回調(diào)函數(shù)。
如果調(diào)用CWnd::SetTimer函數(shù)時(shí)最后一個(gè)參數(shù)為NULL,則通過WM_TIMER的消息處理函數(shù)來處理定時(shí)事件。添加WM_TIMER消息的處理函數(shù)的方法是,在VS2010工程的Class View類視圖中找到要添加定時(shí)器的類,點(diǎn)擊右鍵,選擇Properties,顯示其屬性頁(yè),然后在屬性頁(yè)工具欄上點(diǎn)擊Messages按鈕,下面列表就列出了所有消息,找到WM_TIMER消息,添加消息處理函數(shù)。添加后,cpp文件中會(huì)出現(xiàn)類似如下內(nèi)容:
C++代碼
BEGIN_MESSAGE_MAP(CExample44Dlg, CDialogEx) ...... ON_WM_TIMER() END_MESSAGE_MAP() void CExample44Dlg::OnTimer(UINT_PTR nIDEvent) { // TODO: Add your message handler code here and/or call default CDialogEx::OnTimer(nIDEvent); }
之后就可以在OnTimer函數(shù)中進(jìn)行相應(yīng)的處理了。OnTimer的參數(shù)nIDEvent為定時(shí)器ID,即在SetTimer成員函數(shù)中指定的定時(shí)器ID,如果有多個(gè)定時(shí)器,我們可以像下面這樣處理:
C++代碼
void CExample44Dlg::OnTimer(UINT_PTR nIDEvent) { // TODO: Add your message handler code here and/or call default switch (nIDEvent) { case 1: // 如果收到ID為1的定時(shí)器的消息則調(diào)用func1函數(shù) func1(); break; case 2: // 如果收到ID為2的定時(shí)器的消息則調(diào)用func2函數(shù) fun2(); break; ...... default: break; } CDialogEx::OnTimer(nIDEvent); }
如果調(diào)用CWnd::SetTimer函數(shù)時(shí)最后一個(gè)參數(shù)不為NULL,則需要定義回調(diào)函數(shù)。回調(diào)函數(shù)的形式如下:
C++代碼
void CALLBACK EXPORT TimerProc( HWND hWnd, // handle of CWnd that called SetTimer UINT nMsg, // WM_TIMER UINT nIDEvent // timer identification DWORD dwTime // system time );
參數(shù)hWnd為調(diào)用SetTimer成員函數(shù)的CWnd對(duì)象的句柄,即擁有此定時(shí)器的窗口的句柄;參數(shù)nMsg為WM_TIMER,而且總是為WM_TIMER;參數(shù)nIDEvent為定時(shí)器ID;參數(shù)dwTime為系統(tǒng)啟動(dòng)以來的毫秒數(shù),即GetTickCount函數(shù)的返回值。
這樣CWnd::SetTimer函數(shù)最后一個(gè)參數(shù)就可以為TimerProc。
這里注意下,回調(diào)函數(shù)的名稱不一定為TimerProc,可以取其他名字,但返回值類型、參數(shù)的類型和個(gè)數(shù)不能改變。
下面給出一個(gè)回調(diào)函數(shù)的例子:
C++代碼
void CALLBACK EXPORT TimerProc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime) { switch(nTimerid) { case 1: // 處理ID為1的定時(shí)器的事件 func1(); break; case 2: // 處理ID為2的定時(shí)器的事件 func2(); break; ...... default: break; } }
回調(diào)函數(shù)為全局函數(shù),需要寫在使用它的位置的前面,或者寫在后面然后在使用之前聲明。
3、銷毀定時(shí)器。
不再使用定時(shí)器時(shí),可以銷毀它。銷毀定時(shí)器需使用CWnd類的KillTimer成員函數(shù),CWnd::KillTimer函數(shù)的原型如下:
參數(shù)nIDEvent為要銷毀的定時(shí)器的ID,是調(diào)用CWnd::SetTimer函數(shù)時(shí)設(shè)置的定時(shí)器ID。如果定時(shí)器被銷毀則返回TRUE,而如果沒有找到指定的定時(shí)器則返回FALSE。
如果要銷毀多個(gè)定時(shí)器,則多次調(diào)用KillTimer函數(shù)并分別傳入要銷毀的定時(shí)器的ID。
通過Windows API函數(shù)使用定時(shí)器
如果我們不使用MFC定時(shí)器,而通過Windows API函數(shù)使用定時(shí)器,其實(shí)是很類似的。下面雞啄米簡(jiǎn)單說下步驟吧。
1、啟動(dòng)定時(shí)器。
使用API函數(shù)SetTimer啟動(dòng)定時(shí)器,SetTimer函數(shù)的原型如下:
C++代碼
INT_PTR SetTimer( HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc );
參數(shù)hWnd為與定時(shí)器關(guān)聯(lián)的窗口的句柄;參數(shù)nIDEvent為非零的定時(shí)器ID,如果hWnd等于NULL,且還不存在ID為nIDEvent的定時(shí)器,那么nIDEvent參數(shù)被忽略,然后生成一個(gè)新ID的定時(shí)器,而如果hWnd不為NULL,且hWnd指定的窗口已存在ID為nIDEvent的定時(shí)器,那么這個(gè)已存在的定時(shí)器被新定時(shí)器所取代。參數(shù)uElapse和lpTimerFunc同CWnd::SetTimer函數(shù)。
2、為WM_TIMER消息添加消息處理函數(shù),或者定義回調(diào)函數(shù)。
如果調(diào)用SetTimer函數(shù)時(shí)最后一個(gè)參數(shù)為NULL,我們需要自己為WM_TIMER消息添加處理函數(shù),要注意的是,WM_TIMER消息的附加數(shù)據(jù)wParam為定時(shí)器ID,lParam為回調(diào)函數(shù)的指針,如果調(diào)用SetTimer時(shí)回調(diào)函數(shù)為NULL,那么lParam也為NULL。
而如果調(diào)用SetTimer函數(shù)時(shí)最后一個(gè)參數(shù)不為NULL,我們就需要定義回調(diào)函數(shù)。回調(diào)函數(shù)的定義同MFC定時(shí)器。
3、銷毀定時(shí)器。
銷毀定時(shí)器使用KillTimer API函數(shù),原型如下:
參數(shù)hWnd為與定時(shí)器關(guān)聯(lián)的窗口的句柄,與啟動(dòng)定時(shí)器時(shí)SetTimer函數(shù)的hWnd參數(shù)值相同;參數(shù)uIDEvent為要銷毀的定時(shí)器的ID,如果傳遞給SetTimer的參數(shù)hWnd有效,則uIDEvent應(yīng)與傳遞給SetTimer的參數(shù)nIDEvent相同,而如果SetTimer的參數(shù)hWnd為NULL,則uIDEvent應(yīng)為SetTimer返回的定時(shí)器ID。該函數(shù)成功則返回TRUE,否則返回FALSE。
MFC定時(shí)器應(yīng)用實(shí)例
雞啄米給大家演示一個(gè)定時(shí)器的例子,該實(shí)例功能很簡(jiǎn)單,就是使用兩個(gè)定時(shí)器,定時(shí)更新兩個(gè)編輯框中的顯示內(nèi)容,第一個(gè)編輯框每秒刷新一次,從1刷新到10,然后銷毀定時(shí)器,第二個(gè)編輯框每?jī)擅胨⑿乱淮危瑥?刷新到5,然后銷毀定時(shí)器。下面簡(jiǎn)單說下步驟:
1、創(chuàng)建基于對(duì)話框的工程,名稱設(shè)為“Example44”。
2、在自動(dòng)生成的對(duì)話框模板IDD_EXAMPLE44_DIALOG中,刪除“TODO: Place dialog controls here.”靜態(tài)文本控件。添加兩個(gè)靜態(tài)文本框控件,Caption分別設(shè)為“1秒鐘刷新一次”和“2秒鐘刷新一次”,再添加兩個(gè)個(gè)Edit Control控件,ID使用默認(rèn)的IDC_EDIT1和IDC_EDIT2,兩者的Read Only屬性都設(shè)為True。此時(shí)的對(duì)話框模板如下圖:
3、為CExample44Dlg類添加兩個(gè)成員變量,分別為m_nData1、m_nData2,并在CExample44Dlg類的構(gòu)造函數(shù)中初始化:
C++代碼
CExample44Dlg::CExample44Dlg(CWnd* pParent /*=NULL*/) : CDialogEx(CExample44Dlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); // 兩個(gè)數(shù)據(jù)初始化為0 m_nData1 = 0; m_nData2 = 0; }
4、在對(duì)話框模板上雙擊OK按鈕,添加點(diǎn)擊消息的處理函數(shù),并修改如下:
C++代碼
void CExample44Dlg::OnBnClickedOk() { // TODO: Add your control notification handler code here // 啟動(dòng)ID為1的定時(shí)器,定時(shí)時(shí)間為1秒 SetTimer(1, 1000, NULL); // 啟動(dòng)ID為2的定時(shí)器,定時(shí)時(shí)間為2秒 SetTimer(2, 2000, NULL); //CDialogEx::OnOK(); }
這樣,點(diǎn)擊OK按鈕時(shí)就不會(huì)退出,而是啟動(dòng)兩個(gè)定時(shí)器。
5、根據(jù)上面MFC定時(shí)器講解中為WM_TIMER消息添加處理函數(shù)的方法,添加WM_TIMER的消息處理函數(shù)OnTimer,并修改其實(shí)現(xiàn)如下:
C++代碼
void CExample44Dlg::OnTimer(UINT_PTR nIDEvent) { // TODO: Add your message handler code here and/or call default switch (nIDEvent) { case 1: // 如果m_nData1已經(jīng)達(dá)到10,則銷毀ID為1的定時(shí)器 if (10 == m_nData1) { KillTimer(1); break; } // 刷新編輯框IDC_EDIT1的顯示 SetDlgItemInt(IDC_EDIT1, ++m_nData1); break; case 2: // 如果m_nData2已經(jīng)達(dá)到5,則銷毀ID為2的定時(shí)器 if (5 == m_nData2) { KillTimer(2); break; } // 刷新編輯框IDC_EDIT2的顯示 SetDlgItemInt(IDC_EDIT2, ++m_nData2); default: break; } CDialogEx::OnTimer(nIDEvent); }
6、運(yùn)行程序,點(diǎn)擊OK按鈕,查看效果。
關(guān)于定時(shí)器的內(nèi)容就講這些,相信了解了這些,一般的定時(shí)器應(yīng)用都能解決了。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自: