WM_PAINT介绍及OnPaint()函数的作用原理
* MFC中 OnPaint()是对这个消息的反应函数( mfc 的 CWnd::OnPaint() 没做什么,只是丢给系统处理,下面就是介绍它在系统中的处理流程)
关于 WM_PAINT 消息
系统会在多个不同的时机发送WM_PAINT消息:当第一次创建一个窗口时,当改变窗口的大小时,当把窗口从另一个窗口背后移出时,当最大化或最小化窗口时,等等,这些动作都是由系统管理的,应用只是被动地接收该消息,在消息处理函数中进行绘制操作;大多数的时候应用也需要能够主动引发窗口中的绘制操作,比如当窗口显示的数据改变的时候,这一般是通过InvalidateRect和InvalidateRgn函数来完成的。
InvalidateRect和 InvalidateRgn把指定的区域加到窗口的Update Region(Update Region:Windows窗口更新区域/无效区域)中,当应用的消息队列没有其他消息时,如果窗口的Update Region不为空时,系统就会自动产生WM_PAINT消息。
像这种通过InvalidateRect和InvalidateRgn来使窗口区域无效,依赖于系统在合适的时机发送WM_PAINT消息的机制实际上是一种异步工作方式,也就是说,在无效化窗口区域和发送WM_PAINT消息之间是有延迟的;有时候这种延迟并不是我们希望的,这时我们当然可以在无效化窗口区域后利用SendMessage 发送一条WM_PAINT消息来强制立即重画,但不如使用Windows GDI为我们提供的更方便和强大的函数:UpdateWindow和RedrawWindow。UpdateWindow会检查窗口的Update Region,当其不为空时才发送WM_PAINT消息;RedrawWindow则给我们更多的控制:是否重画非客户区和背景,是否总是发送 WM_PAINT消息而不管Update Region是否为空等。
系统为什么不在调用Invalidate时发送WM_PAINT消息呢?又为什么非要等应用消息队列为空时才发送WM_PAINT消息呢?这是因为系统把在窗口中的绘制操作当作一种低优先级的操作,于是尽可能地推后做。不过这样也有利于提高绘制的效率:两个WM_PAINT消息之间通过 InvalidateRect和InvaliateRgn使之失效的区域就会被累加起来,然后在一个WM_PAINT消息中一次得到更新,不仅能避免多次重复地更新同一区域,也优化了应用的更新操作。
无效区域的坐标并不附带在WM_PAINT消息的参数中.实际上,Windows为每个窗口维护一个“绘图信息结构”,无效区域的坐标就在其中,每当消息循环空的时候,如果Windows发现存在一个无效区域,就会放入一个WM_PAINT消息。那么“绘图信息结构”怎么获取呢?BeginPaint函数的第二个参数就是一个绘图信息结构的缓冲区地址,windows会在这里返回绘图信息结构,结构中包含了无效区域的位置和大小,绘图信息结构的定义如下:
typedef struct tagPAINTSTRUCT {......}PAINTSTRUCT;
系统OnPaint()的内部处理流程
一 :
先执行OnEraseBkgnd,擦除背景(如果想自绘控件,这个函数直接return TRUE就可以了,这样就不会擦除背景,不会闪)
OnEraseBkGnd与OnPaint的区别与联系
在OnEraseBkGnd中,如果你不调用原来缺省的OnEraseBkGnd只是重画背景则不会有闪烁.而在OnPaint里面,由于它隐含的调用了OnEraseBkGnd,而你又没有处理OnEraseBkGnd 函数,这时就和窗口缺省的背景刷相关了.缺省的 OnEraseBkGnd操作使用窗口的缺省背景刷刷新背景(一般情况下是白刷),而随后你又自己重画背景造成屏幕闪动.
OnEraseBkGnd不是每次都会被调用的.如果你调用Invalidate的时候参数为TRUE,那么在OnPaint里面隐含调用BeginPaint的时候就产生WM_ERASEBKGND消息,如果参数是FALSE,则不会重刷背景.
ZYP解释:void Invalidate( BOOL bErase = TRUE ); 该函数的作用是使整个窗口客户区无效。窗口的客户区无效意味着需要重绘,参数bErase为TRUE时,重绘区域内的背景将被重绘即擦除,否则,背景将保持不变。调用Invalidate等函数后窗口不会立即重绘,这是由于WM_PAINT消息的优先级很低,它需要等消息队列中的其它消息发送完后才能被处理。
OnPaint里面会调用BeginPaint函数自动设置显示设备内容的剪切区域而排除任何更新区域外的区域更新区域。如果更新区域被标记为可擦除的,BeginPaint发送一个WM_ERASEBKGND消息给窗口。WM_ERASEBKGND消息的响应函数既是OnEraseBkGnd()
所以解决方法有三个半:
1.用OnEraseBkGnd实现,不要调用原来的OnEraseBkGnd函数.
2.用OnPaint实现,同时重载OnEraseBkGnd,其中直接返回.
3.用OnPaint实现,创建窗口时设置背景刷为空
4.用OnPaint实现,但是要求刷新时用Invalidate(FALSE)这样
的函数.(不过这种情况下,窗口覆盖等造成的刷新还是要闪一
下,所以不是彻底的解决方法)
都挺简单的.
在MFC中 任何一個window元件的繪圖 都是放在這兩個member function中 既然這兩個member function都是用來畫出元件的 如果我們是一個在做圖形化使用者介面的人 這個問題的解法 比較差點的方法是把OnEraseBkgnd() 改寫成不做事的function
以上本來是會呼叫CDialog::OnEraseBkgnd() 但是如果我們不呼叫的話 Q:基于对话框的程序中如何重载OnEraseBkGnd()函数 A:这是一个消息WM_ERASEBKWND 比較好的做法是直接將繪圖的程式從OnPaint()移到OnEraseBkgnd()來做
特別要注意的是 取得重畫大小是使用GetUpdateRect() 而不是GetClientRect() 如果使用GetClientRect() 會把不該重畫的地方重畫
来自:http://hi.baidu.com/����_�ֵ�/blog/item/2f6d3b10b6c622fac2ce79a5.html
|
二 :
系统的Onpaint中调用了OnDraw,但如果我们自己继承了一个OnPaint函数又没有显式调用OnDraw,则OnDraw就不会被调用,OnInitialUpdate在OnDraw之前,是窗口被创建以后调用的第一个函数。
MFC中OnDraw与OnPaint的区别
在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间被调用。(一个应用程序除了响应WM_PAINT消息外,不应该调用BeginPaint。每次调用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
{
OnDraw中可以绘制用户区域。OnPaint中只是当窗口无效时重绘不会保留CClientDC绘制的内容。
应用程序中几乎所有的绘图都在视图的 OnDraw 成员函数中发生,必须在视图类中重写该成员函数。(鼠标绘图是个特例,这在通过视图解释用户输入中讨论。)
OnCtlColor()是当窗口的控件需要绘制时发生的,它将绘制窗口的控件。
视图窗口完全建立后第一个被框架调用的函数。框架在第一次调用OnDraw前会调用OnInitialUpdate,因此OnInitialUpdate是设置滚动视图的逻辑尺寸和映射模式的最合适的地方。
WM_PAINT介绍及OnPaint()函数的作用原理相关推荐
- OnPaint()函数的作用原理
WM_PAINT是窗口每次重绘都会产生的一个消息. OnPaint是对这个消息的反应函数 mfc 的 CWnd::OnPaint 没做什么,只是丢给系统处理. 一 : 先执行OnEraseBkgnd, ...
- MFC中的Invalidate、OnDraw、OnPaint函数的作用及绘图概念
1.绘图概念 GDI绘图分为背景和前景两个画布的绘制,Invalidate()函数强制重绘制, Invalidate() 如果参数为true则在OnPaint函数对背景先进行绘制,再对前景进行 ...
- 有关C#中重写按钮的onpaint函数,实现按钮形状的用户自定义
在使用C#进行界面开发的过程中,做界面开发经常会用到按钮,而C#界面中的按钮形状只有矩形的,而如果我们需要其他形状的按钮的话,就需要想点儿其他办法了,一般开发自己的控件有三种方法: 首先是复合控件,从 ...
- vcg函数值_简单介绍几种函数信号发生器的原理图及不同功能设计
简单介绍几种函数信号发生器的原理图及不同功能设计 前言 随着大规模集成电路的迅速发展,函数发生器的应用也逐渐广泛起来.函数信号发生器(函数信号发生器的使用)是一种在科研和生产中经常用到的基本波形产生器 ...
- OnDraw和OnPaint函数的区别
CWnd::OnPaint() 是CWnd类的成员函数,是WM_PAINT 消息的响应函数.当你调用CWnd::UpdateWindow(),CWnd::RedrawWindow()时, 或者窗口被其 ...
- Python学习札记(二十) 函数式编程1 介绍 高阶函数介绍
参考: 函数式编程 高阶函数 Note A.函数式编程(Functional Programming)介绍 1.函数是Python内建支持的一种封装,我们通过一层一层的函数调用把复杂任务分解成简单的任 ...
- mysql的replace()函数介绍【mysql函数】
#下面就是对这个函数的简要介绍以及范例. #示例: #比如你要将 表 tb1里面的 f1字段的abc替换为def: 1 UPDATE tb1 SET f1=REPLACE(f1, 'abc', 'de ...
- 简单介绍Javascript匿名函数和面向对象编程
忙里偷闲,简单介绍一下Javascript中匿名函数和闭包函数以及面向对象编程.首先简单介绍一下Javascript中的密名函数. 在Javascript中函数有以下3中定义方式: 1.最常用的定义方 ...
- Python3.9标准库math中的函数汇总介绍(53个函数和5个常数)
为了更好的用计算机帮助我们运算,首先要了解自己使用的库中有什么方法,否则就会做会多费力不讨好的重复工作. 本篇博文我们来了解Python标准库的math函数. 参考资料: Python3.9的math ...
最新文章
- pandas重置dataframe的索引(reset_index)、如果索引不匹配dataframe操作时候的问题、重置索引(不设置drop=true)远索引生成新的数据列
- Pandas进阶修炼120题,给你深度和广度的船新体验
- 阿里云数据库RDS环境搭建
- c++中有表示正无穷的数吗_阅读:贯穿编程人生CSAPP[2]信息表示
- java连接数据库的基本操作
- SpringBoot与缓存使用及原理(上)
- 微信小程序报错 TypeError: Cannot read property ‘setData‘ of undefined
- 一个萌新关于电脑安装软件错误提示“1402”的应对方法
- 房租,社会教给年轻人的第一课
- 第一章:python入门储备知识
- 国内有名的文化与教育调查研究咨询公司
- antd form 表单数据校验·记
- Python向左,数学向右:梅森素数
- 建议收藏 | 数据化、信息化、数字化、智能化到底都是指什么?彼此有什么联系?
- kotlin的学习记录
- Vue自定义指令实现弹窗拖拽,四边拉伸及对角线拉伸
- 【Linux】Ubuntu 18.04网易云音乐安装后无法打开问题解决
- Navicat Premium教程|Navicat Premium怎么用?
- wx图片的相机相册获取,预览图片,图片保存,图片的信息
- matlab动态文字,matlab GUI界面文字动态显示
热门文章
- php100 代码,php_100 PHP源代码 - 下载 - 搜珍网
- java dao service实例_浅谈Action+Service +Dao 功能
- vuecli打包后的dist目录无法访问_听说很多人都不会打包,教你Python实现前端自动化打包部署!...
- axure 小程序 lib_详细揭秘微信小程序框架技术——Mpx
- html表格高度适应屏幕,Table的自适应高度
- c语言subscripted_c语言。数组的问题。急!
- python ioc di_Sping(一)——IOC/DI
- 编译原理实验语义分析_「编译原理」LL(1)文法分析,简单优先分析
- 在中国做操作系统研发 20 年是种什么体验?
- android 毕业设计 文献翻译,android毕业设计外文翻译.doc