我的程序用双缓冲绘图,我发现刷新速度慢。我分析原因可能是我将整个client区都重画了,但是我不会只画invalidate区域的方法。另外如果是一个系统的messagebox引起的重画,我怎么取得无效矩形?我在PreTranslateMessage里拦截WM_PAINT,然后GetUpdateRect正确么?
程序如下: CPoint ptCenter;
CRect rect,ellipseRect;
GetClientRect(&rect);
ptCenter = rect.CenterPoint();
// pDC->GetClipBox(&clip); CDC dcMem;                                                 //用于缓冲作图的内存DC
CBitmap bmp;                                                //内存中承载临时图象的位图
dcMem.CreateCompatibleDC(pDC);              //依附窗口DC创建兼容内存DC
bmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());//创建兼容位图
//  bmp.CreateCompatibleBitmap(pDC,m_update_rect.Width(), m_update_rect.Height());
dcMem.SelectObject(&bmp);                         //将位图选择进内存DC
dcMem.FillSolidRect(rect,pDC->GetBkColor());//按原来背景填充客户区,不然会是黑色
// dcMem.FillSolidRect(m_update_rect,pDC->GetBkColor()); CPen   pen; 
pen.CreatePen(PS_SOLID,1,RGB(255,0,0)); 
CPen* pOldPen = dcMem.SelectObject(&pen);  for(int i=2000;i>0;i--)                                         //在内存DC上做同样的同心圆图象
{
ellipseRect.SetRect(ptCenter,ptCenter);
ellipseRect.InflateRect(i*2,i*2);
dcMem.Ellipse(ellipseRect);
}

pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,SRCCOPY);//将内存DC上的图象拷贝到前台
// pDC->BitBlt(m_update_rect.left,m_update_rect.top,m_update_rect.Width(),m_update_rect.Height(),
// &dcMem,0,0,SRCCOPY);//将内存DC上的图象拷贝到前台 dcMem.SelectObject(pOldPen);
pen.DeleteObject();
dcMem.DeleteDC();                                      //删除DC
bmp.DeleteObject();  

解决方案 »

  1.   

    代码好像没有什么了,还有使用双缓冲绘图时重载OnEraseBkgnd然后返回TRUE//////////////////////////////////////////////////////////////////////////////
    另外如果是一个系统的messagebox引起的重画,我怎么取得无效矩形?我在PreTranslateMessage里拦截WM_PAINT,然后GetUpdateRect正确么? 没有这必要,系统并不是所有情况下都是重绘,有时是通过保存屏幕位图,必要时恢复
      

  2.   

    你试试在oninitdialog的时候准备好背景dc,在onpaint时只bitblt到client中,那样只画一次。
      

  3.   

    for(int i=2000;i>0;i--)                                         //在内存DC上做同样的同心圆图象
        {
            ellipseRect.SetRect(ptCenter,ptCenter);
            ellipseRect.InflateRect(i*2,i*2);
            dcMem.Ellipse(ellipseRect);
        }-------------------------------------------
    这个循环有点多了吧?消耗时间啊。
      

  4.   

    重载OnEraseBkgnd然后返回TRUE ,这个已经作了。我用程序作了个计时测试。
    直接画:首次需要3秒,但移动一个messagebox重画只需要500毫秒。
    我的双缓冲程序:首次需要1秒,但移动一个messagebox重画也需要1秒。
      

  5.   

    http://topic.csdn.net/u/20080111/16/f120fde6-08a8-4e73-bfe8-57c27ebfecef.html
      

  6.   

    你在OnPaint或者OnDraw中用CDC::GetClipBox就可以得到刷新的矩形,然后判断绘图坐标是否在这个区域内,是则绘制;否则不绘制。BitBlt函数也只需要复制这个矩形大小的区域,甚至内存位图也只需要这么大小的矩形。不过内存位图和内存DC最好初始化的时候就创建好,只有改变窗口大小的时候才需要改变内存位图的大小。另外循环中的代码优化是很重要的,比如你这里:    ellipseRect.SetRect(ptCenter,ptCenter);
        for(int i=2000;i>0;i--)                                         //在内存DC上做同样的同心圆图象
        {
            ellipseRect.InflateRect(2, 2);
            dcMem.Ellipse(ellipseRect);
        }
    这样看看是不是有改善。
      

  7.   

    你还是保留一张内存位图作缓冲吧,一开始初始化一下,某些操作如果会改变背景,那就同时更新这张位图,OnPaint里面只管画位图就行了。
      

  8.   

    2楼的方法不适合我的情况,我要画的内容是根据操作要变的,不能初始化时就准备好。 
    -------------------------
    你不会是有东西盖住窗口,画的内容就要改变吧?初始创建一幅桌面大小的内存图象,这样可以适应调整窗口尺寸的需要,不需要反复创建。在内存图象上画好东西,OnPaint只需要把内存图象相应区域画到窗口,有操作需要改变内容和窗口调整尺寸时只需要在内存图象上重画一遍,OnPaint自然会更新显示。
      

  9.   


    测试绘图时间:
    在OnDraw里
    DWORD t1 = GetTickCount();//画图代码,就是问题中包括的那些。DWORD t2 = GetTickCount();绘图时间就是t2-t1
      

  10.   

    说实话,不太敢相信直接画“之后移动一个messagebox重画只需要500毫秒”,难道直接画的时候在颜色不发生变化的情况下,还可以快点完成的???
      

  11.   

    忙了半天还是没搞定!
    to 8楼:“某些操作如果会改变背景,那就同时更新这张位图”
    一个问题是怎么知道改变背景了?是不是还得再OnDraw里?
    另一个问题是同时更新这张位图,是把整个位图重绘么?那时间会减少么?我有点不知道怎么入手了
      

  12.   

    我试出来了,囧……
    先是pDC->GetClipBox(&clip),然后在dcMem.CreateCompatibleDC(pDC)之后加上dcMem.IntersectClipRect(&clip),这样就跟直接画一样了,动一下MessageBox时间400ms。
    不过还是建议保留一张位图作缓存……
      

  13.   

    To 15L,你不可能不知道背景什么时候改变吧?这可是你控制的啊!
    你要求重绘或者说是在Invalidate之前先画好这张图,这样OnDraw的时候不就一次性完成了么?这样的好处是不管窗口怎么覆盖,绘图刷新都是瞬间完成。
    不过你这2000个圆太费时间了,单线程也不是个好办法,可以在要求重绘时,开一个线程画内存位图并在画完后Invalidate,主线程只管复制位图,再用一个锁控制这个位图的读写就可以了。