程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> ExcludeClipRect和無閃爍圖像

ExcludeClipRect和無閃爍圖像

編輯:關於C語言

 Chapter I: ExcludeClipRect在一個剪切區域排除一個矩形,導致繪制該剪切區域時,不繪制該矩形.   ExcludeClipRect函數詳情請參考MSDN,這個函數用於排除一個區域的一部分,常用於繪制圖畫,例如,在一個窗口的客戶區繪制一幅圖片,如下面代碼所示:

  1. case WM_PAINT: 
  2.     hdc = BeginPaint(hWnd, &ps); 
  3.     RECT rc = {0}; 
  4.     GetClientRect (hWnd, &rc) ; 
  5.     HDC hMemDC = CreateCompatibleDC(ps.hdc); 
  6.     SelectObject(hMemDC, g_hBmpAllWstDskWallpaper);//選擇位圖 
  7.  
  8.     //ExcludeClipRect(ps.hdc,0,0,200,100);  //排除部分區域. A line 
  9.     BitBlt(ps.hdc,0,0,300,200,hMemDC,0,0,SRCCOPY); 
  10.     DeleteDC(hMemDC); 
  11.     EndPaint(hWnd,&ps); 
這段代碼在窗口客戶區繪制一個位圖,這沒問題.但是注意一下A行,它是注釋掉的,然後去掉這個注釋,再次運行程序,可以觀察到,這個位圖雖然還是繪制在了窗口的客戶區,但是矩形區域{0, 0, 200, 100}顯示的仍然是窗口的背景色,換句話說,位圖缺了這一塊.這是因為ExcludeClipRect將{0, 0, 200, 100}矩形從窗口剪切區域排除掉了,這樣GDI是不會繪制這個矩形區域的. Chaper II: ExcludeClipRect函數不釋放排除的矩形區域   將Chapter I代碼中的A行改為:
  1. BOOL g_bCall = TRUE;//全局變量. 
  2. if (g_bCall) 
  3.     g_bCall = FALSE; 
  4.     ExcludeClipRect(ps.hdc,0,0,200,100); //排除部分區域,僅調用一次. A line 
再次運行程序,並改變窗口大小,可以發現,客戶區矩形區域{0, 0, 200, 100}始終不會被繪制.可見這個函數一旦被調用,那麼這個函數排除的矩形區域將永遠不會在該DC上繪制,那麼有沒有什麼辦法恢復該區域呢? 其實很簡單,將那塊被"Exclude"掉的矩形區域再"找回來"就行了.辦法就是程序再創建一個剪切區域,使其大小和位置和之前"Exclude"掉的相同,然後調用ExtSelectClipRgn,注意最後一個參數要使用RGN_OR,這表示合並兩個剪切區域.這樣就相當於找回了這個"Exclude"掉的矩形區域.下面是代碼:
  1. #define RECT_WIDTH(rt)      (rt.right-rt.left) 
  2. #define RECT_HEIGHT(rt)     (rt.bottom-rt.top) 
  3. RECT g_rcExclud = {0}; 
  4. BOOL g_bCancelExcludeRect = FALSE; 
  5. case WM_PAINT: 
  6.     hdc = BeginPaint(hWnd, &ps); 
  7.     RECT rc = {0}; 
  8.     GetClientRect (hWnd, &rc) ; 
  9.     HDC hMemDC = CreateCompatibleDC(ps.hdc); 
  10.     SelectObject(hMemDC, g_hBmpAllWstDskWallpaper);//選擇位圖 
  11.  
  12.     // "exclud"掉的區域在右下角. 
  13.     g_rcExclud.left = rc.right-200; 
  14.     g_rcExclud.top = rc.bottom-100; 
  15.     g_rcExclud.right = rc.right; 
  16.     g_rcExclud.bottom = rc.bottom; 
  17.  
  18.     HRGN hrgn = NULL;   // 將上次"exclud"掉的區域填補回來. 
  19.     if (g_bCancelExcludeRect && RECT_WIDTH(g_rcExclud) && RECT_HEIGHT(g_rcExclud)) 
  20.     { 
  21.         hrgn = CreateRectRgn(g_rcExclud.left, g_rcExclud.top, g_rcExclud.right, g_rcExclud.bottom); 
  22.         ExtSelectClipRgn(ps.hdc, hrgn, RGN_OR); 
  23.         FillRect(ps.hdc,&g_rcExclud,(HBRUSH)GetStockObject(COLOR_WINDOW));//擦除上次繪制的圖片區域. 
  24.     } 
  25.  
  26.     (!g_bCancelExcludeRect) //"exclud"掉窗口右下角區域. 
  27.         ExcludeClipRect(ps.hdc,g_rcExclud.left, g_rcExclud.top, RECT_WIDTH(g_rcExclud), RECT_HEIGHT(g_rcExclud)); 
  28.     BitBlt(ps.hdc,0,0,400,300,hMemDC,0,0,SRCCOPY);//在右下角繪制一個位圖. 
  29.  
  30.     DeleteDC(hMemDC); 
  31.     if (hrgn != NULL) DeleteObject(hrgn); 
  32.     EndPaint(hWnd,&ps); 
Chapter III: 使用ExcludeClipRect實現無閃爍圖像 有網友寫過相關文章:http://dev.10086.cn/cmdn/wiki/index.php?edition-view-6349-1.html 這篇文章些的不錯,不過還是有一個問題,就是Chapter II所提到的ExcludeClipRect不會釋放"exclude"掉的區域,這樣如果因為窗口大小的改變導致位圖位置的變化,而"exclude"掉的區域是不會被背景擦除的. 而且這篇文章還有一個地方沒有說清楚,那就是解決圖像閃爍的辦法其實是不用擦除窗口背景,而繪制窗口前景色,圖像區域用位圖繪制,其它區域用窗口背景色繪制,這相當於把一幅挖了一個洞(這個部分就是圖像,其它部分使用背景色繪制)的畫布貼到窗口,這樣不產生繪制重疊部分,下面是修改後的代碼:  
  1. case WM_PAINT: 
  2.     { 
  3.         hdc = BeginPaint(hWnd, &ps); 
  4.         RECT rc = {0}; 
  5.         GetClientRect (hWnd, &rc) ; 
  6.  
  7.         HDC hMemDC = CreateCompatibleDC(ps.hdc); 
  8.         SelectObject(hMemDC, g_hBmpAllWstDskWallpaper); 
  9.  
  10.         HRGN hrgn = NULL; 
  11.         if (RECT_WIDTH(g_rcExclud) && RECT_HEIGHT(g_rcExclud)) 
  12.         { 
  13.             hrgn = CreateRectRgn(g_rcExclud.left, g_rcExclud.top, g_rcExclud.right, g_rcExclud.bottom); 
  14.             ExtSelectClipRgn(ps.hdc, hrgn, RGN_OR);//恢復上次被"excude"掉的區域,必須的,否則這一部分不會被繪制. 
  15.             FillRect(ps.hdc,&g_rcExclud,(HBRUSH)GetStockObject(COLOR_WINDOW));//擦除上次繪制的圖片區域. 
  16.         } 
  17.  
  18.         g_rcExclud.left = rc.right-300; 
  19.         g_rcExclud.top = rc.bottom-200; 
  20.         g_rcExclud.right = rc.right; 
  21.         g_rcExclud.bottom = rc.bottom; 
  22.  
  23.         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); 
  24.         ExcludeClipRect(ps.hdc,g_rcExclud.left,g_rcExclud.top, g_rcExclud.right, g_rcExclud.bottom);//排除掉圖像所占據的區域 
  25.         FillRect(ps.hdc,&rc,(HBRUSH)GetStockObject(COLOR_WINDOW));// 用窗口背景色繪制其余區域. 
  26.  
  27.         DeleteObject(hrgn); 
  28.         DeleteDC (hMemDC) ;                      //釋放內存設備環境 
  29.         EndPaint(hWnd, &ps); 
  30.         return 0; 
  31.     } 
  32.     break; 
  33. case WM_SIZE: 
  34.     InvalidateRect(hWnd, NULL, FALSE);//最後一個參數為FALSE,表示不用擦除背景. 
  35.     break; 
最後,改變窗口的大小,觀察一下這幅圖片,始終在窗口右下角,而且圖片的確不再閃爍.  

 

本文出自 “零一小築” 博客,請務必保留此出處http://jetyi.blog.51cto.com/1460128/642401

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved