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