我的程序用双缓冲绘图,我发现刷新速度慢。我分析原因可能是我将整个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();
程序如下: 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();
另外如果是一个系统的messagebox引起的重画,我怎么取得无效矩形?我在PreTranslateMessage里拦截WM_PAINT,然后GetUpdateRect正确么? 没有这必要,系统并不是所有情况下都是重绘,有时是通过保存屏幕位图,必要时恢复
{
ellipseRect.SetRect(ptCenter,ptCenter);
ellipseRect.InflateRect(i*2,i*2);
dcMem.Ellipse(ellipseRect);
}-------------------------------------------
这个循环有点多了吧?消耗时间啊。
直接画:首次需要3秒,但移动一个messagebox重画只需要500毫秒。
我的双缓冲程序:首次需要1秒,但移动一个messagebox重画也需要1秒。
for(int i=2000;i>0;i--) //在内存DC上做同样的同心圆图象
{
ellipseRect.InflateRect(2, 2);
dcMem.Ellipse(ellipseRect);
}
这样看看是不是有改善。
-------------------------
你不会是有东西盖住窗口,画的内容就要改变吧?初始创建一幅桌面大小的内存图象,这样可以适应调整窗口尺寸的需要,不需要反复创建。在内存图象上画好东西,OnPaint只需要把内存图象相应区域画到窗口,有操作需要改变内容和窗口调整尺寸时只需要在内存图象上重画一遍,OnPaint自然会更新显示。
测试绘图时间:
在OnDraw里
DWORD t1 = GetTickCount();//画图代码,就是问题中包括的那些。DWORD t2 = GetTickCount();绘图时间就是t2-t1
to 8楼:“某些操作如果会改变背景,那就同时更新这张位图”
一个问题是怎么知道改变背景了?是不是还得再OnDraw里?
另一个问题是同时更新这张位图,是把整个位图重绘么?那时间会减少么?我有点不知道怎么入手了
先是pDC->GetClipBox(&clip),然后在dcMem.CreateCompatibleDC(pDC)之后加上dcMem.IntersectClipRect(&clip),这样就跟直接画一样了,动一下MessageBox时间400ms。
不过还是建议保留一张位图作缓存……
你要求重绘或者说是在Invalidate之前先画好这张图,这样OnDraw的时候不就一次性完成了么?这样的好处是不管窗口怎么覆盖,绘图刷新都是瞬间完成。
不过你这2000个圆太费时间了,单线程也不是个好办法,可以在要求重绘时,开一个线程画内存位图并在画完后Invalidate,主线程只管复制位图,再用一个锁控制这个位图的读写就可以了。