双缓冲绘图

【问题】在以前的双缓冲Demo中,发现这个在移动一张牌的时候,效率还能忍受过去。但是当应用双缓冲技术到显示多张纸牌的时候,我们会发现效率已经不能再让人忍受了。移动纸牌发生飘移;发牌的时候,当把定时器间隔修改为1ms的时候,速度还是很慢。为此需要对双缓冲的效率进行改善。 【改善措施】经过调查,改善的措施具体如下:

 1. 将创建内存画布的工作移动到OnSize函数中去做,也就是当窗口大小发生变化的时候,才能去再次创建内存画布,否则就用原来已经创建好的。 void CDemoDlg::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); // TODO: Add your message handler code here CClientDC clientDC(this); CreateMemoryCanvas(&clientDC); } 2. InvalidateRect这个函数在使用的时候,要指定刷新区域。因为计算机的绘图效率很高,但是显示效率却很低。在OnPaint函数中去判断是否与指定的刷新区域相交,如果相交,则进行绘图显示,否则不去显示。这样做极大地提高了刷新效率。 void CDemoDlg::OnPaint() { CPaintDC dc(this); // device context for painting dc.GetClipBox(m_clipRect); CRect intersectRect; // 将背景图片显示在内存DC中 int nDestX = 0; int nDestY = 0; CRect bkRect; for (nDestY = 0; nDestY <= m_clientRect.bottom /*- BK_WIDTH*/; nDestY +=BK_WIDTH) { for (nDestX = 0; nDestX <= m_clientRect.right /*- BK_WIDTH*/; nDestX += BK_WIDTH) { bkRect.left = nDestX; bkRect.top = nDestY; bkRect.right = nDestX + BK_WIDTH; bkRect.bottom = nDestY + BK_WIDTH; // 如果当前区域与指定刷新区域相交,则进行绘图显示。 if (intersectRect.IntersectRect(bkRect, m_clipRect)) { DisplayBmp(&dc, &m_memDC, IDB_BITMAP6, nDestX, nDestY); } } } // 把纸牌2显示在内存DC中。 if (intersectRect.IntersectRect(m_rectBmp2, m_clipRect)) { DisplayBmp(&dc, &m_memDC, IDB_BITMAP2, m_rectBmp2.left, m_rectBmp2.top); } // 把纸牌1显示在内存DC中。 if (intersectRect.IntersectRect(m_rectBmp1, m_clipRect)) { DisplayBmp(&dc, &m_memDC, IDB_BITMAP1, m_rectBmp1.left, m_rectBmp1.top); } // 将内存DC上的图象拷贝到前台 dc.BitBlt(0, 0, m_clientRect.Width(), m_clientRect.Height(), &m_memDC, 0, 0, SRCCOPY); } void CDemoDlg::OnMouseMove(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default // 如果可以移动,则更新当前纸牌矩形区域 if (m_bRemove) { // 更新当前纸牌矩形区域 CRect oldRect = m_rectBmp1; m_rectBmp1.left = m_rectBmp1.left + (point.x - m_ptOld.x); m_rectBmp1.top = m_rectBmp1.top + (point.y - m_ptOld.y); m_rectBmp1.bottom = m_rectBmp1.top + CARD_HEIGHT; m_rectBmp1.right = m_rectBmp1.left + CARD_WIDTH; CRect newRect = m_rectBmp1; // 这里为了擦除移牌的痕迹,刷新的区域 = 该纸牌的旧矩形区域 + 该纸牌的新矩形区域。 m_paintRect.UnionRect(oldRect, newRect); InvalidateRect(m_paintRect, FALSE); // 记录当前坐标,为旧的坐标 m_ptOld = point; } CDialog::OnMouseMove(nFlags, point); } 【改善效果】:在以前移动一张纸牌,刷新所需要的时间大概为47ms.(这里要画104张纸牌)。 通过以上的改善措施后,刷新所需要的时间不到1ms(这里只画一张纸牌)。

原文地址:https://www.cnblogs.com/buffer/p/1407359.html