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