在图形图形处理过程中,双缓冲是一项基本的技术。我们都知道,如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,由于窗体在频繁的用背景色来擦除原有图形,引起了很大的视觉反差。从而引起了闪烁。解决这一问题的有效方法就是双缓冲技术。
窗体在刷新时,总要有一个擦除原来图像的过程。虚函数OnEraseBkgnd利用背景色填充窗体绘图区,然后再调用新的绘图代码进行重绘,这样擦除再重绘的过程就引起了视觉上的反差。
既然是因为背景色擦除图像引起的闪烁,那么我们就把背景色删除,但是这样的话再重绘时,原来的图形没有擦除,再添加上新的图形,这样看起来更乱了。所以只是去掉背景色还是不够的。到这里我们想到用位图来直接覆盖视区,在这个位图上绘制图形。把一个位图拷贝到视区中显示,有一个BitBlt函数,因为是整个内存块的复制,所以速度很快。
我们来做一个比较看看。。。。。。。
1,新建一个名为DBB的单文档程序,在视类中添加
CDC m_dcMem; // 内存DC
CBitmap m_bmp; // 内存DC中的位图
int m_nRadius; // 位图上要画的圆的半径
enum STATE_DRAW // 选择的绘制方式
{
STATE_NONE, // 为选择绘制模式
STATE_NORMAL, // 选择了普通的绘制模式
STATE_DBB // 选择了双缓冲绘制模式
};
STATE_DRAW m_stateDraw;
void OnDrawNormal();
void OnDrawDbb();
2,我们在创建完程序后,第一个执行的函数OnInitialUpdate()中添加如下代码:
CRect rc;
GetClientRect(&rc);
// 为屏幕DC创建兼容的内存DC
if (!m_dcMem.CreateCompatibleDC(NULL))
::PostQuitMessage(0);
// 创建兼容位图
m_bmp.CreateCompatibleBitmap(&m_dcMem, rc.Width(), rc.Height());
m_dcMem.SelectObject(&m_bmp);
SetTimer(1, 100, 0);
//我们要在OnTimer中重绘圆,使其一直刷新,普通的绘制方式会出现明显的闪烁的现象。
//而双缓冲的闪烁现象很不明显
3,定义上面定义的两个函数
void CDBBView::OnDrawNormal()
{
CDC *pDC = GetDC();
CRect rc;
GetClientRect(&rc);
// 用白色填充
pDC->FillSolidRect(&rc, 0x00FFFFFF);
for (int i = 0; i < rc.Width() - 1; i += 16)
{
for (int j = 0; j < rc.Height() - 1; j += 16)
{
pDC->Ellipse(i, j, i + m_nRadius, j + m_nRadius);
}
}
ReleaseDC(pDC);
}
void CDBBView::OnDrawDbb()
{
CDC *pDC = GetDC();
CRect rc;
GetClientRect(&rc);
m_dcMem.FillSolidRect(&rc, 0x00FFFFFF);
// 画圆
for(int i = 0; i < rc.Width() - 1; i+= 16)
{
for(int j = 0; j < rc.Height() - 1; j+= 16)
{
m_dcMem.Ellipse(i, j, i + m_nRadius, j + m_nRadius);
}
}
// 一次性的将内存设备环境上绘制完毕的图形"贴"到屏幕上
pDC->BitBlt(0, 0, rc.Width(), rc.Height(), &m_dcMem, 0, 0, SRCCOPY);
ReleaseDC(pDC);
}
我们添加两个菜单,用来选择是用普通绘制方式还是用双缓冲绘制方式绘图。
IDM_NORMAL 普通绘制
IDM_DBB 双缓冲绘制
在视类中添加消息响应,响应代码如下:
void CDBBView::OnNormal()
{
// TODO: Add your command handler code here
m_stateDraw = STATE_NORMAL;
}
void CDBBView::OnDbb()
{
// TODO: Add your command handler code here
m_stateDraw = STATE_DBB;
}
void CDBBView::OnUpdateNormal(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->SetCheck(STATE_NORMAL == m_stateDraw);
}
void CDBBView::OnUpdateDbb(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->SetCheck(STATE_DBB == m_stateDraw);
}
好了,现在添加OnTimer()函数,来处理画圆的动作。具体代码如下:
void CDBBView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
if (STATE_NONE == m_stateDraw)
{
CView::OnTimer(nIDEvent);
return;
}
if (m_nRadius < 16)
++m_nRadius;
else
m_nRadius = 0;
if (STATE_NORMAL == m_stateDraw)
OnDrawNormal();
else if (STATE_DBB == m_stateDraw)
OnDrawDbb();
CView::OnTimer(nIDEvent);
}
自己试试,在用普通绘制方式时会出现明显的闪烁现象,在使用双缓冲绘制方式时基本上没有闪烁显现。
哎,转帖的别人的贴,写的语句不通,呵呵,凑合着看吧,有想要源码的联系我。。。。。。。。