問(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)制刷新背景就行了。