Chapter I: ExcludeClipRect在一個剪切區域排除一個矩形,導緻繪制該剪切區域時,不繪制該矩形.
ExcludeClipRect函數詳情請參考MSDN,這個函數用于排除一個區域的一部分,常用于繪制圖畫,例如,在一個視窗的客戶區繪制一幅圖檔,如下面代碼所示:
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
RECT rc = {0};
GetClientRect (hWnd, &rc) ;
HDC hMemDC = CreateCompatibleDC(ps.hdc);
SelectObject(hMemDC, g_hBmpAllWstDskWallpaper);//選擇位圖
//ExcludeClipRect(ps.hdc,0,0,200,100); //排除部分區域. A line
BitBlt(ps.hdc,0,0,300,200,hMemDC,0,0,SRCCOPY);
DeleteDC(hMemDC);
EndPaint(hWnd,&ps);
}
客戶區,但是矩形區域{0, 0, 200, 100}顯示的仍然是視窗的背景色,換句話說,位圖缺了這一塊.這是因為ExcludeClipRect将{0, 0, 200, 100}矩形從視窗剪切區域
Chaper II: ExcludeClipRect函數不釋放排除的矩形區域
将Chapter I代碼中的A行改為:
BOOL g_bCall = TRUE;//全局變量.
if (g_bCall)
g_bCall = FALSE;
ExcludeClipRect(ps.hdc,0,0,200,100); //排除部分區域,僅調用一次. A line
該DC上繪制,那麼有沒有什麼辦法恢複該區域呢? 其實很簡單,将那塊被"Exclude"掉的矩形區域再"找回來"就行了.辦法就是程式再建立一個剪切區域,使其大小和位置
#define RECT_WIDTH(rt) (rt.right-rt.left)
#define RECT_HEIGHT(rt) (rt.bottom-rt.top)
RECT g_rcExclud = {0};
BOOL g_bCancelExcludeRect = FALSE;
// "exclud"掉的區域在右下角.
g_rcExclud.left = rc.right-200;
g_rcExclud.top = rc.bottom-100;
g_rcExclud.right = rc.right;
g_rcExclud.bottom = rc.bottom;
HRGN hrgn = NULL; // 将上次"exclud"掉的區域填補回來.
if (g_bCancelExcludeRect && RECT_WIDTH(g_rcExclud) && RECT_HEIGHT(g_rcExclud))
{
hrgn = CreateRectRgn(g_rcExclud.left, g_rcExclud.top, g_rcExclud.right, g_rcExclud.bottom);
ExtSelectClipRgn(ps.hdc, hrgn, RGN_OR);
FillRect(ps.hdc,&g_rcExclud,(HBRUSH)GetStockObject(COLOR_WINDOW));//擦除上次繪制的圖檔區域.
}
(!g_bCancelExcludeRect) //"exclud"掉視窗右下角區域.
ExcludeClipRect(ps.hdc,g_rcExclud.left, g_rcExclud.top, RECT_WIDTH(g_rcExclud), RECT_HEIGHT(g_rcExclud));
BitBlt(ps.hdc,0,0,400,300,hMemDC,0,0,SRCCOPY);//在右下角繪制一個位圖.
if (hrgn != NULL) DeleteObject(hrgn);
Chapter III: 使用ExcludeClipRect實作無閃爍圖像
有網友寫過相關文章:http://dev.10086.cn/cmdn/wiki/index.php?edition-view-6349-1.html
而"exclude"掉的區域是不會被背景擦除的.
而且這篇文章還有一個地方沒有說清楚,那就是解決圖像閃爍的辦法其實是不用擦除視窗背景,而繪制視窗前景色,圖像區域用位圖繪制,其它區域用視窗背景色繪制,
hdc = BeginPaint(hWnd, &ps);
RECT rc = {0};
GetClientRect (hWnd, &rc) ;
HDC hMemDC = CreateCompatibleDC(ps.hdc);
SelectObject(hMemDC, g_hBmpAllWstDskWallpaper);
HRGN hrgn = NULL;
if (RECT_WIDTH(g_rcExclud) && RECT_HEIGHT(g_rcExclud))
{
hrgn = CreateRectRgn(g_rcExclud.left, g_rcExclud.top, g_rcExclud.right, g_rcExclud.bottom);
ExtSelectClipRgn(ps.hdc, hrgn, RGN_OR);//恢複上次被"excude"掉的區域,必須的,否則這一部分不會被繪制.
FillRect(ps.hdc,&g_rcExclud,(HBRUSH)GetStockObject(COLOR_WINDOW));//擦除上次繪制的圖檔區域.
}
g_rcExclud.left = rc.right-300;
g_rcExclud.top = rc.bottom-200;
g_rcExclud.right = rc.right;
g_rcExclud.bottom = rc.bottom;
BitBlt(ps.hdc,g_rcExclud.left,g_rcExclud.top,g_rcExclud.right-g_rcExclud.left,g_rcExclud.bottom-g_rcExclud.top,hMemDC,0,0,SRCCOPY);
ExcludeClipRect(ps.hdc,g_rcExclud.left,g_rcExclud.top, g_rcExclud.right, g_rcExclud.bottom);//排除掉圖像所占據的區域
FillRect(ps.hdc,&rc,(HBRUSH)GetStockObject(COLOR_WINDOW));// 用視窗背景色繪制其餘區域.
DeleteObject(hrgn);
DeleteDC (hMemDC) ; //釋放記憶體裝置環境
EndPaint(hWnd, &ps);
return 0;
break;
case WM_SIZE:
InvalidateRect(hWnd, NULL, FALSE);//最後一個參數為FALSE,表示不用擦除背景.
最後,改變視窗的大小,觀察一下這幅圖檔,始終在視窗右下角,而且圖檔的确不再閃爍.
本文轉自jetyi51CTO部落格,原文連結:http://blog.51cto.com/jetyi/642401 ,如需轉載請自行聯系原作者