OnPaint是對這個(gè)消息的反應函數
mfc 的 CWnd::OnPaint 沒(méi)做什么,只是丟給系統處理。
一 :
OnEraseBkGnd與OnPaint的區別與聯(lián)系
在OnEraseBkGnd中,如果你不調用原來(lái)缺省的OnEraseBkGnd只是重畫(huà)背景則不會(huì )有閃爍.而在OnPaint里面,由于它隱含的調用了OnEraseBkGnd,而你又沒(méi)有處理OnEraseBkGnd 函數,這時(shí)就和窗口缺省的背景刷相關(guān)了.缺省的 OnEraseBkGnd操作使用窗口的缺省背景刷刷新背景(一般情況下是白刷),而隨后你又自己重畫(huà)背景造成屏幕閃動(dòng).
OnEraseBkGnd不是每次都會(huì )被調用的.如果你調用Invalidate的時(shí)候參數為T(mén)RUE,那么在OnPaint里面隱含調用BeginPaint的時(shí)候就產(chǎn)生WM_ERASEBKGND消息,如果參數是FALSE,則不會(huì )重刷背景.
ZYP解釋?zhuān)?/strong>void Invalidate( BOOL bErase = TRUE ); 該函數的作用是使整個(gè)窗口客戶(hù)區無(wú)效。窗口的客戶(hù)區無(wú)效意味著(zhù)需要重繪,參數bErase為T(mén)RUE時(shí),重繪區域內的背景將被重繪即擦除,否則,背景將保持不變。調用Invalidate等函數后窗口不會(huì )立即重繪,這是由于WM_PAINT消息的優(yōu)先級很低,它需要等消息隊列中的其它消息發(fā)送完后才能被處理。
OnPaint里面會(huì )調用BeginPaint函數自動(dòng)設置顯示設備內容的剪切區域而排除任何更新區域外的區域更新區域。如果更新區域被標記為可擦除的,BeginPaint發(fā)送一個(gè)WM_ERASEBKGND消息給窗口。WM_ERASEBKGND消息的響應函數既是OnEraseBkGnd()
所以解決方法有三個(gè)半:
1.用OnEraseBkGnd實(shí)現,不要調用原來(lái)的OnEraseBkGnd函數.
2.用OnPaint實(shí)現,同時(shí)重載OnEraseBkGnd,其中直接返回.
3.用OnPaint實(shí)現,創(chuàng )建窗口時(shí)設置背景刷為空
4.用OnPaint實(shí)現,但是要求刷新時(shí)用Invalidate(FALSE)這樣
的函數.(不過(guò)這種情況下,窗口覆蓋等造成的刷新還是要閃一
下,所以不是徹底的解決方法)
都挺簡(jiǎn)單的.
在MFC中 任何一個(gè)window元件的繪圖 都是放在這兩個(gè)member function中
在設定上 OnEraseBkgnd()是用來(lái)畫(huà)底圖的 而OnPaint()是用來(lái)畫(huà)主要物件的
舉例說(shuō)明 一個(gè)按鈕是灰色的 上面還有文字
則OnEraseBkgnd()所做的事就是把按鈕畫(huà)成灰色
而OnPaint()所做的事 就是畫(huà)上文字
既然這兩個(gè)member function都是用來(lái)畫(huà)出元件的
那為何還要分OnPaint() 與 OnEraseBkgnd() 呢
其實(shí)OnPaint() 與 OnEraseBkgnd() 特性是有差的
1.
2.
3.
所以 OnPaint()被呼叫一次之前 可能會(huì )呼叫OnEraseBkgnd()好幾次
如果我們是一個(gè)在做圖形化使用者介面的人
常會(huì )需要把一張美美的圖片設為我們dialog的底圖
把繪圖的程式碼放在OnPaint() 之中 可能會(huì )常碰到一些問(wèn)題
比方說(shuō)拖曳一個(gè)視窗在我們做的dialog上面一直移動(dòng)
則dialog會(huì )變成灰色 直到動(dòng)作停止才恢復
這是因為每次需要重繪的時(shí)候 程式都會(huì )馬上呼叫OnEraseBkgnd()
OnEraseBkgnd()就把dialog畫(huà)成灰色
而只有動(dòng)作停止之後 程式才會(huì )呼叫OnPaint() 這時(shí)才會(huì )把我們要畫(huà)的底圖貼上去
這個(gè)問(wèn)題的解法 比較差點(diǎn)的方法是把OnEraseBkgnd() 改寫(xiě)成不做事的function
如下所示







以上本來(lái)是會(huì )呼叫CDialog::OnEraseBkgnd() 但是如果我們不呼叫的話(huà)
程式便不會(huì )畫(huà)上灰色的底色了
Q:基于對話(huà)框的程序中如何重載OnEraseBkGnd()函數
A:這是一個(gè)消息WM_ERASEBKWND
比較好的做法是直接將繪圖的程式從OnPaint()移到OnEraseBkgnd()來(lái)做
如下所示


















二 :
MFC中OnDraw與OnPaint的區別
在OnPaint中調用OnDraw,一般來(lái)說(shuō),用戶(hù)自己的繪圖代碼應放在OnDraw中。
OnPaint()是CWnd的類(lèi)成員,負責響應WM_PAINT消息。OnDraw()是CVIEW的成員函數,沒(méi)有響應消息的功能.當視圖變得無(wú)效時(shí)(包括大小的改變,移動(dòng),被遮蓋等等),Windows發(fā)送WM_PAINT消息。該視圖的OnPaint 處理函數通過(guò)創(chuàng )建CPaintDC類(lèi)的DC對象來(lái)響應該消息并調用視圖的OnDraw成員函數.OnPaint最后也要調用OnDraw,因此一般在OnDraw函數中進(jìn)行繪制。
The WM_PAINT message is sent when the UpdateWindow or RedrawWindow member function is called.
在OnPaint中,將調用BeginPaint,用來(lái)獲得客戶(hù)區的顯示設備環(huán)境,并以此調用GDI函數執行繪圖操作。在繪圖操作完成后,將調用EndPaint以釋放顯示設備環(huán)境。而OnDraw在BeginPaint與EndPaint間被調用。(一個(gè)應用程序除了響應WM_PAINT消息外,不應該調用BeginPaint。每次調用BeginPaint都應該有相應的EndPaint函數。)
1) 在mfc結構里OnPaint是CWnd的成員函數. OnDraw是CView的成員函數.
2) OnPaint()調用OnDraw(),OnPrint也會(huì )調用OnDraw(),所以OnDraw()是顯示和打印的共同操作。
OnPaint是WM_PAINT消息引發(fā)的重繪消息處理函數,在OnPaint中會(huì )調用OnDraw來(lái)進(jìn)行繪圖。OnPaint中首先構造一個(gè)CPaintDC類(lèi)得實(shí)例,然后一這個(gè)實(shí)例為參數來(lái)調用虛函數OnPrepareDC來(lái)進(jìn)行一些繪制前的一些處理,比設置映射模式,最后調用OnDraw。而OnDraw和OnPrepareDC不是消息處理函數。所以在不是因為重繪消息所引發(fā)的OnPaint導致OnDraw被調用時(shí),比如在OnLButtonDown等消息處理函數中繪圖時(shí),要先自己調用OnPrepareDC。
至于CPaintDC和CClientDC根本是兩回事情 CPaintDC是一個(gè)設備環(huán)境類(lèi),在OnPaint中作為參數傳遞給OnPrepareDC來(lái)作設備環(huán)境的設置。真正和CClientDC具有可比性的是CWindowDC,他們一個(gè)是描述客戶(hù)區域,一個(gè)是描述整個(gè)屏幕。
如果是對CVIEW或從CVIEW類(lèi)派生的窗口繪圖時(shí)應該用OnDraw。
OnDraw()和OnPaint()有什么區別呢?
首先:我們先要明確CView類(lèi)派生自CWnd類(lèi)。而OnPaint()是CWnd的類(lèi)成員,同時(shí)負責響應WM_PAINT消息。OnDraw()是CVIEW的成員函數,并且沒(méi)有響應消息的功能。這就是為什么你用VC成的程序代碼時(shí),在視圖類(lèi)只有OnDraw沒(méi)有OnPaint的原因。而在基于對話(huà)框的程序中,只有OnPaint。
其次:我們在第《每天跟我學(xué)MFC》3的開(kāi)始部分已經(jīng)說(shuō)到了。要想在屏幕上繪圖或顯示圖形,首先需要建立設備環(huán)境DC。其實(shí)DC是一個(gè)數據結構,它包含輸出設備(不單指你17寸的純屏顯示器,還包括打印機之類(lèi)的輸出設備)的繪圖屬性的描述。MFC提供了CPaintDC類(lèi)和CWindwoDC類(lèi)來(lái)實(shí)時(shí)的響應,而CPaintDC支持重畫(huà)。當視圖變得無(wú)效時(shí)(包括大小的改變,移動(dòng),被遮蓋等等),Windows 將 WM_PAINT 消息發(fā)送給它。該視圖的OnPaint 處理函數通過(guò)創(chuàng )建 CPaintDC 類(lèi)的DC對象來(lái)響應該消息并調用視圖的 OnDraw 成員函數。通常我們不必編寫(xiě)重寫(xiě)的 OnPaint 處理成員函數。





































OnDraw中可以繪制用戶(hù)區域。OnPaint中只是當窗口無(wú)效時(shí)重繪不會(huì )保留CClientDC繪制的內容。
這兩個(gè)函數有區別也有聯(lián)系:
1、區別:OnDraw是一個(gè)純虛函數,定義為virtual void OnDraw( CDC* pDC ) = 0; 而OnPaint是一個(gè)消息響應函數,它響應了WM_PANIT消息,也是是窗口重繪消息。
2、聯(lián)系:我們一般在視類(lèi)中作圖的時(shí)候,往往不直接響應WM_PANIT消息,而是重載OnDraw純虛函數,這是因為在CVIEW類(lèi)中的WM_PANIT消息響應函數中調用了OnDraw函數,如果在CMYVIEW類(lèi)中響應了WM_PAINT消息,不顯式地調用OnDraw函數的話(huà),是不會(huì )在窗口重繪的時(shí)候調用OnDraw函數的。
應用程序中幾乎所有的繪圖都在視圖的 OnDraw 成員函數中發(fā)生,必須在視圖類(lèi)中重寫(xiě)該成員函數。(鼠標繪圖是個(gè)特例,這在通過(guò)視圖解釋用戶(hù)輸入中討論。)
OnDraw 重寫(xiě):
通過(guò)調用您提供的文檔成員函數獲取數據。
通過(guò)調用框架傳遞給 OnDraw 的設備上下文對象的成員函數來(lái)顯示數據。
當文檔的數據以某種方式更改后,必須重繪視圖以反映該更改。默認的 OnUpdate 實(shí)現使視圖的整個(gè)工作區無(wú)效。當視圖變得無(wú)效時(shí),Windows 將 WM_PAINT 消息發(fā)送給它。該視圖的 OnPaint 處理函數通過(guò)創(chuàng )建 CPaintDC 類(lèi)的設備上下文對象來(lái)響應該消息并調用視圖的 OnDraw 成員函數。
當沒(méi)有添加WM_PAINT消息處理時(shí),窗口重繪時(shí),由OnDraw來(lái)進(jìn)行消息響應...當添加WM_PAINT消息處理時(shí),窗口重繪時(shí),WM_PAINT消息被投遞,由OnPaint來(lái)進(jìn)行消息響應.這時(shí)就不能隱式調用OnDraw了.必須顯式調用(
隱式調用:當由OnPaint來(lái)進(jìn)行消息響應時(shí),系統自動(dòng)調用CView::OnDraw(&pDC).
想象一下,窗口顯示的內容和打印的內容是差不多的,所以,一般情況下,統一由OnDraw來(lái)畫(huà)。窗口前景需要刷新時(shí),系統會(huì )會(huì )調用到OnPaint,而OnPaint一般情況下是對DC作一些初始化操作后,調用OnDraw()。
OnEraseBkGnd(),是窗口背景需要刷新時(shí)由系統調用的。明顯的一個(gè)例子是設置窗口的背景顏色(你可以把這放在OnPaint中去做,但是會(huì )使產(chǎn)生閃爍的現象)。
至于怎么界定背景和前景,那要具體問(wèn)題具體分析了,一般情況下,你還是很容易區別的吧。
的確,OnPaint()用來(lái)響應WM_PAINT消息,視類(lèi)的OnPaint()內部根據是打印還是屏幕繪制分別以不同的參數調用OnDraw()虛函數。所以在OnDraw()里你可以區別對待打印和屏幕繪制。
其實(shí),MFC在進(jìn)行打印前后還做了很多工作,調用了很多虛函數,比如OnPreparePrint()等。
另外OnInitialUpdate
視圖窗口完全建立后第一個(gè)被框架調用的函數??蚣茉诘谝淮握{用OnDraw前會(huì )調用OnInitialUpdate,因此OnInitialUpdate是設置滾動(dòng)視圖的邏輯尺寸和映射模式的最合適的地方。
聯(lián)系客服