BeginPaint和GetDC的区别

第一种情况显示出来的字很正常。 # B9 D1 }# q& p  ], T+ j
case WM_PAINT: ! _1 F3 |7 T1 o& }; M. }
           gdc = BeginPaint (hwnd, &ps); * F2 s; w+ A4 i+ C6 p. p) n* x
           TextOut (gdc, 0, 0, s, strlen (s)); + @( D# s2 W1 w3 y" M0 E& B/ m
           EndPaint (hwnd, &ps);
9 t* J9 o, d; [8 O- H break;
3 b& O& M- m4 [/ u8 h 第二种情况显示 的字不停闪烁。
% G  H' I) o; X2 K$ E9 u6 ^ case WM_PAINT:
1 S5 y: I1 r8 W+ A            gdc = GetDC (hwnd); - R% s* c( p$ M( g
           TextOut (gdc, 0, 0, s, strlen (s));
& Q% h' D+ {5 j, R4 O            ReleaseDC (hwnd, gdc);
/ i1 _7 A4 ?$ o+ I! L break;

BeginPaint() 和EndPaint() 可以删除消息队列中的WM_PAINT消息,并使无效区域有效。
/ /! G6 s& L; V/ u GetDC()和 ReleaseDC()并不删除也不能使无效区域有效,因此当程序 跳出 WM_PAINT 时 ,无效区域仍然存在。系统 就回不断发送WM_PAINT消息,于是程序不断处 理WM_PAINT消息。
! s- |6 B9 l3 j2 w+ f BeginPaint、 EndPaint会告诉GDI内部,这个窗口 需要重画的地方已经重画了,这样WM_PAINT处 理完返回给系统后,系统不会再重发WM_PAINT,而GetDC没有告诉系统这个窗口需要重画的地方已经画过,在你把程序返回给系统后,系统一直以为通 知你的重画命令你还没有乖乖的执行或者执行出错,所以在消息空闲时,它还会不断地发WM_PAINT催促你画,导致程序卡死。3 Y1 F7 _+ k: @  l

; m7 {# y3 `: G& E: l4 T 无效区域 :0 D; B) `$ K3 d* k% q( a' f

  {& a% q. @# {4 |6 I0 A/ A; @' F 无 效区域就是指需要重画的区域,无效的意思是:当前内容是旧的,过时的。
( /4 z4 r% w) Y: Y# u 假设A是新弹出的一个对话框或被 激活的现有对话框,A对话框置于原来的活动 对话框B前面,造成对话框B的部分或全部被覆盖,当 对话框A移开或关闭后,使对话框B原来被覆盖的地方重新可见。那部分被覆盖的地方就称为无效区域。
/ y. j1 I0 n7 |# m, T% j( Z* D8 ~2 X 只 有当一个窗口消息空闲时,系统才会抽空检查一下这个窗口的无效区域是否为非空(WM_PAINT的优先级是最低的。这也就是为什么系统很忙时窗口和桌面往 往会出现变白、刷新不了、留拖拽痕迹等现象的原因),如果非空,系统就发送WM_PAINT。所以一定要用BeginPaint、EndPaint把无效 区域设为空,否则WM_PAINT将一直被发送。% {: E2 S/ S3 K/ W# E6 C$ p  O

' b6 z9 L0 `/ R* / 为什么WINDOWS要提出无效区域的 概念?
5 T, Q- D: Q  i2 F" h 这是为了加速。
: @$ p* |0 z: ^ 因为BeginPaint和EndPaint 用到的设备描述符只会在当前的无效区域内绘画,在有效区域内的绘画会自动 被过滤,大家都知道,WIN GDI的绘画速度是比较慢的,所以能节省一个象素就节省一个,不用吝啬,这样可以有效加快绘画速度。
* G& e# N9 L; B 可见BeginPaint、 EndPaint是比较“被动”的,只在窗口新建时和被摧残时才重画。 3 J4 i+ /! F  X+ Z
而GetDC用于主动绘制,只要你指到哪,它就打到哪。它不加判断就都画上去,无效区域跟它没关系。对话框没被覆盖没被摧残,它很健康,系统没要求它重 画,但开发者有些情况下需要它主动重画:比如一个定时换外观的窗口,这时候就要在WM_TIMER处理代码 用GetDC。这时候再用BeginPaint、 EndPaint的话,会因为无效区域为空,所有绘画操作都将被过滤掉。

/
3 h! i2 ]$ G. J 下面是更加详细的介绍
( w, w$ v$ L' b2 N //========================================================================
( x6 N. D; e( |2 ?( D# O$ k //TITLE: ; m( G8 ]8 e5 e) E. }& o
//     EVC绘制位图--BeginPaint()与GetDC()的区别
& ~$ g0 L; G: t( V+ w //AUTHOR:
1 M+ J: o* C6 X! h# Q0 G- | //     norains
! e9 s* e0 }$ S3 @9 ~ //========================================================================
: g2 @0 B4 P) F: x3 O. k7 V. ? 1.BeginPaint() 和GetDC() 5 ^! L( ]8 a6 Z* l/ L1 o
         在EVC中绘制位图比较方便,有不少现成的函数可供调用,我们所要注意的只是BeginPaint()或GetDC()的使用即可. " x/ h" s: C3 M  l( N; Q4 W7 j
         因为代码比较简单,所以不做更多解释. . C5 d4 H9 c+ K  ~% j1 [$ x
         这是消息循环函数:

响应WM_PAINT消息的函数,在这里进行位图的绘制:

我们都知道BeginPaint()和EndPaint()需要配套使用,并且这两个函数也只能用在WM_PAINT消息的相应函数当中.如果我们在 WM_PAINT的响应函数中将以上两个绘制函数相应替换为GetDC()和ReleaseDC()会有什么结果呢? / s& z  L3 `2 Q5 Q. j
         即: - |4 @  C' j# N. t! r: C9 f3 e9 L
         HDC hdc = BeginPaint(hWnd,&ps);     -->    HDC hdc = GetDC(hWnd); . B! i5 J* {* X" ^
         EndPaint(hWnd,&ps);                 -->    ReleaseDC(hWnd,hdc); " f: U! I# R, M
         编译运行 程序,我们发现窗口一片空白,好像没有绘制位图.但 其实不尽然,我们采用单步调试 ,可以发现其实位图已经绘制出来,只不过又被背景颜 色抹掉了.由此可知,如果需要使用GetDC(),我们对消息循环函数必须要加上对WM_ERASEBKGND的处理:

只要系统不对WM_ERASEBKGND进行默认处理,我们用GetDC()替代BeginPaint()就可以正常使用. ! A7 A, /3 q+ q7 }2 i
         至此我们可以看出BeginPaint(),EndPaint()和GetDC(),ReleaseDC()的区别.前一对只能用在WM_PAINT响 应函数中,并且绘制背景时不会被抹掉;后一对随处可用,但如果用在WM_PAINT响应函数中,那么接下来将会被WM_ERASEBKGND消息的响应函 数的背景绘制给抹掉.
6 v( k5 u* R  u; V$ O, W; C7 j
) V' B3 L; c$ h- |5 z5 S 2.绘图闪烁问题     
5 I" k! z( K, c3 R     3 j  B2 z/ `4 b
     有时候我们大量绘制屏幕时,可能会出现屏幕闪烁问题,这时候可以采用双缓冲的做法.步骤首先是创建一个内存 DC,然后往内存DC中绘图,最后把内存DC的内容 复制到显示DC中,完成绘制.具体过程并不复杂,结合代码来说明一下. % @) R; w( Z( ^* ?  /( r: e* T
     PS:这段代码也是相应WM_PAINT 消息的.

 

1 O1 ~  {" ]/ _1 u1 z! n& U% j

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值