1. 程式人生 > >MFC兩種拖動滑鼠動態畫圖的方法

MFC兩種拖動滑鼠動態畫圖的方法

一般來說,一次畫圖的過程分為滑鼠左鍵按下,滑鼠移動,滑鼠左鍵彈起。要想在滑鼠移動的過程中動態顯示所畫的圖的變化過程,所畫的圖只能是可以由兩個點確定的圖形,如直線、矩形、橢圓等等。舉例來說,如何畫一條線段?我們要知道起點和終點。起點自然是滑鼠左鍵按下時滑鼠的位置,終點是滑鼠移動時當前的滑鼠位置。既然是拖動滑鼠動態畫圖,那麼畫圖的動作自然是在滑鼠移動的響應函式OnMouseMove()裡完成。要想讓圖跟著滑鼠移動而變化,就必須在滑鼠移動時不斷根據滑鼠新位置畫圖,然而不停畫圖,原來畫的舊圖還停留在那裡。本來一次滑鼠移動只要畫一根線段,現在一次滑鼠移動畫出好多根線段。所以關鍵是如何擦除舊圖。第一種方法是儲存上一次滑鼠停留的位置,然後用背景色的畫筆把舊圖描一遍。

//滑鼠左鍵按下

void C畫圖Dlg::OnLButtonDown(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
  mousemode = 1;//標識滑鼠左鍵已按下
  pt_Begin = pt_End = pt_Mid = point;//pt_Begin標識起點,pt_End標識新終點,pt_Mid標識舊終點
 CDialogEx::OnLButtonDown(nFlags, point);
}

//滑鼠移動

void C畫圖Dlg::OnMouseMove(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 if (mousemode == 1)//確保滑鼠移動是在滑鼠左鍵按下後
 {
  pt_Mid = pt_End;//將原終點的值賦給pt_Mid
  pt_End = point;//將當前滑鼠的位置賦給新終點
  EraseLine(pt_Begin, pt_Mid);//擦掉舊線段
  DrawLine(color,pt_Begin, pt_End);//畫新線段

CDialogEx::OnMouseMove(nFlags, point);
  }
 }

但是這樣會把原來作好的圖也擦掉。想到的解決方法是將原來作好的圖的資料(如起點和終點,還可以擴充如畫筆顏色,圖形種類等,寫成一個class)儲存在vector裡面,擦掉舊圖後先把儲存在vector裡面的圖畫一遍,再畫新圖,當然也可以畫新圖之後再把儲存在vector裡面的圖畫一遍。儲存畫好的圖在滑鼠左鍵彈起的時候進行。

//滑鼠移動

void C畫圖Dlg::OnMouseMove(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 if (mousemode == 1)//確保滑鼠移動是在滑鼠左鍵按下後
 {
  pt_Mid = pt_End;
  pt_End = point;
  EraseLine(pt_Begin, pt_Mid);//擦掉舊線段
  DrawLine(color,pt_Begin, pt_End);//畫新線段
  DrawpGraph(vec_pGraph);//重畫已畫好的圖形

CDialogEx::OnMouseMove(nFlags, point);
 }

//滑鼠左鍵彈起

void C畫圖Dlg::OnLButtonUp(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 if (mousemode == 1)
 {
  mousemode = 0;
  vector<POINT> vec;
  vec.push_back(pt_Begin);
  vec.push_back(pt_End);
  previousGraph temp(drawmode, color, vec);//previousGraph是儲存每個畫好的圖的資料的class
  vec_pGraph.push_back(temp);//將這次畫的圖形的種類,顏色,起點和終點存入向量vec_pGraph中
  pt_Begin = { 0, 0 };
  pt_Mid = { 0, 0 };
  pt_End = { 0, 0 };
 }

CDialogEx::OnLButtonUp(nFlags, point);

}

將畫好的圖的資料儲存在vector裡面的一個好處是我們可以很容易地進行撤銷與重做。然而假如一開始不是在一張空白的圖上作畫,而是在一張背景圖上作畫時,這樣還是會擦掉背景圖。第二種方法可以解決這個問題。

第二種方法進行動態畫圖的思路是滑鼠左鍵按下時將當前視窗的內容儲存為一張圖片,滑鼠移動過程中每次畫新圖之前都先載入這張圖片。

void CDrawXView::DrawpGraph()//函式,功能是載入儲存了滑鼠左鍵按下時視窗影象的圖片
{
 test.Attach(image.Detach());//test是CBitmap型別的物件
 CDC MemDC;
 CDC dc;
 MemDC.CreateCompatibleDC(NULL);
 dc.CreateCompatibleDC(&MemDC);
 dc.SelectObject(&test);
 CClientDC ClientDC(this);
 ClientDC.BitBlt(0, 0, //目標裝置邏輯橫、縱座標
  AreaWidth, AreaHeight, //顯示點陣圖的畫素寬、高度
  &dc, //待顯示點陣圖資料的裝置情境物件
  0, 0, //源資料中的橫、縱座標
  SRCCOPY);
}

//滑鼠左鍵按下
void CDrawXView::OnLButtonDown(UINT nFlags, CPoint point)
{
 mousemode = 1;
 CRect rect; GetClientRect(&rect);//獲取畫布大小  
 CClientDC dc(this); 
 hbit = CreateCompatibleBitmap(dc, rect.right - rect.left, rect.bottom - rect.top);//建立相容點陣圖
 HDC hdc = CreateCompatibleDC(dc);      //建立相容DC,以便將影象儲存為不同的格式 
 HBITMAP hOldMap = (HBITMAP)SelectObject(hdc, hbit); //將點陣圖選入DC,並儲存返回值  
 BitBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, dc, 0, 0, SRCCOPY); //將螢幕DC的影象複製到記憶體DC中    
 hbit = (HBITMAP)SelectObject(hdc, hOldMap); 
 image.Attach(hbit);//將影象儲存到image中,image是CImage型別
 pt_Begin = pt_End = pt_Mid = point;
 CScrollView::OnLButtonDown(nFlags, point);
}
//滑鼠移動
void CDrawXView::OnMouseMove(UINT nFlags, CPoint point)
{
 if (mousemode == 1)
 {
  pt_End = point;
  DrawpGraph();
  DrawLine(color, pt_Begin, pt_End);
 }
 CScrollView::OnMouseMove(nFlags, point);
}

//滑鼠左鍵彈起

void C畫圖Dlg::OnLButtonUp(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 if (mousemode == 1)
 {
  mousemode = 0;
  pt_Begin = { 0, 0 };
  pt_End = { 0, 0 };
 }

CDialogEx::OnLButtonUp(nFlags, point);

}