天天看點

CWnd::OnPaint & CView::OnDraw

CWnd::OnPaint 

afx_msg void OnPaint( );

Remarks

The framework calls this member function when Windows or an application makes a request to repaint a portion of an application’s window. The

WM_PAINT message is sent when the UpdateWindow or RedrawWindow member function is called.

CView::OnDraw

virtual void OnDraw( CDC* pDC ) = 0;

Called by the framework to render an p_w_picpath of the document.

The framework calls this function to perform screen display, printing, and print preview, and it passes a different device context in each case. There is no default implementation.

You must override this function to display your view of the document.

If you need to distinguish between normal screen display and printing, call the IsPrinting member function of the device context.

差別已經很明顯。OnPaint()是CWnd的成員函數,所有CWnd的子類都有一份OnPaint,而OnDraw()則是CView類中聲明的純虛函數。OnPaint()響應WM_PAINT消息,OnDraw不響應任何消息,隻是一個虛函數。CWnd的子類分為四大類:FrameWindows, Dialog Boxes, Views, Controls,是以除了View及其子類使用OnDraw()外,其餘三類都使用OnPaint()來重畫。OnPaint()的工作是'Screen Display',而OnDraw()則可以做'Screen display, printing, print preview'等工作。

再看MFC源代碼中如何做:

void CView::OnPaint()

{

    // standard paint routine

    CPaintDC dc(this);

    OnPrepareDC(&dc);

    OnDraw(&dc);

}

OnPaint()是CWnd類的非虛函數,CView中重載了該函數。從代碼中可以看出,在CView響應WM_PAINT消息的情況下,在OnPaint中先調用了OnPrepareDC(),然後調用了OnDraw()。查MSDN,可以看到,

OnPrepareDC()的作用是:framework中在OnDraw()之前調用它,或者在OnPrint中調用它,前者是為了準備螢幕顯示,後者是為了列印。MFC中OnPrepareDC的源代碼是:

void CView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)

    ASSERT_VALID(pDC);

    UNUSED(pDC); // unused in release builds

    // Default to one page printing if doc length not known

    if (pInfo != NULL)

        pInfo->m_bContinuePrinting =

            (pInfo->GetMaxPage() != 0xffff || (pInfo->m_nCurPage == 1));

這是CView中的定義,OnPrepareDC()是一個虛函數。完全可以改寫它。在CView各子類中該函數的定義都不一樣。

OnDraw()和OnPaint()

2007-10-31 09:16

OnDraw()和OnPaint()兄弟

經常有朋友問這樣的問題:

我在視圖畫的圖象或者文字,當視窗改變後為什麼不見了?

OnDraw()和OnPaint()兩個都是解決上面的問題,有什麼不同?

OnDraw()和OnPaint()好象兄弟倆,因為它們的工作類似。

至于不見了的問題簡單,因為當你的視窗改變後,會産生無效區域,這個無效的區域需要重畫。一般Windows回發送兩個消息WM_PAINT(通知客戶區有變化)和WM_NCPAINT(通知非客戶區有變化)。非客戶區的重畫系統自己搞定了,而客戶區的重畫需要我們自己來完成。這就需要OnDraw()或OnPaint()來重畫視窗。

OnDraw()和OnPaint()有什麼差別呢?

首先:

我們先要明确CView類派生自CWnd類。而OnPaint()是CWnd的類成員,同時負責響應WM_PAINT消息。OnDraw()是CVIEW的成員函數,并且沒有響應消息的功能。這就是為什麼你用VC成的程式代碼時,在視圖類隻有OnDraw沒有OnPaint的原因。

其次:

我們在第《每天跟我學MFC》3的開始部分已經說到了。要想在螢幕上繪圖或顯示圖形,首先需要建立裝置環境DC。其實DC是一個資料結構,它包含輸出裝置(不單指你17寸的純屏顯示器,還包括列印機之類的輸出裝置)的繪圖屬性的描述。MFC提供了CPaintDC類和CWindwoDC類來實時的響應,而CPaintDC支援重畫。

當視圖變得無效時(包括大小的改變,移動,被遮蓋等等),Windows 将 WM_PAINT 消息發送給它。該視圖的 OnPaint 處理函數通過建立 CPaintDC 類的DC對象來響應該消息并調用視圖的 OnDraw 成員函數。通常我們不必編寫重寫的 OnPaint 處理成員函數。

///CView預設的标準的重畫函數

     CPaintDC dc(this);

     OnPreparDC(&dc);

     OnDraw(&dc); //調用了OnDraw

既然OnPaint最後也要調用OnDraw,是以我們一般會在OnDraw函數中進行繪制。下面是一個典型的程式

///視圖中的繪圖代碼首先檢索指向文檔的指針,然後通過DC進行繪圖調用。

void CMyView::OnDraw( CDC* pDC )

     CMyDoc* pDoc = GetDocument();

     CString s = pDoc->GetData();    // Returns a CString

     CRect rect;

     GetClientRect( &rect );

     pDC->SetTextAlign( TA_baseLINE | TA_CENTER );

     pDC->TextOut( rect.right / 2, rect.bottom / 2,

                   s, s.GetLength() );

最後:

現在大家明白這哥倆之間的關系了吧。是以我們一般用OnPaint維護視窗的客戶區(例如我們的視窗客戶區加一個背景圖檔),用OnDraw維護視圖的客戶區(例如我們通過滑鼠在視圖中畫圖)。當然你也可以不按照上面規律來,隻要達到目的并且沒有問題,怎麼幹都成。

補充:

我們還可以利用Invalidate(),ValidateRgn(),ValidateRect()函數強制的重畫視窗,具體的請參考MSDN吧。

Onpaint和OnDraw的差別[轉]

OnPaint是WM_PAINT消息的消息處理函數,在OnPaint中調用OnDraw,一般來說,使用者自己的繪圖代碼應放在OnDraw中。

OnPaint()是CWnd的類成員,負責響應WM_PAINT消息。OnDraw()是CVIEW的成員函數,沒有響應消息的功能.當視圖變得無效時(包括大小的改變,移動,被遮蓋等等),Windows發送WM_PAINT消息。該視圖的OnPaint 處理函數通過建立CPaintDC類的DC對象來響應該消息并調用視圖的OnDraw成員函數.OnPaint最後也要調用OnDraw,是以一般在OnDraw函數中進行繪制。

The WM_PAINT message is sent when the UpdateWindow or RedrawWindow member function is called.

在OnPaint中,将調用BeginPaint,用來獲得客戶區的顯示裝置環境,并以此調用GDI函數執行繪圖操作。在繪圖操作完成後,将調用EndPaint以釋放顯示裝置環境。而OnDraw在BeginPaint與EndPaint間被調用。

1) 在mfc結構裡OnPaint是CWnd的成員函數. OnDraw是CView的成員函數.

2) OnPaint()調用OnDraw(),OnPrint也會調用OnDraw(),是以OnDraw()是顯示和列印的共同操作。

OnPaint是WM_PAINT消息引發的重繪消息處理函數,在OnPaint中會調用OnDraw來進行繪圖。OnPaint中首先構造一個CPaintDC類得執行個體,然後一這個執行個體為參數來調用虛函數OnPrepareDC來進行一些繪制前的一些處理,比設定映射模式,最後調用OnDraw。而OnDraw和OnPrepareDC不是消息處理函數。是以在不是因為重繪消息所引發的OnPaint導緻OnDraw被調用時,比如在OnLButtonDown等消息處理函數中繪圖時,要先自己調用OnPrepareDC。

至于CPaintDC和CClientDC根本是兩回事情 CPaintDC是一個裝置環境類,在OnPaint中作為參數傳遞給OnPrepareDC來作裝置環境的設定。真正和CClientDC具有可比性的是CWindowDC,他們一個是描述客戶區域,一個是描述整個螢幕。

如果是對CVIEW或從CVIEW類派生的視窗繪圖時應該用OnDraw。

繼續閱讀