现在的位置: 首页 > 综合 > 正文

双缓冲刷新效率的改善

2013年12月06日 ⁄ 综合 ⁄ 共 2325字 ⁄ 字号 评论关闭

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

【解决方法】
经过调查,解决方法具体如下:
1. 将创建内存画布的工作移动到OnSize函数中去做,也就是当窗口大小发生变化的时候,才能去再次创建内存画布,否则就用原来已经创建好的。

  1. void CDemoDlg::OnSize(UINT nType, int cx, int cy) 
  2. {
  3.  CDialog::OnSize(nType, cx, cy);
  4.  // TODO: Add your message handler code here 
  5.  CClientDC clientDC(this);
  6.  CreateMemoryCanvas(&clientDC);
  7. }

2. InvalidateRect这个函数在使用的时候,要指定刷新区域。因为计算机的绘图效率很高,但是显示效率却很低。在OnPaint函数中去判断是否与指定的刷新区域相交,如果相交,则进行绘图显示,否则不去显示。这样做极大地提高了刷新效率。

  1. void CDemoDlg::OnPaint() 
  2. {
  3.  CPaintDC dc(this); // device context for painting 
  4.  dc.GetClipBox(m_clipRect);
  5.  CRect intersectRect;
  6.  // 将背景图片显示在内存DC中 
  7.  int nDestX = 0;
  8.  int nDestY = 0;
  9.  CRect bkRect;
  10.  for (nDestY = 0; nDestY <= m_clientRect.bottom /*- BK_WIDTH*/;
  11.   nDestY +=BK_WIDTH)
  12.  {
  13.   for (nDestX = 0; nDestX <= m_clientRect.right /*- BK_WIDTH*/;
  14.    nDestX += BK_WIDTH)
  15.   {
  16.    bkRect.left = nDestX;
  17.    bkRect.top = nDestY;
  18.    bkRect.right = nDestX + BK_WIDTH;
  19.    bkRect.bottom = nDestY + BK_WIDTH;
  20.   
  21.    // 如果当前区域与指定刷新区域相交,则进行绘图显示。 
  22.    if (intersectRect.IntersectRect(bkRect, m_clipRect))
  23.    {
  24.     DisplayBmp(&dc, &m_memDC, IDB_BITMAP6, nDestX, nDestY);
  25.    }
  26.   }
  27.  }
  28.  // 把纸牌2显示在内存DC中。 
  29.  if (intersectRect.IntersectRect(m_rectBmp2, m_clipRect))
  30.  {
  31.   DisplayBmp(&dc, &m_memDC, IDB_BITMAP2, m_rectBmp2.left, m_rectBmp2.top);
  32.  }
  33.  // 把纸牌1显示在内存DC中。 
  34.  if (intersectRect.IntersectRect(m_rectBmp1, m_clipRect))
  35.  {
  36.   DisplayBmp(&dc, &m_memDC, IDB_BITMAP1, m_rectBmp1.left, m_rectBmp1.top);
  37.  }
  38.  // 将内存DC上的图象拷贝到前台 
  39.  dc.BitBlt(0, 0, m_clientRect.Width(), m_clientRect.Height(), 
  40.   &m_memDC, 0, 0, SRCCOPY);
  41. }
  42. void CDemoDlg::OnMouseMove(UINT nFlags, CPoint point) 
  43. {
  44.  // TODO: Add your message handler code here and/or call default 
  45.  // 如果可以移动,则更新当前纸牌矩形区域 
  46.  if (m_bRemove)
  47.  {
  48.   // 更新当前纸牌矩形区域 
  49.   CRect oldRect = m_rectBmp1;
  50.   m_rectBmp1.left = m_rectBmp1.left + (point.x - m_ptOld.x);
  51.   m_rectBmp1.top = m_rectBmp1.top + (point.y - m_ptOld.y);
  52.   m_rectBmp1.bottom = m_rectBmp1.top + CARD_HEIGHT;
  53.   m_rectBmp1.right = m_rectBmp1.left + CARD_WIDTH;
  54.   CRect newRect = m_rectBmp1;
  55.   // 这里为了擦除移牌的痕迹,刷新的区域 = 该纸牌的旧矩形区域 + 该纸牌的新矩形区域。 
  56.   m_paintRect.UnionRect(oldRect, newRect);
  57.   InvalidateRect(m_paintRect, FALSE);
  58.   
  59.   // 记录当前坐标,为旧的坐标 
  60.   m_ptOld = point;
  61.  }
  62.  CDialog::OnMouseMove(nFlags, point);
  63. }

【解决后的效果】:
在以前移动一张纸牌,刷新所需要的时间大概为47ms.(这里要画104张纸牌)。 通过以上的改善措施后,刷新所需要的时间不到1ms(这里只画一张纸牌)。

抱歉!评论已关闭.