ExcludeClipRect和无闪烁图像

  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); 
客户区,但是矩形区域{0, 0, 200, 100}显示的仍然是窗口的背景色,换句话说,位图缺了这一块.这是因为ExcludeClipRect将{0, 0, 200, 100}矩形从窗口剪切区域
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 
该DC上绘制,那么有没有什么办法恢复该区域呢? 其实很简单,将那块被"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
而"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
最后,改变窗口的大小,观察一下这幅图片,始终在窗口右下角,而且图片的确不再闪烁.
 










本文转自jetyi51CTO博客,原文链接:http://blog.51cto.com/jetyi/642401  ,如需转载请自行联系原作者


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值