本人之前一直了解雙緩衝繪圖的基本原理,但是在研究很久之後才大概知道具體的使用過程,本文將詳細介紹本人在實際專案中使用雙緩衝繪圖的案例。
實現功能:主介面顯示某張包含人臉的圖片,通過dlib detector獲取到人臉上的68個關鍵點,繪製在圖片上顯示,然後通過滑鼠拖動圖片上的關鍵點,調整位置,之後儲存。雙緩衝主要能夠解決拖動關鍵點時螢幕閃爍的問題,本文主要側重在雙緩衝的實現,其他功能概不介紹。
具體實現:
1.定義全域性變數:
1 2 3 4 5 6 7 8 9 |
CDC dc_mem://記憶體繪製dc CDC *dc://繪圖dc vector<CPoint> face://儲存人臉中關鍵點的座標 CBitmap bitmap; //記憶體繪圖相關變數 CImage image; |
2.在OnInitDialog()函式中初始化繪圖dc=GetDC();
3.OnEraseBkgnd()函式直接return true;
新增函式afx_msg BOOL OnEraseBkgnd(CDC* pDC);
新增訊息ON_WM_ERASEBKGND();
這一步很關鍵!!!
4.在OnPaint()中呼叫DrawOnBuffer()繪圖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
void CEditLmDlg::DrawOnBuffer() { CRgn rgn; rgn.CreateRectRgn(0, 0, image_width, image_height); dc->SelectClipRgn(&rgn); dc_mem.CreateCompatibleDC(dc); bitmap.CreateCompatibleBitmap(dc, edit_rect.Width(), edit_rect.Height()); CBitmap *pOldBit = dc_mem.SelectObject(&bitmap); dc_mem.FillSolidRect(edit_rect, dc->GetBkColor()); dc_mem.SetStretchBltMode(HALFTONE); CRect rect(0, 0, image_width, image_height); image.Draw(dc_mem.m_hDC, rect); dc->BitBlt(0, 0, edit_rect.Width(), edit_rect.Height(), &dc_mem, 0, 0,SRCCOPY); /**將所有的點繪製到dc_mem上*/程式碼略 dc->SelectClipRgn(NULL); dc_mem.DeleteDC(); bitmap.DeleteObject(); } |
函式中CreateRectRgn函式設定裁剪區可以保證重新整理時只重新整理圖片的部分,不重新整理圖片外的其他控制元件,這樣其他控制元件就不會出現閃爍的情況,另外函式結束時要將裁剪區設定為空。
5.至於拖動關鍵點的操作需要呼叫以下三個函式,以及宣告對應的三個訊息即可,在OnLButtonUp,OnMouseMove中將變化後的點的座標更新到face中,並呼叫Invalidate()即可。
1 2 3 4 5 6 7 |
afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnMouseMove(UINT nFlags, CPoint point); ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() |
綜上,雙緩衝繪圖的關鍵是怎麼把所有的繪圖操作放到一個繪圖函式中,該過程可能需要很多的全域性變數來儲存繪圖相關資料。