雙緩衝刷新效率的改善

【問題】
在以前的雙緩衝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(這裏只畫一張紙牌)。

發佈了31 篇原創文章 · 獲贊 5 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章