BeginPaint和GetDC的区别

这是个windows编程问题。 
第一种情况显示出来的字很正常。 
case WM_PAINT: 
           gdc = BeginPaint (hwnd, &ps); 
           TextOut (gdc, 0, 0, s, strlen (s)); 
           EndPaint (hwnd, &ps); 
break; 
第二种情况显示的字不停闪烁。 
case WM_PAINT: 
           gdc = GetDC (hwnd); 
           TextOut (gdc, 0, 0, s, strlen (s)); 
           ReleaseDC (hwnd, gdc); 
break; 
请教两种函数的作用?

BeginPaint() 和EndPaint() 可以删除消息队列中的WM_PAINT消息,并使无效区域有效。 
GetDC()和ReleaseDC()并不删除也不能使无效区域有效,因此当程序跳出 WM_PAINT 时 ,无效区域仍然存在。系统就回不断发送WM_PAINT消息,于是程序不断处理WM_PAINT消息。

BeginPaint、EndPaint会告诉GDI内部,这个窗口需要重画的地方已经重画了,这样 WM_PAINT处理完返回给系统后,系统不会再重发WM_PAINT,而GetDC没有告诉系统这个窗口需要重画的地方已经画过,在你把程序返回给系统 后,系统一直以为通知你的重画命令你还没有乖乖的执行或者执行出错,所以在消息空闲时,它还会不断地发WM_PAINT催促你画,导致程序卡死。

无效区域 :

无效区域就是指需要重画的区域,无效的意思是:当前内容是旧的,过时的。 
假设A是新弹出的一个对话框或被激活的现有对话框,A对话框置于原来的活动对话框B前面,造成对话框B的部分或全部被覆盖,当对话框A移开或关闭后,使对话框B原来被覆盖的地方重新可见。那部分被覆盖的地方就称为无效区域。 
只有当一个窗口消息空闲时,系统才会抽空检查一下这个窗口的无效区域是否为非空(WM_PAINT的优先级是最低的。这也就是为什么系统很忙时窗口和桌面 往往会出现变白、刷新不了、留拖拽痕迹等现象的原因),如果非空,系统就发送WM_PAINT。所以一定要用BeginPaint、EndPaint把无 效区域设为空,否则WM_PAINT将一直被发送。

为什么WINDOWS要提出无效区域的概念?

这是为了加速。 
因为BeginPaint和EndPaint用到的设备描述符只会在当前的无效区域内绘画,在有效区域内的绘画会自动被过滤,大家都知道,WIN GDI的绘画速度是比较慢的,所以能节省一个象素就节省一个,不用吝啬,这样可以有效加快绘画速度。 
可见BeginPaint、EndPaint是比较“被动”的,只在窗口新建时和被摧残时才重画。 
而GetDC用于主动绘制,只要你指到哪,它就打到哪。它不加判断就都画上去,无效区域跟它没关系。对话框没被覆盖没被摧残,它很健康,系统没要求它重 画,但开发者有些情况下需要它主动重画:比如一个定时换外观的窗口,这时候就要在WM_TIMER处理代码用GetDC。这时候再用 BeginPaint、EndPaint的话,会因为无效区域为空,所有绘画操作都将被过滤掉。

PAINTSTRUCT

从上面BeginPaint函数的原形中我们可以看到需要一个PAINTSTRUCT结构对象的内存地址,PAINTSTRUCT结构包含在WinUser.h头文件中。

  定义如下:

typedef struct tagPAINTSTRUCT {
  HDC         hdc; //设备描述表句柄
  BOOL        fErase; //擦除状态
  RECT        rcPaint; //无效矩形座标
  BOOL        fRestore;
  BOOL        fIncUpdate;
  BYTE        rgbReserved[32];
}
PAINTSTRUCT, *PPAINTSTRUCT, *NPPAINTSTRUCT, *LPPAINTSTRUCT;

  事实上当程序调用BeginPaint函数的时候,Windows会自动的填写此结构的各个属性,而程序作者只需要关心前三个属性。

  第一个属性hdc表示当前的设备描述表句柄。

  第二个属性fErase来说,多数情况下它是被标记成FALSE(0)的,这表示Windows已经擦除了无效矩形的背景,这个擦除动作是是在BeginPaint函数中发生的,而擦除背景用的画刷则是WNDCLASS结构中的hbrBackground属性指定的画刷来擦除背景的,在很多情况下可能程序作者想自己定义一些插除行为,那么可以通过响应消息队列中的WM_ERASEBKGND消息来完成。

  第三个属性rcPaint则表示无效矩形座标,它定义了无效矩形的边界。

  RECT结构可以在WinDef.h头文件中找到。

  定义如下:

typedef struct tagRECT
{
LONG    left;
LONG    top;
LONG    right;
LONG    bottom;
} RECT, *PRECT, NEAR *NPRECT, FAR *LPRECT;

  注意,我们在前面提到了InvalidateRect函数,并已经清楚了调用它可以让窗口显示区域内的矩形变为无效,那么我们就可以在处理WM_PAINT消息的时候通过调用它实现在无效矩形外绘图,该调用是在调用BegingPaint函数之前调用的。

  使用方法:

InvalidateRect(hwnd,NULL,TRUE);

  通过上面代码的调用我们让整个显示区域变为了无效,并擦除背景,要注意的是,最后一个参数如果为FALSE,则不擦除背景,原有的东西将保留在原处,这通常是在接受到WM_PAINT消息的时候而不考虑rcPaint属性的情况下简单的重绘整个显示区域最方便的方法,例如,在显示区域内我们输出了一个图形,这个图形的一小部分落在了无效矩形区域内,而这就让绘制这个图形的无效部分变的没有意义,这时就需要重绘整个图形,因为在调用BeginPaint函数传回设备描述表句柄的时候,Windows不会绘制rcPaint也就是无效矩形以外的任何部分。


CPaintDC
CPaintDC 用于响应窗口重绘消息(WM_PAINT)是的绘图输出。CPaintDC在构造函数中调用BeginPaint()取得设备上下文,在析构函数中调用 EndPaint()释放设备上下文。EndPaint()除了释放设备上下文外,还负责从消息队列中清除WM_PAINT消息。因此,在处理窗口重画时,必须使用CPaintDC,否则WM_PAINT消息无法从消息队列中清除,将引起不断的窗口重画。CPaintDC也只能用在WM_PAINT消息处理之中。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值