(一) OnPaint 和 OnDraw
  (1)OnPaint是WM_PAINT消息的消息处理函数,在OnPaint中调用OnDraw,一般来说,用户自己的绘图代码应放在OnDraw中。
  (2)OnPaint()是CWnd的类成员,负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函数,没有响应消息的功能.
  (3)当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows发送WM_PAINT消息。该视图的OnPaint 处理函数通过创建CPaintDC类的DC对象来响应该消息并调用视图的OnDraw成员函数.OnPaint最后也要调用OnDraw,因此一般在OnDraw函数中进行绘制。
  (4)The WM_PAINT message is sent when the UpdateWindow or RedrawWindow member function is called.
  (5)在OnPaint中,将调用BeginPaint,用来获得客户区的显示设备环境,并以此调用GDI函数执行绘图操作。在绘图操作完成后,将调用EndPaint以释放显示设备环境。而OnDraw在BeginPaint与EndPaint间被调用。
 
(二) MFC结构
  (1)在MFC结构里OnPaint是CWnd的成员函数. OnDraw是CView的成员函数.
  (2)OnPaint()调用OnDraw(),OnPrint也会调用OnDraw(),所以OnDraw()是显示和打印的共同操作。  
  (3)OnPaint是WM_PAINT消息引发的重绘消息处理函数,在OnPaint中会调用OnDraw来进行绘图。
    1. OnPaint中首先构造一个CPaintDC类得实例,然后以这个实例为参数来调用虚函数OnPrepareDC来进行一些绘制前的一些处理,比设置映射模式,最后调用OnDraw。
    2. OnDraw和OnPrepareDC不是消息处理函数。所以在不是因为重绘消息所引发的OnPaint导致OnDraw被调用时,比如在OnLButtonDown等消息处理函数中绘图时,要先自己调用OnPrepareDC。 
  (4)至于CPaintDC和CClientDC根本是两回事情:
    1. CPaintDC是一个设备环境类,在OnPaint中作为参数传递给OnPrepareDC来作设备环境的设置。
    2. 真正和CClientDC具有可比性的是CWindowDC,他们一个是描述客户区域,一个是描述整个屏幕。 如果是对CVIEW或从CVIEW类派生的窗口绘图时应该用OnDraw。
 
(三) OnDraw()和OnPaint()区别
   1. 首先:我们先要明确CView类派生自CWnd类。而OnPaint()是CWnd的类成员,同时负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函数,并且没有响应消息的功能。这就是为什么你用VC生成的程序代码时,在视图类只有OnDraw没有OnPaint的原因。而在基于对话框的程序中,只有OnPaint。
  2. 其次:要想在屏幕上绘图或显示图形,首先需要建立设备环境DC。其实DC是一个数据结构,它包含输出设备(不单指你的纯屏显示器,还包括打印机之类的输出设备)的绘图属性的描述。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 CString CRect rect;
pDC->SetTextAlign( TA_BASELINE | TA_CENTER );
pDC->TextOut( rect.right / , rect.bottom / , s, s.GetLength() );
}

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

  4. 补充:我们还可以利用Invalidate(),ValidateRgn(),ValidateRect()函数强制的重画窗口,具体的请参考MSDN的CWnd::Invalidate .

  5. 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函数的(显式调用必须自己准备设备环境(   CDC *pDC=GetDC(); OnDraw(pDC);   ).)。
  3、应用程序中几乎所有的绘图都在视图的 OnDraw 成员函数中发生,必须在视图类中重写该成员函数。(鼠标绘图是个特例,这在通过视图解释用户输入中讨论。)
  4、OnDraw 重写: 通过调用您提供的文档成员函数获取数据。 通过调用框架传递给 OnDraw 的设备上下文对象的成员函数来显示数据。 当文档的数据以某种方式更改后,必须重绘视图以反映该更改。默认的 OnUpdate 实现使视图的整个工作区无效。当视图变得无效时,Windows 将 WM_PAINT 消息发送给它。该视图的 OnPaint 处理函数通过创建 CPaintDC 类的设备上下文对象来响应该消息并调用视图的 OnDraw 成员函数。  
  5、想象一下,窗口显示的内容和打印的内容是差不多的,所以,一般情况下,统一由OnDraw来画。窗口前景需要刷新时,系统会会调用到OnPaint,而OnPaint一般情况下是对DC作一些初始化操作后,调用OnDraw()。
  6、OnEraseBkGnd(),是窗口背景需要刷新时由系统调用的。明显的一个例子是设置窗口的背景颜色(你可以把这放在OnPaint中去做,但是会使产生闪烁的现象)。 至于怎么界定背景和前景,那要具体问题具体分析了,一般情况下,你还是很容易区别的吧。
 
(五)
  OnPaint()用来响应WM_PAINT消息,视类的OnPaint()内部根据是打印还是屏幕绘制分别以不同的参数调用OnDraw()虚函数。所以在OnDraw()里你可以区别对待打印和屏幕绘制。 其实,MFC在进行打印前后还做了很多工作,调用了很多虚函数,比如OnPreparePrint()等。
  对于OnDraw() :This method is called by the framework to render an image of the document. The framework calls this method to perform screen display, printing, and print preview, and it passes a different device context in each case. There is no default implementation.
 
 

Onpaint和OnDraw的区别的更多相关文章

  1. 重绘控件中OnPaint、OnDraw、OnDrawItem和DrawItem的区别

    ==================================================================================================== ...

  2. C#中控件Control的Paint事件和OnPaint虚函数的区别

    句柄 : 句柄,是整个Windows编程的基础.一个句柄是指使用的一个唯一的整数值,即一个4字节(64位程序中为8字节)长的数值,来标识应用程序中的不同对象和同类对象中的不同的实例,诸如,一个窗口,按 ...

  3. 关于MFC中的OnPaint和OnDraw

    当窗口发生改变后,会产生无效区域,这个无效的区域需要重画. 一般Windows会发送两个消息WM_PAINT(通知客户区 有变化)和WM_NCPAINT(通知非客户区有变化). 非客户区的重画系统自己 ...

  4. 把OnDraw和OnPaint弄清楚(转贴)

    OnDraw()和OnPaint()兄弟 经常有朋友问雷神这样的问题:我在视图画的图象或者文字,当窗口改变后为什么不见了?OnDraw()和OnPaint()两个都是解决上面的问题,有什么不同? 雷神 ...

  5. MFC中OnDraw()和OnPaint()的区别[转]

    问题 问题:我在视图画的图象或者文字,当窗口改变后为什么不见了?OnDraw()和OnPaint()两个都是解决上面的问题,有什么不同? OnDraw()和OnPaint()好象兄弟俩,因为它们的工作 ...

  6. [MFC]MFC中OnDraw与OnPaint的区别

    问题 问题:我在视图画的图象或者文字,当窗口改变后为什么不见了?OnDraw()和OnPaint()两个都是解决上面的问题,有什么不同? OnDraw()和OnPaint()好象兄弟俩,因为它们的工作 ...

  7. MFC中的Invalidate、OnDraw、OnPaint函数的作用

    MFC中的Invalidate.OnDraw.OnPaint函数的作用 CWnd::Invalidate voidInvalidate( BOOL bErase = TRUE ); 该函数的作用是使 ...

  8. OnDraw和Opanit的区别

    OnPaint是WM_PAINT消息的消息处理函数,在OnPaint中调用OnDraw,一般来说,用户自己的绘图代码应放在OnDraw中.  OnPaint() 是CWnd的类成员,负责响应WM_PA ...

  9. MFC中 Invalidate() , InvalidateRect() , UpdateWindow(), Redrawwindow() 区别

    1. void Invalidate( BOOL bErase = TRUE ); 该函数的作用是使整个窗口客户区无效.窗口的客户区无效意味着需要重绘,例如,如果一个被其它窗口遮住的窗口变成了前台窗口 ...

随机推荐

  1. 贝塞尔曲线.简单推导与用opengl实现动态画出。

    在opengl中,我们可以用少许的参数来描述一个曲线,其中贝塞尔曲线算是一种很常见的曲线控制方法,我们先来看维基百科里对贝塞尔曲线的说明: 线性贝塞尔曲线 给定点P0.P1,线性贝塞尔曲线只是一条两点 ...

  2. 实现接口时@Override注解问题

      用IntelliJ 15打开一个以前的工程,发现代码出现很多关于@Override的错误,编辑器提示:“@Override is not allowed when implementing int ...

  3. tornado 的 define 和options方法解读

    一.源码解读 tornado是facebook开源的非阻塞web容器,类似java的netty,tornado.options是负责解析tornado容器的全局参数的,同时也能够解析命令行传递的参数和 ...

  4. python进行数据分析------相关分析

    相关分析 import statsmodels.api as sm import pandas as pd import numpy as np from patsy.highlevel import ...

  5. c数据结构第一个公式写程序计算给定多项式在给定点x处的值

    假设x=2,那么a的数组有几个, 那n就是根据索引来的 假设数组[, , , , ] n就是0, 1, 2,,3, 4 f = + ( + ( + ( + ()))) f = + ( + ( + ( ...

  6. ITSM运营实施案例 - 汽车行业

    M公司是在汽车行业知名TOP企业,在日常运营过程中有如下问题: ******************************************************************** ...

  7. Java如何比较两个数组是否相等?

    在Java中,如何检查两个数组是否相等? 示例 以下示例显示如何使用数组的equals()方法来检查两个数组是否相等. package com.yiibai; import java.util.*; ...

  8. 如何解决#1045 - Access denied for user 'root'@'localhost' (using password: NO)问题

    1. #1045 - Access denied for user 'root'@'localhost'  (using password: NO) 解决方案 在phpMyAdmin中librarie ...

  9. LeetCode224——Basic Calculator

    Implement a basic calculator to evaluate a simple expression string. The expression string may conta ...

  10. keep-alive pipeline区别

    在http1.1中,引入了一种新的特性,即pipeline.那么什么是pipeline呢?pipeline其实就是流水线作业,它可以看作为keepalive的一种升华,因为pipeline也是基于长连 ...