MFC双缓冲简介

发布时间 2023-07-18 15:52:39作者: 左边的翼

一、MFC为什么要实现双缓冲

  在MFC界面绘图中,时常会遇到界面闪烁问题,尤其是在绘图不断更新的过程中,原因是“旧”图像还没擦除,“新”图像已经绘制,附加显示器刷新率及肉眼等问题,造成图像闪烁,给用户体验降低;在该条件下,需要通过双缓冲机制进行,关于闪烁的具体解释可参考https://en.wikipedia.org/wiki/Multiple_buffering。下面是MFC在没有双缓冲条件下的代码效果:

  1、启动计时器

 1 SetTimer(1, 50, NULL); 

  2、计时器事件处理

1 void CMFCPaintingDlg::OnTimer(UINT_PTR nIDEvent)
2 {
3     Invalidate();
4     CDialogEx::OnTimer(nIDEvent);
5 }

  3、窗体WM_PAINT事件

static int value = 0;
void CMFCPaintingDlg::OnPaint()
{
    CPaintDC dc(this);
    Graphics graphics(dc);
    graphics.SetSmoothingMode(SmoothingModeHighQuality);
    value += 5;
    DrawTJGraph(graphics, value);
    CDialogEx::OnPaint();
}

   4、功能函数实现

void CMFCPaintingDlg::DrawTJGraph(Graphics & graphics, int rotateValue)
{
    CRect rect;
    CPoint pt;
    int r=200;
    GetClientRect(&rect);
    graphics.TranslateTransform(rect.Width()/2, rect.Height()/2);
    graphics.RotateTransform(rotateValue);

    graphics.FillPie(&SolidBrush(Color(255, 255, 255)), -r / 2, -r / 2, r, r, 90, 180);
    graphics.FillPie(&SolidBrush(Color(0, 0, 0)), -r / 2, -r / 2, r, r, -90, 180);

    graphics.FillEllipse(&SolidBrush(Color(255, 255, 255)), -r / 4, -r / 2, r / 2, r / 2);
    graphics.FillEllipse(&SolidBrush(Color(0, 0, 0)), -r / 4, 0, r / 2, r / 2);

    graphics.FillEllipse(&SolidBrush(Color(0, 0, 0)), -r / 8, -3 * r / 8, r / 4, r / 4);
    graphics.FillEllipse(&SolidBrush(Color(255, 255, 255)), -r / 8, r / 8, r / 4, r / 4);
}

二、MFC中实现双缓冲绘图

  代码效果如下所示:

  1、变量定义

CDC MemDCIndicator;
CBitmap MemBitmapIndicator;
CDC *pDC;

   2、启动定时器

 1 SetTimer(1, 50, NULL); 

  3、定时器时间处理

 1 static int value = 0;
 2 void DoubleBufferDlg::OnTimer(UINT_PTR nIDEvent)
 3 {
 4     value += 5;
 5     CRect rt;
 6     GetClientRect(&rt);
 7     pDC = GetDC();
 8     //创建内存中的显示设备
 9     MemDCIndicator.CreateCompatibleDC(pDC);
10     //创建内存中的图像
11     MemBitmapIndicator.CreateCompatibleBitmap(pDC, rt.Width(), rt.Height());
12     //指定内存显示设备在内存图像上画图
13     MemDCIndicator.SelectObject(&MemBitmapIndicator);
14     //初始化绘图背景
15     MemDCIndicator.FillSolidRect(rt, RGB(100, 100, 100));
16     //功能函数
17     DrawTJGraph(MemDCIndicator, value);
18     //将内存中图像呈现
19     pDC->BitBlt(rt.left, rt.top, rt.Width(), rt.Height(), &MemDCIndicator, 0, 0, SRCCOPY);
20     //释放资源
21     MemDCIndicator.DeleteDC();
22     MemBitmapIndicator.DeleteObject();
23     ReleaseDC(pDC);
24     CDialogEx::OnTimer(nIDEvent);
25 }

  4、功能函数

 1 void DoubleBufferDlg::DrawTJGraph(CDC & dc, int rotateValue)
 2 {
 3     Graphics graphics(dc);
 4     graphics.SetSmoothingMode(SmoothingModeHighQuality);
 5     CRect rect;
 6     int r = 200;
 7     GetClientRect(&rect);
 8     graphics.TranslateTransform(rect.Width() / 2, rect.Height() / 2);
 9     graphics.RotateTransform(rotateValue);
10 
11     graphics.FillPie(&SolidBrush(Color(255, 255, 255)), -r / 2, -r / 2, r, r, 90, 180);
12     graphics.FillPie(&SolidBrush(Color(0, 0, 0)), -r / 2, -r / 2, r, r, -90, 180);
13 
14     graphics.FillEllipse(&SolidBrush(Color(255, 255, 255)), -r / 4, -r / 2, r / 2, r / 2);
15     graphics.FillEllipse(&SolidBrush(Color(0, 0, 0)), -r / 4, 0, r / 2, r / 2);
16 
17     graphics.FillEllipse(&SolidBrush(Color(0, 0, 0)), -r / 8, -3 * r / 8, r / 4, r / 4);
18     graphics.FillEllipse(&SolidBrush(Color(255, 255, 255)), -r / 8, r / 8, r / 4, r / 4);
19 }