MFC中OnDraw与OnPaint的区别

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。 

OnDraw()和OnPaint()有什么区别呢? 
首先:我们先要明确CView类派生自CWnd类。而OnPaint()是CWnd的类成员,同时负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函数,并且没有响应消息的功能。这就是为什么你用VC成的程序代码时,在视图类只有OnDraw没有OnPaint的原因。而在基于对话框的程序中,只有OnPaint。 
其次:我们在第《每天跟我学MFC》3的开始部分已经说到了。要想在屏幕上绘图或显示图形,首先需要建立设备环境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 CString CRect 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()等。 

转载于:https://www.cnblogs.com/orez88/articles/2216607.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/462448.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows Internet

网址:http://baike.baidu.com/view/560670.htm WinInet 求助编辑百科名片 WinInet(“Windows Internet”)API帮助程序员使用三个常见的Internet协议,这三个协议是用于World Wide Web万维网的超文本传输协议(HTTP:Hyper…

PHP使用CURL抓取页面

cURL的基本原理 curl是利用URL语法在命令行方式下工作的开源文件传输工具&#xff0c;他能够从互联网上获得各种各样的网络资源。简单来说&#xff0c;curl就是抓取页面的升级版。 <?php//1.初始化&#xff0c;创建一个新cURL资源$ch curl_init(); //2.设置URL和相应的选…

Lync Server 2010迁移至Lync Server 2013故障排错 Part3 :内外网共享PPT提示证书问

最近在公司生产环境中部署Lync Server 2013并对公网发布后&#xff0c;发现公网未加域客户端在与内网用户共享PPT时&#xff0c;会报证书错误&#xff0c;如下图所示&#xff1a;但是内网是正确的&#xff0c;经过查询了一下Lync 客户端自身的日志信息后发现&#xff0c;公网客…

用WinInet开发Internet客户端应用指南

一&#xff1a;http://www.vckbase.com/document/viewdoc/?id545 二&#xff1a;http://www.vckbase.com/document/viewdoc/?id546 用WinInet开发Internet客户端应用指南&#xff08;一&#xff09; 编译/NorthTibet 一、概述一个Internet客户端程序的目的是通过Internet…

WebService的基本概念:java webservice,什么是webservice

WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求&#xff0c;轻量级的独立的通讯技术。 这种技术允许网络上的所有系统进行交互。随着技术的发展&#xff0c;一个Web服务可以包含额外的指定功能并且可以在多个B2B应用中协作通讯。 Web服务可以理解…

掌握常见的内部排序方法(插入排序,冒泡排序,选择排序,快速排序,堆排序,希尔排序,归并排序,基数排序等)...

掌握常见的内部排序方法&#xff08;插入排序&#xff0c;冒泡排序&#xff0c;选择排序&#xff0c;快速排序&#xff0c;堆排序&#xff0c;希尔排序&#xff0c;归并排序&#xff0c;基数排序等&#xff09;。数组高级以及Arrays(掌握)排序方法空间复杂度时间复杂度稳定性插…

关于Android错误 View requires API level 14 (current...

2019独角兽企业重金招聘Python工程师标准>>> 问题描述&#xff1a;在界面配置文件main.xml中&#xff0c;可能用上某些控件&#xff08;例如GridLayout&#xff09;遇上下面所说的错误:View requires API level 14(current min is 8), 但将项目clear后&#xff0c;再…

socket-select函数

最近在用socket编程&#xff0c;用到select函数&#xff0c;于是上网查找资料&#xff0c;如下这篇是讲的比较详细易懂的&#xff1a;Select在Socket编程中还是比较重要的&#xff0c;可是对于初学Socket的人来说都不太爱用Select写程序&#xff0c;他们只是习惯写诸如 connect…

javascript 基础 转

最近面试过一些人, 发现即使经验丰富的开发人员, 对于一些基础的理论和细节也常常会模糊. 写本文是因为就我自己而言第一次学习下面的内容时发现自己确实有所收获和感悟. 其实我们容易忽视的javascript的细节还有更多, 本文仅是冰山一角. 希望大家都能通过本文有所斩获.一. Jav…

从表到里学习JVM实现

在社会化分工、软件行业细分专业化的趋势下&#xff0c;会真的参与到底层系统实现的人肯定是越来越少&#xff08;比例上说&#xff09;。真的会参与到JVM实现的人肯定是少数。但如果您对JVM是如何实现的有兴趣、充满好奇&#xff0c;却苦于没有足够系统的知识去深入&#xff0…

2019春第二次课程设计实验报告

2019春第二次课程设计实验报告 一、实验项目名称 用数组实现反弹球消砖块 二、实验项目功能描述 利用键盘按键控制小球方向让小球碰到挡板后反弹上去消除砖块。 三、项目模块结构介绍 四、实现界面展示 五、代码托管链接 https://gitee.com/huangxuannn/events 六、实验总结 上…

[SharePoint 2010] Client Object Model 跨时区查询list item的方法

SharePoint将所有的Datetime类型的数据都以universal的形式(UTC)存储在数据库中&#xff0c;当要在页面上显示类似list item的"Created", "Modified"等时间日期信息时&#xff0c;将数据库中的UTC时间取出来&#xff0c;然后根据当前Site的Regional Settin…

Linux下静态库和动态库的编译连接

http://blog.sina.com.cn/s/blog_4090ba590100t3nu.html .a文件 gcc -c test.c ar rc libtest.a test.o ranlib libtest.a 静态库只要编译出.o文件然后用ar打入包中就可以 动态库或共享库不用libtool工具&#xff1a; gcc -fpic -o test.o -c test gcc -shared -o te…

修改终端服务端口的方法

修改终端服务端口的方法Windows 2000 下的修改办法   win2k的终端服务可以运行在两种方式下&#xff1a;远程管理或应用程序服务器模式。   远程管理模式&#xff1a;允许一定数量的管理员远程管理这个服务器&#xff0c;这个模式对服务器性能的影响程度最低。   应用程序…

PYTHON -c

命令行执行代码转载于:https://www.cnblogs.com/BlueFire-py/p/10957663.html

Linux显示中文乱码解决方法

http://sumit.blog.51cto.com/162317/206698经常使用linux终端&#xff0c;有人上传中文命名的文件显示出中文乱码&#xff0c;下面是解决方法。默认显示的字符编码# echo $LANGen_US.UTF-8修改i18n文件# vi /etc/sysconfig/i18nLANG"zh_CN.GB18030"LANGUAGE"zh…

多行字符串的表示方式

原文载于&#xff1a;http://robinwu.iteye.com/blog/145514 其中最重要的、忽略一切转义字符、多行大包围、相当于的多行版本 1 str <<EOF 2 This isnt a tab: \t 3 and this isnt a newline: \n 4 EOF 5 6 puts str 转载于:https://www.cnblogs.com/kloboh…

nodejs+redis

为什么80%的码农都做不了架构师&#xff1f;>>> redis可以用来管理session http://www.csser.com/board/4f77e6f996ca600f78000936 然后使用的时候redis-server这个服务进程得开着&#xff0c;不然会悲剧的 转载于:https://my.oschina.net/kiloct/blog/137629

Caused by: java.lang.ClassNotFoundException: Cannot find class: User

源代码: <select id"selectAll" resultType"User">select user_id uid,user_name username,user_password password,user_gender gender, user_birthday birthday, user_status status from users</select> 正确代码: <select id"s…

标准C语言库 Glibc 2.15

http://www.oschina.net/p/glibc Glibc 是提供系统调用和基本函数的 C 库&#xff0c;比如open, malloc, printf等等。所有动态连接的程序都要用到它。 Glibc最新更新资讯&#xff0c;共2条 (投递新闻) 1个月前GNU libc 2.15 (Glibc) 发布 2评/952阅 7个月前GLib 2.30.0 发布&…