Win32双缓冲绘图和位图的绘制

最后都变了- 提交于 2019-12-10 15:01:10
前言:

为什么需要使用双缓冲技术?可能很多朋友会问,不知道你们有没有发现,当屏幕刷新的时候会有闪烁,这样让人的体验感极差。原因是绘图与显示器刷新不同步,有时间差,为解决这一问题,这就需要用到双缓冲技术来绘图了。双缓冲技术是相对单缓冲而言的,单缓冲就是直接在设备DC上绘图;而双缓冲就是先在一个与设备DC相兼容的内存缓冲区里进行绘图,然后再一次性复制到设备DC上。一次性在屏幕上显示就不会出现闪烁的现象。

这里需要注意的是:我们创建的兼容DC,不能直接在上面绘图,这里还需要一块画布,那我们创建的兼容DC就相当于画板,有了画板、画布,将画布选放在画板兼容DC上就可以进行绘图了。然后一次性贴在设备DC上就搞定了。如下:

HDC mdc=CreateComatibleDC(hdc);   // 创建兼容DC 画板
HBITMAP bmp=CreatrCompatibleBitnap(hdc,600,600);   // 创建画布
SelectObject(mdc,bmp);   //  将画布选入画板

一、双缓冲技术的使用

双缓冲绘图步骤:

  1. 在内存中创建兼容DC缓冲区(依次包括创建兼容DCCreateComatibleDC、创建画布CreatrCompatibleBitnap、将画布选入SelectObject)。
  2. 在缓冲区进行画图操作(可以画图形、也可以贴位图)。
  3. 将兼容缓冲区一次性复制到设备DC上。(复制用Bitblt函数)
  4. 释放内存缓冲区。(DeleteDC函数)

几个关键API函数:

CreateCompatibleDC:
该函数创建一个与指定设备兼容的内存设备上下文环境(DC)

 HDC CreateCompatibleDC(HDC hdc)

CreateCompatibleBitmap:
该函数创建与指定的设备环境相关的设备兼容的位图.

HBITMAP CreateCompatibleBitmap(HDC hdc,  
                               int nWidth,   // 定位图的宽度,单位为像素
                               int nHeight)// 指定位图的高度,单位为像素

BitBlt:
BitBlt是一个计算机函数,该函数对指定的源设备环境区域中的像素进行位块(bit_block)转换,以传送到目标设备环境.

BOOL BitBlt(  _In_  HDC hdcDest, 
              _In_  int nXDest,  // 指定目标矩形区域左上角的X轴逻辑坐标
              _In_  int nYDest,  // 指定目标矩形区域左上角的Y轴逻辑坐标
              _In_  int nWidth,  // 指定源在目标矩形区域的逻辑宽度
              _In_  int nHeight, // 指定源在目标矩形区域的逻辑高度
              _In_  HDC hdcSrc,  // 指向源设备环境的句柄
              _In_  int nXSrc,   // 指定源矩形区域左上角的X轴逻辑坐标
              _In_  int nYSrc,   // 指定源矩形区域左上角的Y轴逻辑坐标
              _In_  DWORD dwRop); //指定光栅操作代码。这些代码将定义源矩形区域的颜色数据,如何与目标矩形区域的颜色数据组合以完成最后的颜色。

单双缓冲技术操作对比:

单缓冲技术绘制两个矩形:

// 直接在设备DC上绘制
Rectangle(hdc, 100, 100, 200, 200);
Rectangle(hdc, 300, 300, 200, 200);

双缓冲技术绘制两个矩形:

// 1.创建兼容缓冲区
mdc = CreateCompatibleDC(hdc);   // 创建兼容DC
bmp = CreateCompatibleBitmap(hdc, 600, 600);   // 创建兼容位图画布
SelectObject(mdc, bmp);    // 选入

// 2.在缓冲区绘制 
Rectangle(mdc, 100, 100, 200, 200);
Rectangle(mdc, 300, 300, 200, 200);

// 3.一次性复制到设备DC
BitBlt(hdc, 0, 0, 500, 500, mdc, 0, 0, SRCCOPY);
 
// 4.释放缓冲区DC
DeleteDC(mdc);

二、绘制位图

绘制位图步骤:

  1. 创建兼容DC(CreateCopatibleDC函数)
  2. 加载位图(LoadImage函数和LoadBitmap函数)
  3. 选取位图对象,使用BitBlt函数进行贴图(SelectObject函数)
  4. 释放兼容DC(DeleteDC函数)

加载位图API函数:
第一种 :LoadImage
LoadImage是一种函数,功能是装载图标,光标,或位图。

HANDLE LoadImage(HINSTANCE hinst,// 处理包含被装载图像模块的实例句柄。若要装载OEM图像,则设此参数值为0。
                  LPCTSTR lpszName,// 图像资源名称
                  UINT uType,   // 指定被装载图像类型,IMAGE_BITMAP:装载位图;IMAGE_CURSOR:装载光标;IMAGE_ICON:装载图标。
                  int cxDesired,// 指定图标或光标的宽度,以像素为单位
                  int cyDesired,// 指定图标或光标的高度,以像素为单位
                  UINT fuLoad);// 加载标识,含义见链接

第二种 :LoadBitmap
该函数从模块的可执行文件中加载指定的位图资源,该函数已经被函数LoadImage替代。

HBITMAP LoadBitmap(HINSTANCE hInstance, LPCTSTR lpBitmapName)

注意: 在内存DC上绘制位图时也需要创建一个与窗口DC兼容的内存DC(maphdc),还需要一个HBITMAP map来加载位图,然后选用位图对象( SelectObject(maphdc,map)与之前画笔画刷选取一样),最后用BitBlt函数将位图贴入内存DC上。
上面所说的BitBlt函数是指在内存DC上贴位图,其中包括在设备DC和双缓冲技术的缓冲DC.在双缓冲技术绘制位图时,需要特别注意的是:兼容DC我们创建了两个(mdc和maphdc),mdc是真正的缓冲区(开始将所有图形位图都绘制在这个缓冲DC中),而maphdc是在选取位图时用的,会有很多人理解错,我开始学的时候也有点。HBITMAP 我们也声明了两个(bmp和map),bmp是mdc的画布(需要用CreateCompatibleBitmap来创建),而map只是用来加载位图的。以下做个对比说明:

单缓冲绘制位图:
// 1.创建兼容DC
maphdc = CreateCompatibleDC(hdc);

// 2.加载位图
HBITMAP map = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP1), IMAGE_BITMAP, 500, 500, LR_CREATEDIBSECTION);

// 3.选取位图对象,使用BitBlt函数贴图
SelectObject(maphdc, map);
BitBlt(hdc, 0, 0, 1500, 1500, maphdc, 0, 0, SRCCOPY);

// 4.释放兼容DC
DeleteDC(maphdc);

双缓冲绘制位图:
// 1.创建兼容缓冲区
mdc = CreateCompatibleDC(hdc);   // 创建兼容DC
bmp = CreateCompatibleBitmap(hdc, 600, 600);   // 创建兼容位图画布
SelectObject(mdc, bmp);    // 选入

// 2.在缓冲区绘制 

maphdc = CreateCompatibleDC(hdc); /*创建兼容DC*/
      
/*贴第一张位图*/
HBITMAP map = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP1), IMAGE_BITMAP, 500, 500, LR_CREATEDIBSECTION);
SelectObject(maphdc, map);
BitBlt(mdc, 0, 0, 500, 500, maphdc, 0, 0, SRCCOPY);
      /*贴第二张位图*/
HBITMAP map = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP1), IMAGE_BITMAP, 500, 500, LR_CREATEDIBSECTION);
SelectObject(maphdc, map);
BitBlt(mdc, 0, 0, 500, 500, maphdc, 0, 0, SRCCOPY);
       
DeleteDC(maphdc);  /*释放兼容DC*/
      
// 3.一次性复制到设备DC
BitBlt(hdc, 0, 0, 500, 500, mdc, 0, 0, SRCCOPY);
 
// 4.释放缓冲区DC
DeleteDC(mdc); 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!