zoukankan      html  css  js  c++  java
  • MFC双缓冲解决闪烁问题

      最近在写一个图像编辑软件,环境是MFC,但是MFC的视图刷新机制使得图像闪烁得非常厉害(图像缩放时尤其明显),在网上查了一些资料,最好的方法是用双缓冲的方式显示,这里总结一下。

      双缓冲的原理可以这样形象的理解:把电脑屏幕看作一块黑板。首先我们在内存环境中建立一个“虚拟“的黑板,然后在这块黑板上绘制复杂的图形,等图形全部绘制完毕的时候,再一次性的把内存中绘制好的图形“拷贝”到另一块黑板(屏幕)上。采取这种方法可以提高绘图速度,极大的改善绘图效果。 

    主要实现代码如下:

    1 CDC MemDC; //首先定义一个内存显示设备对象
    2  CBitmap MemBitmap;//定义一个位图对象 
    3  MemDC.CreateCompatibleDC(NULL);  //创建兼容设备dc
    4  MemBitmap.CreateCompatibleBitmap(pDC,W,H);  
    5 CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap); 
    6 MemDC.FillSolidRect(0,0,W,H,RGB(255,255,255));//填充初始颜色
    7 cimg.DrawToHDC(MemDC.GetSafeHdc(),CRect(0,0,W,H));//绘图到内存显示设备
    8          
    9 pDC->BitBlt(rect.left,rect.top,W,H,&MemDC,0,0,SRCCOPY); //绘图到真实显示设备

      主要思路就是先创建一个虚拟dc和一张虚拟位图,用于将图像输出到虚拟设备上,内容在虚拟设备挥好后再输出到真实dc上显示出来,这样在要输出的时候才输出,提高了绘图效率。在这种方式下,所有需要显示的函数都可以先会在内存虚拟dc上,虚拟dc可以作为一个全局的变量或者类的成员变量存在,方便调用。

      另外还需重载背景刷新函数OnEraseBkgnd(view类的函数),其的主要作用是刷新背景,刷新次数频繁了就出现了闪烁,因此在需要的时候调用这个函数,其他时候直接return ture即可。

      其实基本思路还是暂停MFC自带的刷新机制,控制图像的刷新,在你想要刷新的时候刷新即可。

      另外有个参考资料如下,不懂实际操作时候可以参考。

      1 内存DC和内存位图

     2 (一)实验目的:
     3      学会使用内存DC解决重画问题
     4 
     5 (二)实验内容:
     6 
     7   当Windows系统需要重画窗口时,会向窗口发送一条WM_PAINT消息,应用程序需要在WM_PAINT消息响应函数(或View类中的OnDraw)中重画整个窗口(即重新显示窗口中的信息)。
     8   可以把所有绘图的工作放到OnDraw、OnPaint等函数中作,但这样作可能会出现三个缺点:速度慢、屏幕闪烁、不方便。
     9   所以,对于需要较复杂绘图的程序,一般方法是在内存中保存窗口内容的一个拷贝(内存DC)来实现重画。每次收到WM_PAINT消息时,将内存DC的内容复制到屏幕上。
    10 
    11 、重建一个工程,在View类的头文件中向View类添加成员变量:指向内存DC的指针和指向内存位图的指针
    12     CDC* m_pMemDC;
    13     CBitmap* m_pBitmap;
    14 、在View类的构造函数中添加代码创建CDC和CBitmap对象
    15     m_pMemDC=new CDC();
    16     m_pBitmap=new CBitmap();
    17 、在View类的析构函数中添加代码销毁CDC和CBitmap对象
    18     delete m_pMemDC;
    19     delete m_pBitmap;
    20 、用Class Wizard为View类添加一个WM_CREATE消息处理函数OnCreate(LPCREATESTRUCT lpCreateStruct),在处理函数中添加代码创建内存DC和位图
    21     //得到屏幕尺寸
    22     int maxX=GetSystemMetrics(SM_CXSCREEN);
    23     int maxY=GetSystemMetrics(SM_CYSCREEN);
    24     //创建内存DC和位图
    25     CDC* pDC=GetDC();
    26     m_pMemDC->CreateCompatibleDC(pDC);
    27     m_pBitmap->CreateCompatibleBitmap(pDC,maxX,maxY);
    28     m_pMemDC->SelectObject(m_pBitmap);
    29     ReleaseDC(pDC);
    30     //初始化内存DC为全白
    31     CBrush brush;
    32     brush.CreateStockObject(WHITE_BRUSH);
    33     CBrush* poldbrush=m_pMemDC->SelectObject(&brush);
    34     m_pMemDC->PatBlt(0,0,maxX,maxY,PATCOPY);
    35     m_pMemDC->SelectObject(poldbrush);
    36 、在OnDraw中添加重画代码
    37     CRect rect;
    38     GetClientRect(rect);
    39     pDC->BitBlt(0,0,rect.Width(),rect.Height(),m_pMemDC,0,0,SRCCOPY);
    40 、用Class Wizard为View类添加一个WM_LBUTTONDOWN消息处理函数,用于响应鼠标左键单击消息。
    41 、在该鼠标消息处理函数中,添加绘图代码
    42     m_pMemDC->TextOut(point.x,point.y,"Test");
    43     Invalidate(FALSE);
    44 、编译运行程序,在鼠标左键点击的地方都会显示出“Test”。最小化窗口,再恢复窗口,可以发现前面显示的“Test”仍然保留。
    45 
    46 说明:
    47   Invalidate函数刷新整个窗口,如果每次绘图修改的区域较小,可以使用InvalidateRect函数代替Invalidate函数以加快显示速度。例如鼠标消息处理函数中的绘图代码可以改为如下代码:
    48     CString str="Test";
    49     CRect rect(point.x,point.y,point.x,point.y);
    50     m_pMemDC->DrawText(str,&rect,DT_CALCRECT|DT_LEFT); //得到要绘制的文本在屏幕上的尺寸
    51     m_pMemDC->DrawText(str,&rect,DT_LEFT);
    52     InvalidateRect(rect,FALSE); //只刷新需要绘制文本的区域
    53   如果绘图次数很频繁,位图很大,用这种方法可以明显改善绘图性能。
    54   Invalidate(TRUE)先清除DC再重画,Invalidate(FALSE)直接在原图上画,性能更好,两者可以视情况选用。
  • 相关阅读:
    HDU1029 Ignatius and the Princess IV
    UVA11039 Building designing【排序】
    UVA11039 Building designing【排序】
    POJ3278 HDU2717 Catch That Cow
    POJ3278 HDU2717 Catch That Cow
    POJ1338 Ugly Numbers(解法二)
    POJ1338 Ugly Numbers(解法二)
    UVA532 Dungeon Master
    UVA532 Dungeon Master
    POJ1915 Knight Moves
  • 原文地址:https://www.cnblogs.com/xweiwei/p/1901686.html
Copyright © 2011-2022 走看看