MFC中OnPaint和OnDraw的区别

MFCOnDrawOnPaint的区别 
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 UpdateWindowor RedrawWindow member function is called.
 

OnPaint中,将调用BeginPaint,用来获得客户区的显示设备环境,并以此调用GDI函数执行绘图操作。在绘图操作完成后,将调用EndPaint以释放显示设备环境。而OnDrawBeginPaintEndPaint间被调用。 

1)
mfc结构里OnPaintCWnd的成员函数.OnDrawCView的成员函数. 
2) OnPaint()
调用OnDraw()OnPrint也会调用OnDraw(),所以OnDraw()是显示和打印的共同操作。 

OnPaint
WM_PAINT消息引发的重绘消息处理函数,在OnPaint中会调用OnDraw来进行绘图。OnPaint中首先构造一个CPaintDC类得实例,然后一这个实例为参数来调用虚函数OnPrepareDC来进行一些绘制前的一些处理,比设置映射模式,最后调用OnDraw。而OnDrawOnPrepareDC不是消息处理函数。所以在不是因为重绘消息所引发的OnPaint导致OnDraw被调用时,比如在OnLButtonDown等消息处理函数中绘图时,要先自己调用OnPrepareDC 
至于CPaintDCCClientDC根本是两回事情 CPaintDC是一个设备环境类,在OnPaint中作为参数传递给OnPrepareDC来作设备环境的设置。真正和CClientDC具有可比性的是CWindowDC,他们一个是描述客户区域,一个是描述整个屏幕。 
如果是对CVIEW或从CVIEW类派生的窗口绘图时应该用OnDraw 

OnDraw()
OnPaint()有什么区别呢? 
首先:我们先要明确CView类派生自CWnd类。而OnPaint()CWnd的类成员,同时负责响应WM_PAINT消息。OnDraw()CVIEW的成员函数,并且没有响应消息的功能。这就是为什么你用VC成的程序代码时,在视图类只有OnDraw没有OnPaint的原因。而在基于对话框的程序中,只有OnPaint 
其次:我们在第《每天跟我学MFC3的开始部分已经说到了。要想在屏幕上绘图或显示图形,首先需要建立设备环境DC。其实DC是一个数据结构,它包含输出设备(不单指你17寸的纯屏显示器,还包括打印机之类的输出设备)的绘图属性的描述。MFC提供了CPaintDC类和CWindwoDC类来实时的响应,而CPaintDC支持重画。当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows WM_PAINT 消息发送给它。该视图的OnPaint 处理函数通过创建 CPaintDC 类的DC对象来响应该消息并调用视图的OnDraw成员函数。通常我们不必编写重写的OnPaint处理成员函数。 
///CView
默认的标准的重画函数 
void CView::OnPaint() //
VIEWCORE.CPP 
{
 

CPaintDC dc(this); 
OnPrepareDC(&dc) 
OnDraw(&dc); //
调用了OnDraw 
}
 
///CView默认的标准的OnPrint函数 
void CView::OnPrint(CDC* pDC, CPrintInfo*)
 

ASSERT_VALID(pDC); 
OnDraw(pDC); // Call Draw 


既然OnPaint最后也要调用OnDraw,因此我们一般会在OnDraw函数中进行绘制。下面是一个典型的程序。 
///
视图中的绘图代码首先检索指向文档的指针,然后通过DC进行绘图调用。 
void CMyView::OnDraw( CDC* pDC )
 


CMyDoc* pDoc = GetDocument(); 
CString s = pDoc->GetData(); 
GetClientRect( &rect ); // Returns a CStringCRect rect; 
pDC->SetTextAlign( TA_BASELINE | TA_CENTER ); 
pDC->TextOut( rect.right / 2, rect.bottom / 2,s, s.GetLength() ); 

最后:现在大家明白这哥俩之间的关系了吧。因此我们一般用OnPaint维护窗口的客户区(例如我们的窗口客户区加一个背景图片),用OnDraw维护视图的客户区(例如我们通过鼠标在视图中画图)。当然你也可以不按照上面规律来,只要达到目的并且没有问题,怎么干都成。补充:我们还可以利用Invalidate(),ValidateRgn(),ValidateRect()函数强制的重画窗口,具体的请参考MSDN吧。 

OnDraw
中可以绘制用户区域。OnPaint中只是当窗口无效时重绘不会保留CClientDC绘制的内容。 

这两个函数有区别也有联系: 

1
、区别:OnDraw是一个纯虚函数,定义为virtual void OnDraw( CDC* pDC ) = 0; 而OnPaint是一个消息响应函数,它响应了WM_PANIT消息,也是是窗口重绘消息。 

2
、联系:我们一般在视类中作图的时候,往往不直接响应WM_PANIT消息,而是重载OnDraw纯虚函数,这是因为在CVIEW类中的WM_PANIT消息响应函数中调用了OnDraw函数,如果在CMYVIEW类中响应了WM_PAINT消息,不显式地调用OnDraw函数的话,是不会在窗口重绘的时候调用OnDraw函数的。 

应用程序中几乎所有的绘图都在视图的 OnDraw成员函数中发生,必须在视图类中重写该成员函数。(鼠标绘图是个特例,这在通过视图解释用户输入中讨论。) 


OnDraw
重写: 
通过调用您提供的文档成员函数获取数据。 
通过调用框架传递给 OnDraw的设备上下文对象的成员函数来显示数据。 
当文档的数据以某种方式更改后,必须重绘视图以反映该更改。默认的 OnUpdate实现使视图的整个工作区无效。当视图变得无效时,Windows WM_PAINT 消息发送给它。该视图的 OnPaint 处理函数通过创建 CPaintDC 类的设备上下文对象来响应该消息并调用视图的 OnDraw成员函数。 

当没有添加WM_PAINT消息处理时,窗口重绘时,OnDraw来进行消息响应...当添加WM_PAINT消息处理时,窗口重绘时,WM_PAINT消息被投递,OnPaint来进行消息响应.这时就不能隐式调用OnDraw.必须显式调用(CDC *pDC=GetDC(); OnDraw(pDC); ).. 
隐式调用:当由OnPaint来进行消息响应时,系统自动调用CView::OnDraw(&pDC). 


想象一下,窗口显示的内容和打印的内容是差不多的,所以,一般情况下,统一由OnDraw来画。窗口前景需要刷新时,系统会会调用到OnPaint,而OnPaint一般情况下是对DC作一些初始化操作后,调用OnDraw() 


OnEraseBkGnd()
,是窗口背景需要刷新时由系统调用的。明显的一个例子是设置窗口的背景颜色(你可以把这放在OnPaint中去做,但是会使产生闪烁的现象)。 
至于怎么界定背景和前景,那要具体问题具体分析了,一般情况下,你还是很容易区别的吧。 

的确,OnPaint()用来响应WM_PAINT消息,视类的OnPaint()内部根据是打印还是屏幕绘制分别以不同的参数调用OnDraw()虚函数。所以在OnDraw()里你可以区别对待打印和屏幕绘制。 
其实,MFC在进行打印前后还做了很多工作,调用了很多虚函数,比如OnPreparePrint()等。





  在MFC程序设计中,按照传统的设计,如果处理WM_PAINT消息,一般会派生一个OnPaint函数,映射到WM_PAINT消息上进行绘图处理。但是很多程序中并没有出现OnPaint,一个OnDraw函数做了更多的绘图操作。而在消息映射的列表中,也没有见到WM_PAINT到OnDraw的映射。
实际上,OnDraw不是OnPaint的映射,出现OnDraw,是为了实现各种不同的设备上的绘图一致性。
首先,读者需要明白的是, WM_PAINT消息是为了绘制屏幕而出现的,因此, 在OnPaint中,我们只能存取屏幕DC,进行绘制,常见的代码是:
void MyWnd::OnPaint()
{
            CPaintDC dc(this);  //相当于BeginPaint()
        //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),要么自己创建CPaintDC实例,并调用OnDraw.
OnPaint(   )與OnDraw(   )的區別:  
OnPaint()是消息響應函數,默認是WM_PAINT消息的入口. 
OnDraw()是虛函數,是被OnPaint(  )調用的函數.  
OnPaint(   )優先于OnDraw(  ),如果重載了OnPaint(   ),則不會响应OnDraw(   ).如果需要,則需明确調用OnDraw(   )函數.     
     
//   In   this   example   a   rectangle  is   drawn   in   a   view.    
  //   The   OnChangeRect()   function   changes   the   dimensions   
  //   of   the  rectangle   and  then   calls   CWnd::Invalidate()   so   the   
  //   client   area   of   the  view   will   be   redrawn   next  time   the 
  //   window   is   updated.     It   then   calls   CWnd::UpdateWindow    
  //   to   force   the   new  rectangle   to  be   painted. 
   
  void   CTestView::OnChangeRect()    
  {  
        //   Change   Rectangle   size.  
        m_rcBox   =   CRect(20,   20,   210,  210);  
   
        //   Invalidate  window   so   entire   client   area   
        //   is   redrawn   when   UpdateWindow  is   called. 
        Invalidate();        
   
        //   Update   Window   to   cause  View   to   redraw.  
        UpdateWindow();  
  }  
   
  //   On   Draw  function   draws  the   rectangle. 
  void   CTestView::OnDraw(CDC*  pDC)  
  {  
  //     ..    Other   draw  code   here. 
   
        pDC->Draw3dRect(m_rcBox,  0x00FF0000,   0x0000FF00); 
     
     
用InvalidateRect()函数或者发一个WM_PAINT消息。 
  OnDraw()是回调函数,参数CDC*pDC是WINDOWS系统传来的!


总结:
       ON_PAINT是用来响应WM_PAINT消息的,在窗口变得无效等导致重画的情况下,都会调用ON_PAINT函数来响应WM_PAINT消息。而在基类中,在ON_PAINT函数中,会自动调用OnDraw函数,使得窗口重画时,能保存窗口原先的内容。ON_PAINT函数是用来响应WM_PAINT消息的,而OnDraw函数仅仅只是CView的虚函数。加入OnDraw函数的原因是ON_PAINT函数只是用来绘制屏幕的,在其他设备上绘制时,是不会调用ON_PAINT函数的,而OnDraw函数在OnPaint函数和OnPrint函数中都会被调用的。所以如果创建的东西仅仅是在某个设备上显示时,应该在该设备的消息响应函数中进行绘制;如果在所有的设备上都要进行一致性绘制,则应该在OnDraw函数中进行绘制。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值