MFC框架之OnIdle案例詳解
先看下MSDN對(duì)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.
對(duì)于一般桌面應(yīng)用程序中比較少重載這個(gè)函數(shù)。對(duì)于像是視頻游戲這一塊確有不少用處。在Win32 SDK的開發(fā)環(huán)境中,通過(guò)在消息循環(huán)中添加自已的render()等接口來(lái)使自已的程序核心運(yùn)轉(zhuǎn)起來(lái),這也是常用的一種辦法。來(lái)到MFC的環(huán)境中,保證程序運(yùn)轉(zhuǎn)的核心循環(huán)已經(jīng)被整合到MFC中去了,這時(shí)侯要想將自已的接口函數(shù)可以合理的插進(jìn)MFC的循環(huán)結(jié)構(gòu)中,那么這個(gè)OnIdle()就是一個(gè)非常好的地方,在這兒你可以讓你的代碼獲的足夠的運(yùn)行機(jī)會(huì)。先看看MSDN中對(duì)MFC的程序中Idle狀態(tài)的處理:

對(duì)CWinApp::OnIdle進(jìn)行重載,返回非零值代表還有Idle Task任務(wù)要處理,這樣下次OnIdle()仍然會(huì)繼續(xù)執(zhí)行。在你重載CWinApp::OnIdle()時(shí),不要忘記要先調(diào)用CWinApp::OnIdle()進(jìn)行MFC默認(rèn)處理:
if (CWinApp::OnIdle(lCount))
return TRUE;
如果忘掉了的話,你會(huì)發(fā)現(xiàn)一些MFC的UI會(huì)出現(xiàn)問(wèn)題,比如菜單上的選擇狀態(tài)無(wú)法更新等問(wèn)題。
再下面加上你自已的處理函數(shù)即可:
YourMethod(); return TRUE; // 需要更多次的執(zhí)行。。。
對(duì)于MFC程序來(lái)講,很多是采用MFC的文檔視圖類的框架。比如如果你要讓視圖不斷刷新,在這個(gè)不斷刷新的視圖中可以完成場(chǎng)景渲灑更新等操作。你當(dāng)然可以在 YourMethod()中獲取視圖的pView的指針,然后調(diào)用其內(nèi)的接口函數(shù), 就像這樣:
CMainFrame *parent = (CMainFrame *)AfxGetMainWnd();
if ( parent && parent->GetSafeHwnd() )
{
CFrameWnd* pFrame = parent->GetActiveFrame();
CView *pView = pFrame->GetActiveView();
if ( pView )
{
pView->Invalidate();
}
}
但這會(huì)明顯的讓你的程序和MFC的框架不那么配套,MFC的文檔視圖結(jié)構(gòu)的設(shè)計(jì)思想并沒有體現(xiàn)出來(lái)。當(dāng)然這樣做也沒什么錯(cuò)。類似這樣的寫法也是可以正常工作的。
如果你查看過(guò)MFC文檔類CDocument的話,你會(huì)發(fā)現(xiàn)它也有一個(gè)虛函數(shù)叫OnIdle(),很明顯這個(gè)函數(shù)就是讓你完成文檔視圖在Idle時(shí)期的處理工作的地方。你完全在其中可以這樣寫:
POSITION pos = GetFirstViewPosition();
while ( pos != NULL )
{
CView* pView = GetNextView( pos );
pView->Invalidate();
pView->UpdateWindow();
}
通過(guò)在文檔的OnIdle中進(jìn)行處理是更合適的地方。但是同樣需要在CWinApp::OnIdle重載函數(shù)中進(jìn)行一些處理:
// 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;
你也許會(huì)問(wèn)為什么要加上這句 CWinAppEx::OnIdle(0):加這句的目的其實(shí)我是希望調(diào)用MFC默認(rèn)的對(duì)文檔視圖OnIdle的處理,也就是借用下面一段代碼:
// 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)這句。
至此關(guān)于MFC中OnIdle的使用介紹已經(jīng)完了。很多具體的東西還是需要深入MFC的具體實(shí)現(xiàn)當(dāng)中去看。
CWinThread::Run是程序生命的"活水源頭"(侯捷:《深入淺出MFC》,函數(shù)存在于VC++ 6.0安裝目錄下提供的THRDCORE.CPP文件中):
// 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
}
首先進(jìn)行PeekMessage()未Peek到并且bIdle為True則進(jìn)行OnIdle()并且lIdleCount++,完成之后返回一個(gè)值,如果要接收更多的空閑處理時(shí)間,則返回非零值,bIdle仍舊為true,繼續(xù)peek,若仍未peek到,則接著OnIdle,此時(shí)的lIdleCout為1,可根據(jù)這個(gè)值進(jìn)行不同優(yōu)先級(jí)的任務(wù)設(shè)置,若peek到了則do,PumpMessage;如果不需要更多的空閑時(shí)間則返回0,bIdle為false,此時(shí)do第二個(gè)循環(huán),主要是lIdleCount置0然后接著peek,下次空閑的時(shí)候?qū)⒅匦逻M(jìn)行OnIdle的任務(wù)。
OnIdle具體如下:
CWinApp::OnIdle virtual BOOL OnIdle( LONG lCount );
返回值:如果要接收更多的空閑處理時(shí)間,則返回非零值;如果不需要更多的空閑時(shí)間則返回0。
參數(shù):
|
lCount |
該參數(shù)是一個(gè)計(jì)數(shù)值,當(dāng)應(yīng)用程序的消息隊(duì)列為空,OnIdle函數(shù)被調(diào)用時(shí),該計(jì)數(shù)值就增加1。每當(dāng)一條新消息被處理時(shí),該計(jì)數(shù)值就被復(fù)位為0。你可以使用lCount參數(shù)來(lái)確定應(yīng)用程序不處理消息時(shí)空閑時(shí)間的相對(duì)長(zhǎng)度。 |
說(shuō)明:
如果要執(zhí)行空閑時(shí)處理,則重載這個(gè)成員函數(shù)。當(dāng)應(yīng)用程序的消息隊(duì)列為空時(shí),OnIdle就在缺省的消息循環(huán)中被調(diào)用。你可以用重載函數(shù)來(lái)調(diào)用自己的后臺(tái)空閑處理任務(wù)。
OnIdle應(yīng)返回0以表明不需要更多的空閑處理時(shí)間。當(dāng)消息隊(duì)列為空時(shí),OnIdle每被調(diào)用一次lCount參數(shù)就增加,而每處理一條新消息lCount就被復(fù)位為0。你可以根據(jù)這個(gè)計(jì)數(shù)值調(diào)用不同的空閑處理例程。
下面總結(jié)了空閑循環(huán)處理:
|
1. |
如果微軟基礎(chǔ)類庫(kù)中的消息循環(huán)檢查消息隊(duì)列并發(fā)現(xiàn)沒有未被處理的消息,它就為應(yīng)用程序?qū)ο笳{(diào)用OnIdle函數(shù),并將lCount參數(shù)設(shè)為0。 |
|
2. |
OnIdle執(zhí)行一些處理,然后返回一個(gè)非零值,表示它還需要被調(diào)用,以進(jìn)行進(jìn)一步處理。 |
|
3. |
消息循環(huán)再次檢查消息隊(duì)列。如果沒有未處理的消息,則再次調(diào)用OnIdle,增加lCount參數(shù)。 |
|
4. |
最后,OnIdle結(jié)束所有的空閑任務(wù)并返回0。這就告訴消息循環(huán)停止調(diào)用OnIdle直到在消息隊(duì)列中接收到下一條消息為止,在那時(shí),空閑循環(huán)將重新啟動(dòng),而參數(shù)被設(shè)為0。 |
因?yàn)橹挥性贠nIdle返回之后應(yīng)用程序才能處理用戶輸入,因此在OnIdle中不應(yīng)進(jìn)行較長(zhǎng)的任務(wù)。
注意:
OnIdle的缺省實(shí)現(xiàn)更新命令用戶接口對(duì)象,如菜單項(xiàng)和工具條等,還實(shí)現(xiàn)了內(nèi)部數(shù)據(jù)結(jié)構(gòu)的清理。因此,如果你重載了OnIdle,你必須用重載版本中使用的lCount值來(lái)調(diào)用CWinApp::OnIdle。首先調(diào)用所有基類的空閑處理(即直到基類的OnIdle返回0)。如果你需要在基類處理完成之前進(jìn)行一些工作,則應(yīng)回顧基類的實(shí)現(xiàn)以在自己的工作期間選擇一個(gè)合適的lCount值。
示例:
下面的兩個(gè)例子演示了OnIdle的用法。
第一個(gè)例子處理兩個(gè)空閑任務(wù),用lCount參數(shù)來(lái)排列這些任務(wù)的優(yōu)先權(quán)。第一個(gè)任務(wù)優(yōu)先權(quán)較高,一旦可能你就應(yīng)當(dāng)執(zhí)行此任務(wù)。第二個(gè)任務(wù)不十分重要,只有當(dāng)用戶輸入有一個(gè)較長(zhǎng)時(shí)間的間歇的時(shí)候才應(yīng)執(zhí)行此任務(wù)。注意其中對(duì)基類的OnIdle的調(diào)用。第二個(gè)例子管理著一組具有不同優(yōu)先權(quán)的空閑任務(wù)。
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 沒有被設(shè)為TRUE, 不在需要空閑
// 重要:bMore 沒有被設(shè)為 FALSE,因?yàn)?CWinApp::OnIdle可能還有其它空閑任務(wù)要完成。
}
return bMore; // 返回TRUE,只要還有其它空閑任務(wù)
}
第二個(gè)示例:
// 在這個(gè)例子中,有四個(gè)空閑循環(huán)任務(wù),它們被賦予
// 不同的優(yōu)先權(quán),運(yùn)行的機(jī)會(huì)不同:
// Task1在空閑時(shí)總能運(yùn)行,要求在框架處理它自己的空閑循環(huán)任務(wù)時(shí)沒有消息在等候。(lCount為0或1)
// Task2 僅當(dāng)Task1以及運(yùn)行時(shí)才能運(yùn)行,要求當(dāng)Task1運(yùn)行時(shí)沒有消息在等候。
// Task3和Task4僅當(dāng)Task1和Task2都運(yùn)行之后才能運(yùn)行,
// 并且在此期間沒有消息在等候。如果Task3能夠運(yùn)行,
// 則Task4總是在Task3之后立即運(yùn)行。
BOOL CMyApp::OnIdle(LONG lCount)
{
// 在這個(gè)例子中,像多數(shù)應(yīng)用程序一樣,你應(yīng)該讓基類
// 的CWinApp::OnIdle在你試圖進(jìn)行任何附加的空閑循環(huán)
// 過(guò)程之前完成它的處理。
if (CWinApp::OnIdle(lCount)) return TRUE;
// 基類的CWinApp::OnIdle為lCount保留0和1給框架自己的
// 空閑處理使用。如果你希望與框架平等地共享空閑處理
// 時(shí)間,則應(yīng)替換上面的if語(yǔ)句,直接調(diào)用CWinApp::OnIdle,
// 然后為lCount的值0和/或1加入一個(gè)case語(yǔ)句。首先應(yīng)當(dāng)研
// 究基類的實(shí)現(xiàn)以理解你的空閑循環(huán)任務(wù)將會(huì)如何與框架的
// 空閑循環(huán)處理競(jìng)爭(zhēng)。
switch (lCount)
{
case 2:
Task1();
return TRUE; // 下一次給 Task2 一個(gè)機(jī)會(huì)
case 3:
Task2();
return TRUE; // 下一次給Task3和Task4一個(gè)機(jī)會(huì)
case 4:
Task3();
Task4();
return FALSE; // 再次回到空閑循環(huán)任務(wù)
}
return FALSE;
}
到此這篇關(guān)于MFC框架之OnIdle案例詳解的文章就介紹到這了,更多相關(guān)MFC框架之OnIdle內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談C++/C關(guān)于#define的那些奇奇怪怪的用法
本文主要介紹了C++/C關(guān)于#define的那些奇奇怪怪的用法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
VC++文件監(jiān)控之FindFirstChangeNotification
因?yàn)镽eadDirectoryChangesW 上次測(cè)試發(fā)現(xiàn)不能多級(jí)目錄監(jiān)控,所以嘗試用FindFirstChangeNotification來(lái)實(shí)施文件監(jiān)控,需要的朋友可以參考下2019-04-04
C語(yǔ)言實(shí)現(xiàn)自定義掃雷游戲(遞歸版)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)自定義掃雷游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
Qt實(shí)現(xiàn)SqlRelationalTable關(guān)聯(lián)表組件
在Qt中我們可以通過(guò)拖拽的方式將不同組件放到指定的位置,實(shí)現(xiàn)圖形化開發(fā)極大的方便了開發(fā)效率,本章將重點(diǎn)介紹SqlRelationalTable關(guān)聯(lián)表組件的常用方法及靈活運(yùn)用,感興趣的可以了解一下2023-12-12
Qt使用QJson模塊實(shí)現(xiàn)解析Json文件
在項(xiàng)目開發(fā)過(guò)程中,經(jīng)常會(huì)遇到讀寫Json文件的需求,掌握J(rèn)son文件的操作是基礎(chǔ)中的基礎(chǔ),下面我們就來(lái)看看如何使用QT內(nèi)置的QJson模塊解析Json文件吧2023-10-10

