先看下MSDN對OnIdle()介紹:
CWinApp::OnIdle
OnIdle is called in the default message loop when the application's message queue is
empty. Use your override to call your own background idle-handler tasks.
對于一般桌面應用程序中比較少重載這個函數。對于像是視頻游戲這一塊確有不少用處。在Win32 SDK的開發(fā)環(huán)境中,通過在消息循環(huán)中添加自已的render()等接口來使自已的程序核心運轉起來,這也是常用的一種辦法。來到MFC的環(huán)境中,保證程序運轉的核心循環(huán)已經被整合到MFC中去了,這時侯要想將自已的接口函數可以合理的插進MFC的循環(huán)結構中,那么這個OnIdle()就是一個非常好的地方,在這兒你可以讓你的代碼獲的足夠的運行機會。先看看MSDN中對MFC的程序中Idle狀態(tài)的處理:
對CWinApp::OnIdle進行重載,返回非零值代表還有Idle Task任務要處理,這樣下次OnIdle()仍然會繼續(xù)執(zhí)行。在你重載CWinApp::OnIdle()時,不要忘記要先調用CWinApp::OnIdle()進行MFC默認處理:
1
2
|
if (CWinApp::OnIdle(lCount)) return TRUE; |
如果忘掉了的話,你會發(fā)現一些MFC的UI會出現問題,比如菜單上的選擇狀態(tài)無法更新等問題。
再下面加上你自已的處理函數即可:
1
2
|
YourMethod(); return TRUE; // 需要更多次的執(zhí)行。。。 |
對于MFC程序來講,很多是采用MFC的文檔視圖類的框架。比如如果你要讓視圖不斷刷新,在這個不斷刷新的視圖中可以完成場景渲灑更新等操作。你當然可以在 YourMethod()中獲取視圖的pView的指針,然后調用其內的接口函數, 就像這樣:
1
2
3
4
5
6
7
8
9
10
|
CMainFrame *parent = (CMainFrame *)AfxGetMainWnd(); if ( parent && parent->GetSafeHwnd() ) { CFrameWnd* pFrame = parent->GetActiveFrame(); CView *pView = pFrame->GetActiveView(); if ( pView ) { pView->Invalidate(); } } |
但這會明顯的讓你的程序和MFC的框架不那么配套,MFC的文檔視圖結構的設計思想并沒有體現出來。當然這樣做也沒什么錯。類似這樣的寫法也是可以正常工作的。
如果你查看過MFC文檔類CDocument的話,你會發(fā)現它也有一個虛函數叫OnIdle(),很明顯這個函數就是讓你完成文檔視圖在Idle時期的處理工作的地方。你完全在其中可以這樣寫:
1
2
3
4
5
6
7
|
POSITION pos = GetFirstViewPosition(); while ( pos != NULL ) { CView* pView = GetNextView( pos ); pView->Invalidate(); pView->UpdateWindow(); } |
通過在文檔的OnIdle中進行處理是更合適的地方。但是同樣需要在CWinApp::OnIdle重載函數中進行一些處理:
1
2
3
4
5
6
7
|
// In this example, as in most applications, you should let the // base class CWinApp::OnIdle complete its processing before you // attempt any additional idle loop processing. if ( CWinApp::OnIdle(lCount) ) return TRUE; CWinAppEx::OnIdle(0); return TRUE; |
你也許會問為什么要加上這句 CWinAppEx::OnIdle(0):加這句的目的其實我是希望調用MFC默認的對文檔視圖OnIdle的處理,也就是借用下面一段代碼:
1
2
3
4
5
6
7
8
9
10
11
|
// call doc-template idle hook POSITION pos = NULL; if ( m_pDocManager != NULL ) pos = m_pDocManager->GetFirstDocTemplatePosition(); while ( pos != NULL ) { CDocTemplate* pTemplate = m_pDocManager->GetNextDocTemplate(pos); ASSERT_KINDOF( CDocTemplate, pTemplate ); pTemplate->OnIdle(); } |
你完全可以用上面的代碼代替CWinAppEx::OnIdle(0)這句。
至此關于MFC中OnIdle的使用介紹已經完了。很多具體的東西還是需要深入MFC的具體實現當中去看。
CWinThread::Run是程序生命的"活水源頭"(侯捷:《深入淺出MFC》,函數存在于VC++ 6.0安裝目錄下提供的THRDCORE.CPP文件中):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
// main running routine until thread exits int CWinThread::Run() { ASSERT_VALID( this ); // for tracking the idle time state BOOL bIdle = TRUE; LONG lIdleCount = 0; // acquire and dispatch messages until a WM_QUIT message is received. for (;;) { // phase1: check to see if we can do idle work while (bIdle && !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)) { // call OnIdle while in bIdle state if (!OnIdle(lIdleCount++)) bIdle = FALSE; // assume "no idle" state } // phase2: pump messages while available do { // pump message, but quit on WM_QUIT if (!PumpMessage()) return ExitInstance(); // reset "no idle" state after pumping "normal" message if (IsIdleMessage(&m_msgCur)) { bIdle = TRUE; lIdleCount = 0; } } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); } ASSERT(FALSE); // not reachable } |
首先進行PeekMessage()未Peek到并且bIdle為True則進行OnIdle()并且lIdleCount++,完成之后返回一個值,如果要接收更多的空閑處理時間,則返回非零值,bIdle仍舊為true,繼續(xù)peek,若仍未peek到,則接著OnIdle,此時的lIdleCout為1,可根據這個值進行不同優(yōu)先級的任務設置,若peek到了則do,PumpMessage;如果不需要更多的空閑時間則返回0,bIdle為false,此時do第二個循環(huán),主要是lIdleCount置0然后接著peek,下次空閑的時候將重新進行OnIdle的任務。
OnIdle具體如下:
1
2
|
CWinApp::OnIdle virtual BOOL OnIdle( LONG lCount ); |
返回值:如果要接收更多的空閑處理時間,則返回非零值;如果不需要更多的空閑時間則返回0。
參數:
lCount |
該參數是一個計數值,當應用程序的消息隊列為空,OnIdle函數被調用時,該計數值就增加1。每當一條新消息被處理時,該計數值就被復位為0。你可以使用lCount參數來確定應用程序不處理消息時空閑時間的相對長度。 |
說明:
如果要執(zhí)行空閑時處理,則重載這個成員函數。當應用程序的消息隊列為空時,OnIdle就在缺省的消息循環(huán)中被調用。你可以用重載函數來調用自己的后臺空閑處理任務。
OnIdle應返回0以表明不需要更多的空閑處理時間。當消息隊列為空時,OnIdle每被調用一次lCount參數就增加,而每處理一條新消息lCount就被復位為0。你可以根據這個計數值調用不同的空閑處理例程。
下面總結了空閑循環(huán)處理:
1. |
如果微軟基礎類庫中的消息循環(huán)檢查消息隊列并發(fā)現沒有未被處理的消息,它就為應用程序對象調用OnIdle函數,并將lCount參數設為0。 |
2. |
OnIdle執(zhí)行一些處理,然后返回一個非零值,表示它還需要被調用,以進行進一步處理。 |
3. |
消息循環(huán)再次檢查消息隊列。如果沒有未處理的消息,則再次調用OnIdle,增加lCount參數。 |
4. |
最后,OnIdle結束所有的空閑任務并返回0。這就告訴消息循環(huán)停止調用OnIdle直到在消息隊列中接收到下一條消息為止,在那時,空閑循環(huán)將重新啟動,而參數被設為0。 |
因為只有在OnIdle返回之后應用程序才能處理用戶輸入,因此在OnIdle中不應進行較長的任務。
注意:
OnIdle的缺省實現更新命令用戶接口對象,如菜單項和工具條等,還實現了內部數據結構的清理。因此,如果你重載了OnIdle,你必須用重載版本中使用的lCount值來調用CWinApp::OnIdle。首先調用所有基類的空閑處理(即直到基類的OnIdle返回0)。如果你需要在基類處理完成之前進行一些工作,則應回顧基類的實現以在自己的工作期間選擇一個合適的lCount值。
示例:
下面的兩個例子演示了OnIdle的用法。
第一個例子處理兩個空閑任務,用lCount參數來排列這些任務的優(yōu)先權。第一個任務優(yōu)先權較高,一旦可能你就應當執(zhí)行此任務。第二個任務不十分重要,只有當用戶輸入有一個較長時間的間歇的時候才應執(zhí)行此任務。注意其中對基類的OnIdle的調用。第二個例子管理著一組具有不同優(yōu)先權的空閑任務。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
BOOL CMyApp::OnIdle( LONG lCount) { BOOL bMore = CWinApp::OnIdle(lCount); if (lCount == 0) { TRACE( "App idle for short period of time/n" ); bMore = TRUE; } else if (lCount == 10) { TRACE( "App idle for longer amount of time/n" ); bMore = TRUE; } else if (lCount == 100) { TRACE( "App idle for even longer amount of time/n" ); bMore = TRUE; } else if (lCount == 1000) { TRACE( "App idle for quite a long period of time/n" ); // bMore 沒有被設為TRUE, 不在需要空閑 // 重要:bMore 沒有被設為 FALSE,因為 CWinApp::OnIdle可能還有其它空閑任務要完成。 } return bMore; // 返回TRUE,只要還有其它空閑任務 } |
第二個示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
// 在這個例子中,有四個空閑循環(huán)任務,它們被賦予 // 不同的優(yōu)先權,運行的機會不同: // Task1在空閑時總能運行,要求在框架處理它自己的空閑循環(huán)任務時沒有消息在等候。(lCount為0或1) // Task2 僅當Task1以及運行時才能運行,要求當Task1運行時沒有消息在等候。 // Task3和Task4僅當Task1和Task2都運行之后才能運行, // 并且在此期間沒有消息在等候。如果Task3能夠運行, // 則Task4總是在Task3之后立即運行。 BOOL CMyApp::OnIdle( LONG lCount) { // 在這個例子中,像多數應用程序一樣,你應該讓基類 // 的CWinApp::OnIdle在你試圖進行任何附加的空閑循環(huán) // 過程之前完成它的處理。 if (CWinApp::OnIdle(lCount)) return TRUE; // 基類的CWinApp::OnIdle為lCount保留0和1給框架自己的 // 空閑處理使用。如果你希望與框架平等地共享空閑處理 // 時間,則應替換上面的if語句,直接調用CWinApp::OnIdle, // 然后為lCount的值0和/或1加入一個case語句。首先應當研 // 究基類的實現以理解你的空閑循環(huán)任務將會如何與框架的 // 空閑循環(huán)處理競爭。 switch (lCount) { case 2: Task1(); return TRUE; // 下一次給 Task2 一個機會 case 3: Task2(); return TRUE; // 下一次給Task3和Task4一個機會 case 4: Task3(); Task4(); return FALSE; // 再次回到空閑循環(huán)任務 } return FALSE; } |
到此這篇關于MFC框架之OnIdle案例詳解的文章就介紹到這了,更多相關MFC框架之OnIdle內容請搜索服務器之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://www.cnblogs.com/kex1n/archive/2012/03/02/2377621.html