Windows C 程序实现双缓冲

    前期总结了一下C#里怎样实现双缓冲,这次写写如何用Windows C程序实现双缓冲。我对Windows C程序也不是很精通,菜鸟一个,在这里写的也只能算是我的个人笔记而已。
    网上有许多文章讲述了如何使用Visual C++程序实现双缓冲,都是用C++面向对象语言写的,可能对很多没有接触过面向对象语言的C语言初学者来说理解起来有些困难,并且有些好心人也只是把源代码贴上去,不做注释,这就使读者读起来更费劲了。
    在这里,我会就每一条语句作出解释。其中有一个地方比较有趣,值得讨论(见下文)。好了,我们首先看一下双缓冲的基本原理:

一、双缓冲原理及图解

Windows <wbr>C <wbr>程序实现双缓冲

(1)定义设备描述表及位图句柄
    HDC hMemDC;
    HBITMAP hBitmap;
(2)创建一个与窗口矩形显示兼容的内存显示设备描述表,如图所示1步骤
    hMemDC = CreateCompatibleDC(hDC);
(3)用hdc创建一个与窗口矩形显示兼容的位图,如图所示2步骤
    hBitmap = CreateCompatibleBitmap(hDC, rt.right - rt.left, rt.bottom - rt.top);//rt为RECT变量,值为窗口矩形
(4)将位图hBitmap选入到内存显示设备hDCMem中,只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上,如图所示3步骤
    SelectObject(hMemDC, hBitmap);
(5)用hdc背景色将位图清除干净,如图所示4步骤
     FillRect(hDCMem, &rt, hBrush)
(6)绘图,如图所示5步骤
    DrawCircle(&hDCMem, rt, radius)
(7)将内存中的图拷贝到窗口矩形上进行显示,如图所示6步骤
    BitBlt(hdc, 0, 0, rt.right - rt.left, rt.bottom - rt.top, hDCMem, 0, 0, SRCCOPY)
二、例子程序

例子程序来源于网上http://www.vckbase.com/document/viewdoc/?id=1612,设定一个时钟,在窗口矩形中绘制很多半径渐变的圆。你可以通过菜单来选择双缓冲或正常绘制模式。
在WM_CREATE中添加代码:
case WM_CREATE:
   SetTimer(hWnd, ID_TIMER, 150, NULL);
   CheckMenuItem(GetMenu(hWnd), IDM_NORMAL, MF_CHECKED);
   break;

 

在WM_TIMERR中添加代码:
case WM_TIMER:
   if(radius < 10)
   {
    radius++;
   }
   else
   {
    radius = 0;
   }
//注意第三个参数,这里设定为FALSE,表示在刷新窗口矩形是不擦除窗口背景,因此,在WM_PAINT消息中需

//要加入FillRect(hdc, &rt, hBrush),用来擦除上一次所画的东西    

  InvalidateRect(hWnd, NULL, FALSE);   

  break;

 

在WM_PAINT中添加代码:
case WM_PAINT:
   hdc = BeginPaint(hWnd, &ps);//窗口矩形设备描述表
   // TODO: Add any drawing code here...
   RECT rt;//定义矩形变量
   GetClientRect(hWnd, &rt);//对矩形变量赋值为窗口矩形
   //定义设备描述表及位图句柄
   HDC hDCMem;
   HBITMAP hBitmap;
   //定义画笔和画刷
   HPEN hPen;
   HBRUSH hBrush;
   //创建颜色为hdc(窗口矩形)背景色的实画刷
   hBrush = CreateSolidBrush(GetBkColor(hdc));
   //创建颜色为红色,宽度为1的实画笔
   hPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));

   
   if(!fDoubleBuffer)//非双缓冲模式
   {
    SelectObject(hdc, hPen);//将画笔选入hdc
    FillRect(hdc, &rt, hBrush);//用画刷把上一次所画的东西擦干净
    DrawCircle(&hdc, rt, radius);//绘图
   }
   else//双缓冲模式
   {
    //创建一个与窗口矩形显示兼容的内存显示设备描述表
    hDCMem = CreateCompatibleDC(hdc);
    //用hdc创建一个与窗口矩形显示兼容的位图
    hBitmap = CreateCompatibleBitmap(hdc, rt.right - rt.left, rt.bottom - rt.top);//使用这条语句,绘制出来的图形是hPen的颜色--红色
   // hBitmap = CreateCompatibleBitmap(hDCMem, rt.right - rt.left, rt.bottom - rt.top);//使用这条语句,绘制出来的图形并不是hPen的颜色--红色,这是有趣的地方,也是要注意的地方      
    //上述两条语句都可以实现创建与窗口矩形显示兼容的位图,且都能实现双缓冲技术,关键是在这个画笔的使用便捷性上存在差异,我个人觉得还是使用第一种方式更好 
 
    SelectObject(hDCMem, hPen);//将在hdc下创建的画笔选入hDCMem
    SelectObject(hDCMem, hBitmap);//将在hdc下创建的位图hBitmap选入到内存显示设备hDCMem中
    FillRect(hDCMem, &rt, hBrush);//用画刷把上一次所画的东西擦干净
    DrawCircle(&hDCMem, rt, radius);//绘图
    //将内存中的图拷贝到窗口矩形上进行显示
    BitBlt(hdc, 0, 0, rt.right - rt.left, rt.bottom - rt.top, hDCMem, 0, 0, SRCCOPY);
   }
   //删除资源
   DeleteObject(hBitmap);
   DeleteDC(hDCMem);
   DeleteObject(hPen);

   EndPaint(hWnd, &ps);
   break;


处理菜单消息:
case IDM_DOUBLEBUFFER:
     fDoubleBuffer = TRUE;
     CheckMenuItem(GetMenu(hWnd), IDM_NORMAL, MF_UNCHECKED);
     CheckMenuItem(GetMenu(hWnd), IDM_DOUBLEBUFFER, MF_CHECKED);
     break;
case IDM_NORMAL:
     fDoubleBuffer = FALSE;
     CheckMenuItem(GetMenu(hWnd), IDM_DOUBLEBUFFER, MF_UNCHECKED);
     CheckMenuItem(GetMenu(hWnd), IDM_NORMAL, MF_CHECKED);
     break;


绘图函数:
void DrawCircle(HDC *hdc, RECT rt, int radius)
{
 for(int i = 0; i < rt.right - rt.left - 1; i+= 10)
 {
  for(int j = 0; j < rt.bottom - rt.top - 1; j+= 10)
  {
   Ellipse(*hdc, i, j, i + radius, j + radius);
  }
 }
}

例子源码下载:http://www.pudn.com/downloads238/sourcecode/windows/detail1113620.html

 

你可能感兴趣的:(Windows C 程序实现双缓冲)