mfc下实现双缓冲的方法

时间:2021-03-29 10:07:15
         本帖解决的问题:
    如何实现双缓冲 ?


    为什么实现了双缓冲还是会闪烁?


以下资料为本人积累和加上自己的经验
1、简介一下windows mfc的view显示刷新过程:
       (1)、使用背景刷填充view窗体(调用内在机制的);(2)、调用OnPain()\OnDraw(调用用户的);

2、产生闪烁的原因出在于 :当我们很快地刷新view时,都要执行以上两步,而使用背景刷时是实时填充的(本人猜想的),所以效率

很低,于是造成执行以上两步时的时间比人眼的响应时间要长,从而出现了闪烁。

3、解决方案: 我们可以这样想,mfc自动调用背景刷是为了去除旧的信息,然后让用户加上新的信息(调用OnPain或OnDraw),那么我们就

把这两步都自己做吧。其实这两步我们可以合一,简单来说就是我们先在一块内存里面先把东西画好,然后将它直接复制到view,内存复制是

速度很快的,当然我们把背景先要在这快内存里面填充好,这样我们就在这块内存里面都把这两步都搞好了,最后一步就是把它复制到显示的

buffer里面了;

4、具体方法:
先生成一个view窗体:
1)、增加 成员变量
       CBitmap* m_pBitmap;       //这就是内存里面的画布了
       CDC* m_pMemDC;              //这就是用于绘制这块内存的画笔
       int       m_nScreenY;       //这个画布的高
       int m_nScreenX;              //这个画布的宽
2)、然后在view的 【构造函数】里面 添加以下代码(这里就不注析了,会c++的人都懂):
       m_pMemDC=new CDC;
       m_pBitmap=new CBitmap;
       m_nScreenY=1024;
       m_nScreenX=1280;
3)、然后增加消息响应【WM_CREATE】:
添加:
       CDC*pDC=GetDC();
       m_pMemDC->CreateCompatibleDC(pDC);       //创建内存dc
       m_pBitmap->CreateCompatibleBitmap(pDC,m_nScreenX,m_nScreenY);       //创建内存画布
//       m_pBitmap->LoadBitmap(MAKEINTRESOURCE(IDB_BITMAP1));       //你甚至可以用你的资源位图作为画布
       CBitmap*pOldBitmap=m_pMemDC->SelectObject(m_pBitmap);       //让m_pMemDC知道要绘制哪块内存
       CBrush brush(RGB(255,255,255));
       CRect rect;
       GetClientRect(rect);
       m_pMemDC->FillRect(CRect(rect.left,rect.top,m_nScreenX,m_nScreenY),&brush);       //这里相当于我们完成了背景刷
       m_pMemDC->SelectObject(pOldBitmap);
       ReleaseDC (pDC);
4)、 在OnDraw()里面添加:
       CRect rect;
       GetClientRect(rect);       //获取当前用户区的大小
       CBitmap*pOldBitmap=m_pMemDC->SelectObject(m_pBitmap);
       DrawSomething();//这里加入你要画的东西
       pDC->BitBlt (rect.left ,rect.top ,m_nScreenX,m_nScreenY,m_pMemDC,rect.left ,rect.top ,SRCCOPY);       //这里就是将内存里面的

画布复制到显示设备的buffer了
       m_pMemDC->SelectObject(pOldBitmap);
5)、以上其实是完成了双缓冲机制了,但如果你高速地调用Invalidate();时,还是会感到很闪烁的,why?我们 忘记去掉内在的背景刷了 ,要去掉也是超简单:
       添加消息响应:WM_ERASEBKGND,然后在这个响应函数里面添加return true;//(记得在return CView::OnEraseBkgnd(pDC);之上)

6)、大功告成
       当然new 了的东西还要delete ,在析构函数里面再增加:     
       delete m_pBitmap;
       delete m_pMemDC;
7)、如何DrawSomething()
void DrawSomething()
{
       CBitmap*pOldBitmap=m_pMemDC->SelectObject(m_pBitmap);
       m_pMemDC->Rectangle(0,0,100,100);              //画你想画的
       m_pMemDC->SelectObject(pOldBitmap);
       Invalidate();
}

5、小结:
       想当年(也就一年前),这个东西困扰了我很久了,现在翻出来,为了后来者看看,少走些弯道,高手可以不用理了。

整理by Letterb @scnu_cs_05
Email:   letterb@tom.com