我做了一个单文档MFC程序,在背景上加载了一个bmp图像资源,因为程序需要在改背景上用Rectangle(CRect(0,0,412,311))设置一个区域,并不断滴刷新该区域,为了防止bmp背景的闪屏,我就用双缓冲技术加载了该bmp,然后又在该背景上绘制我要动态刷新的区域【即是上面用Rectangle(CRect(0,0,412,311))产生的区域】,发现该区域有闪烁。我就想是否可以再次用双缓冲技术来绘制该区域,但是我发现这样做以后它还是有闪烁。
我的问题是:1.这样做是否思路本身就是错的?请详细解释一下这个错误出在哪里,谢谢!
            2.我是否可在已经加载进来的bmp背景上对闪烁区域单独做出某些处理,比如重载OnEraseBkgnd()函数等(我发现这种也是无法解决问题的)思路去解决该问题,烦请给出具体思路或提示代码,谢谢!
            3.这是我想到的另一种解决思路,向单文档中导入(用非双缓冲技术)bmp做背景,然后在背景上再用双缓冲技术绘制我要不断刷新的区域?但是关键我不知道如何使导入的bmp作为背景,并使我要的区域能真正地在此bmp背景上重绘,请给予赐教?

解决方案 »

  1.   

    导入BMP作为背景的方法:
    如果你真正理解双缓存的意义的话,导入BMP就是同样的道理
    我记得的步骤是
    1.建立2个cdc,A与B,A使用selectobject所要选取的BMP
    2.B使用bitblt或者stretchblt根据自己的需要从内存中画出A这时候A就是所画的背景了。
    大致步骤就是如此,双缓存核心的就是思想。思想不明白就理解不了代码的意义
      

  2.   

    这是我的实现代码: CDC dcMemory;
    dcMemory.CreateCompatibleDC(pDC);
    CBitmap bmp1;
    bmp1.LoadBitmap(IDB_YS_BITMAP);           //载入位图
    BITMAP bmpInfo1;
    bmp1.GetBitmap(&bmpInfo1);                //获取位图
    CBitmap *pOldBitmap=dcMemory.SelectObject(&bmp1);
    pDC->BitBlt(0,0,bmpInfo1.bmWidth,bmpInfo1.bmHeight,&dcMemory,0,0,SRCCOPY);                  //将载入的位图复制到当前窗口中
    ::AfxGetMainWnd()->SetWindowPos(NULL,0,0,bmpInfo1.bmWidth,bmpInfo1.bmHeight+100,SWP_NOMOVE);//使窗口与位图大小相当
    CDC MemDC; //首先定义一个显示设备对象
        CBitmap MemBitmap;//定义一个位图对象     MemDC.CreateCompatibleDC(pDC);//随后建立与屏幕显示兼容的内存显示设备
        MemBitmap.CreateCompatibleBitmap(pDC,412,311);//下面建立一个与屏幕显示兼容的位图    //将位图选入到内存显示设备中
        //只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上
        CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);  //绘制游戏区域,出现闪烁是因为下面的的矩形区没有利用双缓冲技术?
    CPen yspen;
    yspen.CreatePen(1,8,250);                  //创建颜色与背景相近的画笔
    MemDC.SelectObject(&yspen);
    MemDC.Rectangle(CRect(0,0,412,311));   //绘制边框
    // pDC->SelectObject(&yspen);
    // pDC->Rectangle(CRect(343,138,755,449));   //绘制边框    //将内存中的图拷贝到屏幕上进行显示
    // MemDC.BitBlt(343,138,755,449,&MemDC,0,0,SRCCOPY); 
        pDC->BitBlt(343,138,755,449,&MemDC,0,0,SRCCOPY);     //绘图完成后的清理
    bmp1.DeleteObject();
    dcMemory.DeleteDC();
        MemBitmap.DeleteObject();
        MemDC.DeleteDC(); 
      

  3.   

    不对
    只要双缓冲用的正确不管多快都不会闪
    我觉得应该是代码和应用有问题
    比如是不是OnEraseBkgnd没有处理
    或者是在背景的基础上又进行绘图————这样就不是双缓冲了
      

  4.   

    神码缓冲,你真叫得上名字了,怎么还判断不了下面的代码到底是不是用了双缓冲,------我也经常在MFC中贴图,对bitblt用的也算是比较多的了,就像3楼说得那样,那是因为那个函数就是那样要求的,必须有一个DC作为参数而己,没什么神秘的,与你说的上面的代码是双缓冲,下面的代码你为什么就判断他没有采用双缓冲呢,还是你就看到有一个DC的就一定不是双缓冲,,原理要弄清比理解字面更重要,另外你说的闪烁问题,这问题在MFC图形界面中经常出现,我对闪烁问题的理解和处理也不是很深,闪烁其实是刷新的速度慢,慢到我们的肉眼可以明显的感觉到区域的变化过程,这个不是计算机的处理速度不够快,尽量不要从这方面找问题,再往下分析就是前景闪烁还是背景闪烁,是前景刷新时慢还是背景刷新时慢,如果真是慢,那你调用再多的刷新也是无济于事,多半是6楼的思路,个别消息没有处理,或处理不当,,,自己分析吧
      

  5.   

    闪烁的原因是:
    1. “图A(paint)->图B(paint),如果中途出现个第三态图C(EaraseBkgrnd)”, 并且有延迟就会有闪烁. 也就是不是直接图A->B. 中间态会让用户感觉到是闪烁.  
    2. “图A(paint)->图B(paint)是连续的, 但是图A和图B差别很大,并且刷新频率很高”, 也可能让用户感觉到不是闪烁, 而是画面有模糊的时候. 不是图A的状态也不是图B的状态, 而是图A和图B混合的状态, 影响效果.
      

  6.   

    我觉得三楼tiger9991
     
    (Reborn) 
    的回答给了我一些思路,双缓冲技术的思想是在内存里绘制再显示,我其实不需要去刷新我的bmp背景,我的目的是要刷新我的前景(即长方形区域),但是当我改变单文档窗体的大小或拖动时,bmp背景会被重绘,这是我对背景采用双缓冲技术的初衷,我觉得你说的少用刷新的函数我试了重绘在长方形中移动目标,发现重绘显示目标时,仍然有闪屏出现,像上面的代码所示,问题依旧,求教中
      

  7.   

    对于freecodeMAN
     
    (freecodeMAN) 
    给的答案,我又对第三态图C(EaraseBkgrnd)做了return TRUE,但是闪屏仍然存在!
    请多多指教!上面的代码一贴出来了,临时改的,比较乱,各位辛苦了
      

  8.   

    谢谢righthook8
     
    (righthook8) 
    你的意思我明白,我再后面打了个?,这是我在写程序时,提醒自己的,原来程序中就是直接画长方形,后来想到用双缓冲来解决画长方形防闪烁的方法,就写了这么一句,贴的时候忘了删掉,望勿见怪!请多多指教。学MFC没多久,见笑了!
      

  9.   

    你看一眼 父窗口有没有收到WM_PAINT.有时自己OnEreaseBkgrnd return true了。
    但有些时候你会调用一些函数, 导致子窗口刷新同时父窗口也会调用EreaseBkgrnd或者OnPaint。
    这样你虽然用了双缓冲, 但是父窗口的刷新, 可能导致你子窗口两次OnPaint中间产生间隔, 显示父背景, 而形成闪烁.