問(wèn)題是這樣產(chǎn)生的.在OnEraseBkGnd中,如果你不調(diào)用原來(lái)缺省
的OnEraseBkGnd只是重畫背景則不會(huì)有閃爍.而在OnPaint里面,
由于它隱含的調(diào)用了OnEraseBkGnd,而你又沒(méi)有處理OnEraseBkGnd
函數(shù),這時(shí)就和窗口缺省的背景刷相關(guān)了.缺省的
OnEraseBkGnd操作使用窗口的缺省背景刷刷新背景(一般情況
下是白刷),而隨后你又自己重畫背景造成屏幕閃動(dòng).
另外一個(gè)問(wèn)題是OnEraseBkGnd不是每次都會(huì)被調(diào)用的.如果你
調(diào)用Invalidate的時(shí)候參數(shù)為TRUE,那么在OnPaint里面隱含
調(diào)用BeginPaint的時(shí)候就產(chǎn)生WM_ERASEBKGND消息,如果參數(shù)
是FALSE,則不會(huì)重刷背景.

所以解決方法有三個(gè)半:
1.用OnEraseBkGnd實(shí)現(xiàn),不要調(diào)用原來(lái)的OnEraseBkGnd函數(shù).
2.用OnPaint實(shí)現(xiàn),同時(shí)重載OnEraseBkGnd,其中直接返回.
3.用OnPaint實(shí)現(xiàn),創(chuàng)建窗口時(shí)設(shè)置背景刷為空
4.用OnPaint實(shí)現(xiàn),但是要求刷新時(shí)用Invalidate(FALSE)這樣
的函數(shù).(不過(guò)這種情況下,窗口覆蓋等造成的刷新還是要閃一
下,所以不是徹底的解決方法)
都挺簡(jiǎn)單的.
------------------------------------------------------
在MFC中 任何一個(gè)window組件的繪圖 都是放在這兩個(gè)member function中
在設(shè)定上 OnEraseBkgnd()是用來(lái)畫底圖的 而OnPaint()是用來(lái)畫主要對(duì)象的
舉例說(shuō)明 一個(gè)按鈕是灰色的 上面還有文字
則OnEraseBkgnd()所做的事就是把按鈕畫成灰色
而OnPaint()所做的事 就是畫上文字

既然這兩個(gè)member function都是用來(lái)畫出組件的
那為何還要分OnPaint() 與 OnEraseBkgnd() 呢
其實(shí)OnPaint() 與 OnEraseBkgnd() 特性是有差的
1. OnEraseBkgnd()的要求是快速 在里面的繪圖程序最好是不要太耗時(shí)間
因?yàn)?每當(dāng)window組件有任何小變動(dòng) 都會(huì)馬上呼叫OnEraseBkgnd()
2. OnPaint() 是只有在程序有空閑的時(shí)候才會(huì)被呼叫
3. OnEraseBkgnd() 是在 OnPaint() 之前呼叫的
所以 OnPaint()被呼叫一次之前 可能會(huì)呼叫OnEraseBkgnd()好幾次


如果我們是一個(gè)在做圖形化使用者接口的人
常會(huì)需要把一張美美的圖片設(shè)為我們dialog的底圖
把繪圖的程序代碼放在OnPaint() 之中 可能會(huì)常碰到一些問(wèn)題
比方說(shuō)拖曳一個(gè)窗口在我們做的dialog上面一直移動(dòng)
則dialog會(huì)變成灰色 直到動(dòng)作停止才恢復(fù)
這是因?yàn)槊看涡枰乩L的時(shí)候 程序都會(huì)馬上呼叫OnEraseBkgnd()
OnEraseBkgnd()就把dialog畫成灰色
而只有動(dòng)作停止之后 程序才會(huì)呼叫OnPaint() 這時(shí)才會(huì)把我們要畫的底圖貼上去


這個(gè)問(wèn)題的解法 比較差點(diǎn)的方法是把OnEraseBkgnd() 改寫成不做事的function
如下所示
BOOL CMyDlg::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
以上本來(lái)是會(huì)呼叫CDialog::OnEraseBkgnd() 但是如果我們不呼叫的話
程序便不會(huì)畫上灰色的底色了


比較好的做法是直接將繪圖的程序從OnPaint()移到OnEraseBkgnd()來(lái)做
如下所示

// m_bmpBKGND 為一CBitmap對(duì)象 且事先早已加載我們的底圖
// 底圖的大小與我們的窗口client大小一致


BOOL CMyDlg::OnEraseBkgnd(CDC* pDC)
{
CRect rc;
GetUpdateRect(&rc);
CDC srcDC;
srcDC.CreateCompatibleDC(pDC);
srcDC.SelectObject(m_bmpBKGND);

pDC->BitBlt(rc.left,rc.top,rc.GetWidth(),
rc.GetHeight(),&srcDC,rc.left,rc.top,SRCCOPY);
return TRUE;
}

特別要注意的是 取得重畫大小是使用GetUpdateRect() 而不是GetClientRect()
如果使用GetClientRect() 會(huì)把不該重畫的地方重畫

另外不推薦使用GetUpdateRect(),很多情況下這個(gè)函數(shù)在OnEraseBkGnd里調(diào)用會(huì)有問(wèn)題,建議使用GetClipBox()

首先,tr0j4n是好心人,寫得這么長(zhǎng)。但好像不對(duì)哦。

應(yīng)該是這樣的吧,當(dāng)Windows確定客戶區(qū)需要重繪時(shí),它首先發(fā)送WM_ERASEBKGND消息給窗口過(guò)程,由WM_ERASEBKGND消息的默認(rèn)處理用白色畫刷刷除背景,然后再發(fā)送WM_PAINT消息給窗口過(guò)程,由WM_PAINT消息的響應(yīng)程序負(fù)責(zé)繪畫客戶區(qū)內(nèi)容。或者說(shuō),當(dāng)Windows確定客戶區(qū)需要重繪時(shí),它分別發(fā)送WM_ERASEBKGND和WM_PAINT消息,由這兩個(gè)消息的響應(yīng)程序分別負(fù)責(zé)刷除背景和重畫客戶內(nèi)容。

至閃爍的問(wèn)題,是由于刷除背景以后,在WM_PAINT未執(zhí)行完成之前,windows已把視頻卡的緩存輸出到屏幕上了。
 

如何擦除之前的背景圖片?

我明白問(wèn)題所在了,你的問(wèn)題是當(dāng)窗口大小變化時(shí),原來(lái)的背景沒(méi)有被清除,造成圖片重疊顯示,你上面的代碼沒(méi)有問(wèn)題,寫在OnEraseBkgnd()中還是寫在OnPaint()中的結(jié)果都是一樣的,最主要的原因是,當(dāng)我們改變窗口大小時(shí),觸發(fā)WM_SIZE消息,而默認(rèn)的OnSize在內(nèi)部調(diào)用Invalidate時(shí)用的參數(shù)是:Invalidate(FLASE);也就是不刷新背景的。所以原來(lái)的背景刷不掉
解決的方法是處理WM_SIZE,在OnSize()中,調(diào)用:Invalidate(TRUE);強(qiáng)制刷新背景就行了。