天天看點

ExcludeClipRect和無閃爍圖像

 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 ,如需轉載請自行聯系原作者

繼續閱讀