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

所以解決方法有三個(gè)半:
1.用OnEraseBkGnd實(shí)現(xiàn),不要調(diào)用原來的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ù).(不過這種情況下,窗口覆蓋等造成的刷新還是要閃一
下,所以不是徹底的解決方法)
都挺簡單的.
------------------------------------------------------
在MFC中 任何一個(gè)window組件的繪圖 都是放在這兩個(gè)member function中
在設(shè)定上 OnEraseBkgnd()是用來畫底圖的 而OnPaint()是用來畫主要對象的
舉例說明 一個(gè)按鈕是灰色的 上面還有文字
則OnEraseBkgnd()所做的事就是把按鈕畫成灰色
而OnPaint()所做的事 就是畫上文字

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


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


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


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

// m_bmpBKGND 為一CBitmap對象 且事先早已加載我們的底圖
// 底圖的大小與我們的窗口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() 會把不該重畫的地方重畫

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

首先,tr0j4n是好心人,寫得這么長。但好像不對哦。

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

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

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

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