MFC双缓冲+提升绘图效率方法(号称三缓冲):自定义静态背景不频繁擦除(★firecat推荐★)

简介: MFC双缓冲+提升绘图效率方法(号称三缓冲):自定义静态背景不频繁擦除(★firecat推荐★)

应用场景是:绘制一个运动小球,在大屏幕滚动,屏幕背景图也是一个自定义绘制的(填充色,线条和文字等组成)。如图所示。红色是小球,在大背景里动态移动,而背景是静态的,静止不动。


image.png


1、MFC克服C++窗体重绘时的闪烁问题,用到的技巧是双缓冲。双缓冲原理网上的文章好多,这里不赘述。

//---------------------------------MFC双缓冲//---------------------------------
void CViewImage::OnPaint()
{
  CPaintDC dc(this); // device context for painting
        // TODO: 在此处添加消息处理程序代码
        // 不为绘图消息调用 CFormView::OnPaint()
  OnPrepareDC(&dc);
  OnDraw(&dc); //调用了OnDraw
}
void CViewImage::OnDraw(CDC *pDC)
{
  CDC dcMemory; //图形重绘,双缓冲防止闪屏
  CRect rect;
  GetClientRect(&rect);
  CBitmap bmp;
  dcMemory.CreateCompatibleDC(pDC);
  bmp.CreateCompatibleBitmap(pDC, rect.right, rect.bottom);
  CBitmap *pOldBitmap = dcMemory.SelectObject(&bmp);
  dcMemory.SetBkMode(TRANSPARENT);
  DrawBackgroundImage(&dcMemory);//绘制自定义背景图
  DrawBall(&dcMemory);//绘制小球
  pDC->BitBlt(rect.left, rect.top, rect.right, rect.bottom, &dcMemory, 0, 0, SRCCOPY);
  dcMemory.SelectObject(pOldBitmap);
  dcMemory.DeleteDC();
  bmp.DeleteObject();
}
BOOL CViewImage::OnEraseBkgnd(CDC* pDC)
{
  //Invalidate(FALSE)不擦除背景,直接画,它只会向消息队列中添加了WM_PAINT消息。
  //Invalidate(TRUE)擦除背景,它会向消息队列中添加了WM_ERASEBKGND和WM_PAINT两个消息。
  //可见:Invalidate(FALSE)不会清空之前所画图像。
  //如果你想用Invalidate(TRUE)来实现Invalidate(FALSE)一样的效果,
  //你可以添加对WM_ERASEBKGND消息响应的函数,
  //修改OnEraseBkgnd函数的返回值为:return TRUE;
  //返回值return TRUE就是不擦除背景,此时Invalidate(TRUE)与Invalidate(FALSE)的效果是一样的。
  return TRUE;//禁止背景重绘; true表示已处理背景刷新,false表示需要在OnPaint里处理
  //return CFormView::OnEraseBkgnd(pDC);
}


2、本文要解决的是提升绘图效率,不要让背景频繁擦除。本方法可以认为是MFC三缓冲绘图。(#^.^#)


在上面的源码OnDraw函数中,每次都需要绘制自定义背景图和小球图。每隔50毫秒通过Invalidate函数发送WM_PAINT消息刷新屏幕。但实际运行过程中发现,每次绘制自定义背景太占CPU(4%,4核CPU),有什么更好的办法吗?


办法就是不要每次都重绘背景图,因为它是静止不动的。于是想到将背景预先绘制到一个内存设备区域,然后在OnDraw中将该内存设备环境中的内容复制到当前的内存设备环境中。


方法1:画在已知的内存型bmp

//---------------------------------方法1:---------------------------------
定义类的成员变量
CDC dcMemory;//图形重绘,双缓冲防止闪屏
CBitmap bmp;
CBitmap *pOldBitmap;
void CViewImage::initBackgroundImage(CDC* pDC)
{
    if (!bFirst)
    {
      return;
    }
  CRect rect;
  GetClientRect(&rect);
  dcMemory.CreateCompatibleDC(pDC);
  bmp.CreateCompatibleBitmap(pDC, rect.right, rect.bottom);
  pOldBitmap = dcMemory.SelectObject(&bmp);
  dcMemory.SetBkMode(TRANSPARENT);
  //dcMemory.FillSolidRect(0, 0, rect.right, rect.bottom, RGB(255, 255, 255));//默认是黑色
  DrawBackgroundImage(&dcMemory);//绘制自定义背景图
}
void CViewImage::destroyBackgroundImage()
{
    dcMemory.SelectObject(pOldBitmap);
  dcMemory.DeleteDC();
  bmp.DeleteObject();
}
void CViewImage::OnDraw(CDC* pDC)//方法1:画在已知的内存型bmp
{
    initBackgroundImage(CDC* pDC);//使用布尔量控制只绘制一次,但是遇到OnSize消息时,背景图需要重绘
  CRect rect;
  GetClientRect(&rect);
  CDC dcCompatible;
  dcCompatible.CreateCompatibleDC(pDC);
  pOldBitmap = dcCompatible.SelectObject(&bmp);
  DrawBall(&dcCompatible);//绘制小球
  pDC->BitBlt(rect.left, rect.top, rect.right, rect.bottom, &dcCompatible, 0, 0, SRCCOPY);
  dcCompatible.SelectObject(pOldBitmap);
  dcCompatible.DeleteDC();
}


方法2:一个CDC拷贝到另一个CDC

//---------------------------------方法2:---------------------------------
定义类的成员变量
CDC dcMemory1;
CBitmap bmp1;
CBitmap *pOldBitmap1;
void CViewImage::initBackgroundImage(CDC* pDC)
{
  if (!bFirst)
  {
  return;
  }
  CRect rect;
  GetClientRect(&rect);
  dcMemory1.CreateCompatibleDC(pDC);
  bmp1.CreateCompatibleBitmap(pDC, rect.right, rect.bottom);
  pOldBitmap1 = dcMemory1.SelectObject(&bmp1);
  dcMemory1.SetBkMode(TRANSPARENT);
  //dcMemory1.FillSolidRect(0, 0, rect.right, rect.bottom, RGB(255, 255, 255));//默认是黑色
  DrawBackgroundImage(&dcMemory1);//绘制自定义背景图
}
void CViewImage::destroyBackgroundImage()
{
  dcMemory1.SelectObject(pOldBitmap1);
  dcMemory1.DeleteDC();
  bmp1.DeleteObject();
}
void CViewImage::OnDraw(CDC* pDC)
{
  initBackgroundImage(CDC* pDC);//使用布尔量控制只绘制一次,但是遇到OnSize消息时,背景图需要重绘
  //方法2:一个CDC拷贝到另一个CDC
  CDC dcMemory2;
  dcMemory2.CreateCompatibleDC(&dcMemory1);
  CBitmap bmp2;
  bmp2.CreateCompatibleBitmap(&dcMemory1, rect.right, rect.bottom);
  CBitmap *pOldBitmap2 = dcMemory2.SelectObject(&bmp2);
  dcMemory2.SetBkMode(TRANSPARENT);
  dcMemory2.BitBlt(rect.left, rect.top, rect.right, rect.bottom, &dcMemory1, 0, 0, SRCCOPY);//CDC拷贝
  DrawBall(&dcMemory2);//绘制小球
  pDC->BitBlt(rect.left, rect.top, rect.right, rect.bottom, &dcMemory2, 0, 0, SRCCOPY);//绘制在客户区
  dcMemory2.SelectObject(pOldBitmap2);
  dcMemory2.DeleteDC();
  bmp2.DeleteObject();
}


推荐使用方法2!!



---题外话---


//---------------------------------题外话:外部加载位图并显示---------------------------------

void CViewImage::OnDraw(CDC* pDC)
{
  CBitmap bitmap;
  bitmap.LoadBitmap(IDB_BITMAP_DEBUG_TEACH);
  BITMAP bmp1;
  bitmap.GetBitmap(&bmp1);
  CDC dcCompatible;
  dcCompatible.CreateCompatibleDC(pDC);
  pOldBitmap = dcCompatible.SelectObject(&bitmap);
  dcCompatible.MoveTo(1, 1);
  dcCompatible.LineTo(40, 50);
  pDC->BitBlt(rect.left, rect.top, rect.right, rect.bottom, &dcCompatible, 0, 0, SRCCOPY);
  dcCompatible.SelectObject(pOldBitmap);
  dcCompatible.DeleteDC();
  bitmap.DeleteObject();
}


---


参考文献:


https://www.cnblogs.com/renyuan/p/3474802.html


https://bbs.csdn.net/topics/390929456


https://blog.csdn.net/ooyyee11/article/details/7600625


https://www.cnblogs.com/lujin49/p/4704795.html



目录
打赏
0
0
0
0
23
分享
相关文章
Qt实用技巧:代码中QIcon缩放(QPixmap的手动放大和QIcon自动缩小)
Qt实用技巧:代码中QIcon缩放(QPixmap的手动放大和QIcon自动缩小)
Qt实用技巧:代码中QIcon缩放(QPixmap的手动放大和QIcon自动缩小)
为duilib的MenuDemo增加消息响应,优化代码和显示效果
转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/38253297 第一部分         我在前一段时间研究了怎么制作duilib的菜单,花了几天时间以MenuDemo为基础做出个duilib的菜单以备自用,近些天在群里经常会碰到群友问如何给MenuDemo增加消息响应,为了避免重复的回答我特意写这篇日志,希望可以帮到需要之人,同时也介绍了如何美化菜单的效果、动态修改自身的状态以及通过增加属性来优化菜单的xml文件编写过程,先截个图展示一下效果。
1848 0
精简函数栈帧:优化创建和销毁过程的完全解析(建议收藏,提升内功)
精简函数栈帧:优化创建和销毁过程的完全解析(建议收藏,提升内功)
134 1
Qt实用技巧:Qt设计器中QIcon的缩放(qss的放大和QIcon自动缩小(无法自动放大))
Qt实用技巧:Qt设计器中QIcon的缩放(qss的放大和QIcon自动缩小(无法自动放大))
Qt实用技巧:Qt设计器中QIcon的缩放(qss的放大和QIcon自动缩小(无法自动放大))
unity3d Drawcall优化方法
unity3D 对于移动平台的支持无可厚非,但是也有时候用3D 开发出来的应用、游戏在移动终端上的运行有着明显的效率问题,比如卡、画质等各种问题。自己在做游戏开发的时候偶有所得。
1503 0
WebGL 2系列之多采样渲染缓冲对象
本文适合对webgl、计算机图形学、前端可视化感兴趣的读者。
使用不安全代码将 Bitmap 位图转为 WPF 的 ImageSource 以获得高性能和持续小的内存占用
原文:使用不安全代码将 Bitmap 位图转为 WPF 的 ImageSource 以获得高性能和持续小的内存占用 版权声明:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
1254 0
OpenGL ES 纹理图片解析第一波 - 无耐地放弃重写这一部分
OpenGL ES 纹理图片解析第一波 - 无耐地放弃重写这一部分 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循“署名-非商业用途-保持一致”创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS、Android、Html5、Arduino、pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作。
1229 0
C语言编程程序的内存如何布局
C语言编程程序的内存如何布局 C语言程序在内存中各个段的组成  C语言程序连接过程中的特性和常见错误  C语言程序的运行方式  一:C语言程序的存储区域  由C语言代码(文本文件)形成可执行程序(二进制文件),需要经过编译-汇编-连接三个阶段。
815 0

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等