当前位置:C++技术网 > 资讯 > OnPaint函数中CDialog::OnPaint()要注释掉的理由详解

OnPaint函数中CDialog::OnPaint()要注释掉的理由详解

更新时间:2016-01-28 21:47:04浏览次数:1+次

    先执行OnEraseBkgnd,擦除背景(如果想自绘控件,这个函数直接return TRUE就可以了,这样就不会擦除背景,不会闪)OnEraseBkGnd与OnPaint的区别与联系在OnEraseBkGnd中,如果你不调用原来缺省的OnEraseBkGnd只是重画背景则不会有闪烁.而在OnPaint里面,由于它隐含的调用了OnEraseBkGnd,而你又没有处理OnEraseBkGnd 函数,这时就和窗口缺省的背景刷相关了.缺省的 OnEraseBkGnd操作使用窗口的缺省背景刷刷新背景(一般情况下是白刷),而随后你又自己重画背景造成屏幕闪动.OnEraseBkGnd不是每次都会被调用的.如果你调用Invalidate的时候参数为TRUE,那么在OnPaint里面隐含调用BeginPaint的时候就产生WM_ERASEBKGND消息,如果参数是FALSE,则不会重刷背景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中
在設定上 OnEraseBkgnd()是用來畫底圖的 而OnPaint()是用來畫主要物件的
舉例說明 一個按鈕是灰色的 上面還有文字
則OnEraseBkgnd()所做的事就是把按鈕畫成灰色
而OnPaint()所做的事 就是畫上文字
BeginPaint函数的作用就是将窗口重绘的区域设置为空,(也就是Upadate Region为空)。在正常的情况下,我们接受到了WM_PAINT函数后,窗口的Uadate Region都是非空的(如果为空就是不需要发送WM_PAINT消息了)。而当你响应这个消息的时候又不调用BeginPaint函数来清空,窗口的Update Region就是一直都是非空的,系统就会一直发送WM_PAINT消息。 
因此《窗口重绘的一个误区——CDialodExOnPaint函数》以及《MFC实现贪吃蛇贪吃蛇移动效果(矩形自由移动)》文章中,为什么需要注释掉最后一句代码?CDialogEx::OnPaint();这是因为,我们在WM_PAINT函数中加了Invalidate();使得窗口无效。我详细解释下。程序一开始就运行WM_PAINT消息,当程序运行到Invalidate();通知系统,在WM_PAINT消息处理完之后的空闲时间在处理这个WM_PAINT函数,程序代码运行到CDialogEx::OnPaint();此时有Upadate Region且不为空,因此调用底层的OnPaint函数,这时候当BeginPaint函数运行时就会首先调用底层的WM_ERASEBKGND,然后调用消息处理函数OnEraseBkGnd来擦除背景,这时候,我们在之前由OnPaint函数处理的背景就会被覆盖掉了,你可以试试。当你不把CDialogEx::OnPaint();注释掉的话,你设置定时1秒。你会发现你之前绘画的东西一秒之后都没了,这就是因为,WM_PAINT函数中又调用了Invalidate()使得产生了Upadate Region,接着调用底层的CDialogEx::OnPaint()。其实说到这里,你应该得出这样的结论:
我们在WM_PAINT函数中加上Invalidate()之后,注释掉CDialogEx::OnPaint()就相当于在别的WM_消息中调用Invalidate()而不注释掉CDialogEx::OnPaint()。这是为什么?就是因为Upadate Region产生的时间不同。