OnEraseBkGnd與OnPaint的聯繫是什麼? 轉自:http://www.cppblog.com/Walker/articles/144098.html

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

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

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


如果我們是一個在做圖形化使用者接口的人
常會需要把一張美美的圖片設爲我們dialog的底圖
把繪圖的程序代碼放在OnPaint() 之中 可能會常碰到一些問題
比方說拖曳一個窗口在我們做的dialog上面一直移動
則dialog會變成灰色 直到動作停止才恢復
這是因爲每次需要重繪的時候 程序都會馬上呼叫OnEraseBkgnd()
OnEraseBkgnd()就把dialog畫成灰色
而只有動作停止之後 程序纔會呼叫OnPaint() 這時纔會把我們要畫的底圖貼上去


這個問題的解法 比較差點的方法是把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(),很多情況下這個函數在OnEraseBkGnd裏調用會有問題,建議使用GetClipBox()

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

應該是這樣的吧,當Windows確定客戶區需要重繪時,它首先發送WM_ERASEBKGND消息給窗口過程,由WM_ERASEBKGND消息的默認處理用白色畫刷刷除背景,然後再發送WM_PAINT消息給窗口過程,由WM_PAINT消息的響應程序負責繪畫客戶區內容。或者說,當Windows確定客戶區需要重繪時,它分別發送WM_ERASEBKGND和WM_PAINT消息,由這兩個消息的響應程序分別負責刷除背景和重畫客戶內容。

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

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

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

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章