本人之前一直了解雙緩沖繪圖的基本原理,但是在研究很久之後才大概知道具體的使用過程,本文將詳細介紹本人在實際項目中使用雙緩沖繪圖的案例。
實現功能:主界面顯示某張包含人臉的圖片,通過dlib detector獲取到人臉上的68個關鍵點,繪制在圖片上顯示,然後通過鼠標拖動圖片上的關鍵點,調整位置,之後保存。雙緩沖主要能夠解決拖動關鍵點時屏幕閃爍的問題,本文主要側重在雙緩沖的實現,其他功能概不介紹。
具體實現:
1.定義全局變量:
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()繪圖
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()即可。
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()
綜上,雙緩沖繪圖的關鍵是怎麼把所有的繪圖操作放到一個繪圖函數中,該過程可能需要很多的全局變量來保存繪圖相關數據。