MFC圖片上繪圖,左鍵繪圖,右鍵擦除
效果圖:
需求:視窗上顯示圖片,並可以在圖片上畫線,還可以擦除,擦除不影響圖片顯示,只擦除橡皮擦經過的部分
設計:
1.視窗顯示圖片
2.畫圖
3.顯示繪圖,並且不消失
4.擦除自己作的圖
程式碼:
標頭檔案
//用來顯示圖片
CImage ppt;
//原始相容DC,用來擦除時將原圖部分覆蓋到作圖部分
CDC *pOrignMyDC;
//顯示DC,使用者繪圖onPaint
CDC *pShowUpMyDC;
//兩個bitmap用來設定上面兩個dc的點陣圖
CBitmap bmp;
CBitmap bmp2;
1.顯示圖片
//縮放顯示圖片 VOID videoDialog::showPPT() { CWnd *pWnd = CWnd::FromHandle(m_hWnd); if (NULL == pWnd) { return; } CDC* pDC = pWnd->GetDC(); HDC hDC = pDC->m_hDC; CRect rect_frame; CImage image; pWnd->GetClientRect(&rect_frame); HRESULT ret = image.Load(_T("D:\\222huojian.png")); if (0 != ret) { return; } //圖片顯示在左下角,可以單獨定義控制元件用來顯示圖片 rect_frame.left += 200; rect_frame.top += 100; image.Draw(hDC, rect_frame); ReleaseDC(pDC); }
2.畫圖
LRESULT videoDialog::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { static POINT pt_Begin = { 0 }, pt_End = { 0 }; static int mouseState = 0; if (message <= WM_USER) { switch (message) { case WM_PAINT: { //如果在視窗上畫圖,直接在onPait中畫圖即可, //如果在控制元件上畫圖,onPait中畫圖還不夠 break; } case WM_LBUTTONDOWN: { int xPos = GET_X_LPARAM(lParam); int yPos = GET_Y_LPARAM(lParam); CRect rect; this->GetClientRect(&rect); if (xPos > 200 && yPos < 100) { //沒有標題欄,制定一個區域,用來滑鼠拖動視窗 PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, lParam); } else { mouseState = 1; pt_Begin = pt_End = { xPos, yPos }; CClientDC dc(this); if (NULL == pOrignMyDC) { pOrignMyDC = new CDC(); pShowUpMyDC = new CDC(); pOrignMyDC->CreateCompatibleDC(&dc); pShowUpMyDC->CreateCompatibleDC(&dc); bmp.CreateCompatibleBitmap(&dc, rect.right, rect.bottom); bmp2.CreateCompatibleBitmap(&dc, rect.right, rect.bottom); //CreateCompatibleDC之後是1*1畫素的區域,重新選擇一個位圖設定自己的區域, //CreateCompatibleBitmap可以建立一個跟dc相容的點陣圖,,用來是新舊dc大小匹配 pOrignMyDC->SelectObject(&bmp); pShowUpMyDC->SelectObject(&bmp2); pOrignMyDC->BitBlt(rect.left, rect.top, rect.right, rect.bottom, &dc, 0, 0, SRCCOPY); } } break; } case WM_RBUTTONDOWN: { int xPos = GET_X_LPARAM(lParam); int yPos = GET_Y_LPARAM(lParam); mouseState = 2; CRect rect; this->GetClientRect(&rect); CClientDC dc(this); pt_Begin = pt_End = { xPos, yPos }; if (NULL == pOrignMyDC) { pOrignMyDC = new CDC(); pShowUpMyDC = new CDC(); pOrignMyDC->CreateCompatibleDC(&dc); pShowUpMyDC->CreateCompatibleDC(&dc); bmp.CreateCompatibleBitmap(&dc, rect.right, rect.bottom); bmp2.CreateCompatibleBitmap(&dc, rect.right, rect.bottom); //CreateCompatibleDC之後是1*1畫素的區域,重新選擇一個位圖設定自己的區域, //CreateCompatibleBitmap可以建立一個跟dc相容的點陣圖,,用來是新舊dc大小匹配 pOrignMyDC->SelectObject(&bmp); pShowUpMyDC->SelectObject(&bmp2); pOrignMyDC->BitBlt(rect.left, rect.top, rect.right, rect.bottom, &dc, 0, 0, SRCCOPY); } break; } case WM_RBUTTONUP: case WM_LBUTTONUP: { mouseState = 0; CRect rect; this->GetClientRect(&rect); CClientDC dc(this); pShowUpMyDC->BitBlt(rect.left, rect.top, rect.right, rect.bottom, &dc, 0, 0, SRCCOPY); break; } case WM_MOUSEMOVE: { int xPos = GET_X_LPARAM(lParam); int yPos = GET_Y_LPARAM(lParam); CRect rect;//, rect2; //GetClientRect left和top永遠是0 this->GetClientRect(&rect); ////GetWindowRect 相對螢幕座標 //this->GetWindowRect(&rect2); ////ScreenToClient 轉為視窗客戶區座標 //ScreenToClient(&rect2); pt_End = { xPos, yPos }; CClientDC dc(this); if (0 == mouseState) { break; } else if(1 == mouseState) { CPen pen(PS_SOLID, 5, RGB(255, 255, 0));//建立畫筆物件 CPen* pOldPen = dc.SelectObject(&pen); dc.MoveTo(pt_Begin); dc.LineTo(pt_End); dc.SelectObject(pOldPen); } else if (2 == mouseState) { CRect rt; rt.left = pt_Begin.x > 10 ? (pt_Begin.x - 10) : 0; rt.top = pt_Begin.y > 10 ? (pt_Begin.y - 10) : 0; rt.right = pt_End.x + 10; rt.bottom = pt_End.y + 10; this->GetDC()->BitBlt(rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, pOrignMyDC, rt.left, rt.top, SRCCOPY); } pt_Begin = pt_End; break; } } return CDialogEx::WindowProc(message, wParam, lParam); } }
畫圖原理:
1.滑鼠左鍵單擊時,記下座標,起始點和終止點都初始化為此點,設定左鍵按下狀態(mouseState = 1)
2.滑鼠移動時,如果有左鍵按下的狀態(1 == mouseState),就執行畫線,moveto lineto
3.滑鼠左鍵鬆開時,結束左鍵按下狀態(mouseState = 0),並把當前視窗的繪圖資訊記錄到pShowUpMyDC中
長期顯示,不因onPaint而消失
1.初始化兩個DC,pOrignMyDC,pShowUpMyDC。(程式碼中初始化了兩次,其實沒必要,也懶得封裝),其中pOrignMyDC設定為視窗初始狀態,(根據視窗dc設定)。pShowUpDC設定為視窗DC畫完之後存放的dc,因為onpait之後視窗dc中的繪圖全部消失,只有記憶體DC中的繪圖依然保留,所以要在onPait中重新繪製DC
void videoDialog::OnPaint()
{
showPPT();
if (NULL != pShowUpMyDC)
{
CRect rect;
this->GetClientRect(&rect);
CClientDC dc(this);
dc.BitBlt(0, 0, rect.right, rect.bottom, pShowUpMyDC, 0, 0, SRCCOPY);
}
CDialog::OnPaint();
}
擦除原理
1.滑鼠右鍵按下時,記錄右鍵按下狀態(mouseState = 2)
2.滑鼠移動時,如果有右鍵按下的狀態(2 == mouseState),就執行bitblt,將pOrignMyDC中的點陣圖資訊的指定區域,移動到當前視窗的繪圖資訊中,即用最開始的影象資訊,覆蓋繪圖之後的影象資訊,達到擦除的效果
3.滑鼠右鍵鬆開時,結束滑鼠右鍵按下狀態(mouseState = 0),並把當前視窗的繪圖資訊記錄到pShowUpMyDC中
//記錄//
//onPaint時視窗的繪圖訊息,不是控制元件的,
//控制元件獲取自己在視窗中的座標,還要轉換,麻煩,
//new CDC()初始化只有一個畫素,所以需要設定bitmap,以具備畫圖的空間
//cpen就是畫筆,用來畫線
//cbrush就是畫刷,用來畫區域