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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章