首先說一下產生閃爍的原因,當窗口由於任何原因需要重繪時,總是先用背景色或背景圖象將顯示區清除,然後才顯示圖象,這樣在短時間內背景色與顯示圖形交替出現,使得顯示窗口看起來在閃。如果將背景刷設置成NULL,這樣無論怎樣重繪圖形都不會閃了,但是會使得窗口的顯示亂成一團,因為重繪時沒有背景色對原來繪制的圖形進行清除,而又疊加上了新的圖形。
一般的解決方法就是采用雙緩沖,創建一幅內存圖象,把背景和圖片先繪制到該圖象,然後把繪制好的該圖象顯示到窗口,這樣就不會產生閃爍,其實就是隱藏了圖象的顯示過程,原來是在前台,給你看到先在畫布上刷上背景,再畫上圖象,現在是在後台畫好了再拿出來給你看。
看起來好象解決方法是需要一次性繪制好圖象,其實關鍵是不能讓任何背景及圖片在繪制時產生重疊,跟是否一次性繪制沒多大關系。電腦的繪制速度還是很快的,不信可以試試把背景刷設置成NULL,這樣不會閃爍,然後循環調用BitBlt把一幅小圖片鋪滿整個窗口,雖然是多次繪制,一樣不會閃爍,但是如果改變一下循環步長,讓圖片產生重疊,就會開始閃爍了。
知道了閃爍的原因,不用雙緩沖的解決辦法就不難找到了,調用ExcludeClipRect,可以排除掉繪制區域,先繪制圖片,ExcludeClipRect掉圖片的區域,再繪制背景,相當於把一幅挖了一個洞的畫布貼到窗口,這樣不產生繪制重疊部分,就不會產生閃爍了。
API代碼,始終在窗口右下角顯示一幅300*200的圖片,窗口背景為黑色:
case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rc;
HDC hMemDC;
GetClIEntRect(hWnd,&rc);
BeginPaint(hWnd,&ps);
hMemDC = CreateCompatibleDC(ps.hdc);
SelectObject(hMemDC,hbmp);
BitBlt(ps.hdc,rc.right-300,rc.bottom-200,300,200,hMemDC,0,0,SRCCOPY);
ExcludeClipRect(ps.hdc,rc.right-300,rc.bottom-200,rc.right,rc.bottom);
FillRect(ps.hdc,&rc,(HBRUSH)GetStockObject(BLACK_BRUSH));
DeleteDC(hMemDC);
EndPaint(m_hWnd,&ps);
return 0;
}
有時候因為刷新區域的問題,可能調整窗口但是WM_PAINT的代碼不起作用,這時需要響應WM_SIZE消息,通知畫面更新一下:
case WM_SIZE:
InvalidateRect(hWnd,NULL,FALSE);
break;
對於顯示多幅圖象,這個方法也是適用的,只要每繪制完一幅圖象,ExcludeClipRect掉該圖象區域就可以,但是注意如果圖象有重疊,繪制順序是反過來的,即蓋在最上面的圖象需要最先繪制,最後給整個窗口刷上背景就OK了。