第一種情況顯示出來的字很正常。 #
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);
break;
第二種情況顯示
的字不停閃爍。
case
WM_PAINT:
gdc =
GetDC (hwnd); -
R% s* c( p$ M( g
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催促你畫,導致程序卡死。3 Y1 F7 _+ k: @ l
無效區域 :0 D; B) `$ K3 d* k%
q( a' f
無
效區域就是指需要重畫的區域,無效的意思是:當前內容是舊的,過時的。
假設A是新彈出的一個對話框或被
激活的現有對話框,A對話框置於原來的活動
對話框B前面,造成對話框B的部分或全部被覆蓋,當
對話框A移開或關閉後,使對話框B原來被覆蓋的地方重新可見。那部分被覆蓋的地方就稱爲無效區域。
只
有當一個窗口消息空閒時,系統纔會抽空檢查一下這個窗口的無效區域是否爲非空(WM_PAINT的優先級是最低的。這也就是爲什麼系統很忙時窗口和桌面往
往會出現變白、刷新不了、留拖拽痕跡等現象的原因),如果非空,系統就發送WM_PAINT。所以一定要用BeginPaint、EndPaint把無效
區域設爲空,否則WM_PAINT將一直被髮送。% {: E2 S/ S3 K/ W# E6 C$ p O
爲什麼WINDOWS要提出無效區域的
概念?
這是爲了加速。
因爲BeginPaint和EndPaint
用到的設備描述符只會在當前的無效區域內繪畫,在有效區域內的繪畫會自動
被過濾,大家都知道,WIN
GDI的繪畫速度是比較慢的,所以能節省一個象素就節省一個,不用吝嗇,這樣可以有效加快繪畫速度。
可見BeginPaint、
EndPaint是比較“被動”的,只在窗口新建時和被摧殘時才重畫。 3 J4 i+ /! F X+ Z
而GetDC用於主動繪製,只要你指到哪,它就打到哪。它不加判斷就都畫上去,無效區域跟它沒關係。對話框沒被覆蓋沒被摧殘,它很健康,系統沒要求它重
畫,但開發者有些情況下需要它主動重畫:比如一個定時換外觀的窗口,這時候就要在WM_TIMER處理代碼
用GetDC。這時候再用BeginPaint、
EndPaint的話,會因爲無效區域爲空,所有繪畫操作都將被過濾掉。
/////////////////////////
下面是更加詳細的介紹
//========================================================================
//TITLE: ; m( G8 ]8 e5 e) E.
}& o
// EVC繪製位圖--BeginPaint()與GetDC()的區別
//AUTHOR:
//
norains
//========================================================================
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消息的響應函
數的背景繪製給抹掉.
2.繪圖閃爍問題
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