天天看点

【VC++ MFC】OnDraw()和OnPaint()

1、

OnPaint()是消息响应函数,默认是WM_PAINT消息的入口.

OnDraw()是虚函数,是被OnPaint( )调用的函数   

OnPaint( )优先于OnDraw( ),如果重载了OnPaint( ),则不会影响OnDraw( ).如果需要,則需明确调用OnDraw( )函数.

    当你的窗口改变后,会产生无效区域,这个无效的区域需要重画。一般Windows回发送两个消息WM_PAINT(通知客户区有变化)和WM_NCPAINT(通知非客户区有变化)。非客户区的重画系统自己搞定了,而客户区的重画需要我们自己来完成。这就需要OnDraw()或OnPaint()来重画窗口。

OnDraw()和OnPaint()的区别:

CView类派生自CWnd类,而OnPaint()是CWnd的类成员,同时负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函数,并且没有响应消息的功能(所以一般都是由OnPaint()调用OnDraw()?)。

当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows 将 WM_PAINT 消息发送给它。该视图的 OnPaint处理函数通过创建 CPaintDC 类的DC对象来响应该消息并调用视图的 OnDraw 成员函数。通常我们不必编写重写的 OnPaint处理成员函数。

///CView默认的标准的重画函数

void CView::OnPaint()

{

    CPaintDC dc(this);

    OnPreparDC(&dc);

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

}

///

  在MFC程序设计中,按照传统的设计,如果处理WM_PAINT消息,一般会派生一个OnPaint函数,映射到WM_PAINT消息上进行绘图处理。但是很多程序中并没有出现OnPaint,一个OnDraw函数做了更多的绘图操作。而在消息映射的列表中,也没有见到WM_PAINT到OnDraw的映射。

  实际上,OnDraw不是OnPaint的映射,出现OnDraw,是为了实现各种不同的设备上的绘图一致性。

首先,读者需要明白的是,WM_PAINT消息是为了绘制屏幕而出现的,因此,在OnPaint中,我们只能存取屏幕DC,进行绘制,常见的代码是:

void MyWnd::OnPaint()

       CPaintDC dc(this);

     //draw code here

  这里的CPaintDC的构造函数会自动调用BeginPaint,获得一个屏幕DC,并附加在dc对象上。当dc对象析构时,系统自动调用EndPaint并使invalidatedrectangle变成validated状态,从而结束绘制。(注意,重复创建CPaintDC实例会失败也因为如此)

  如果我们在OnPaint中绘制,那么在打印机上绘制我们就需要再写一个OnPrint函数,重新绘制。这样,程序设计者就需要维护两套代码。为了简化操作,MFC框架把大部分绘制操作都放在OnDraw中,OnPaint和OnPrint只构造相应的DC,然后分别调用OnDraw.也就是说,OnDraw适用于所有的设备,而OnPaint只适用于屏幕。

  大家在设计过程中必须注意:OnDraw是被基类的OnPaint主动调用的,如果你继承了

OnPaint,你应该要么调用基类的OnPaint(此前不得创建CPaintDC实例,也不得调用BeginPaint),要么1\自己创建CPaintDC实例,2\并调用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());

补充:我们还可以利用Invalidate(),ValidateRgn(),ValidateRect()函数强制的重画窗口

继续阅读