1. 程式人生 > >VC/MFC動態畫線,畫圓,畫橢圓,畫矩形

VC/MFC動態畫線,畫圓,畫橢圓,畫矩形

2012年12月7日 22:42:14

今天我在csdn網站上通過學習別人的部落格學習到了動態畫矩形,畫線的方法,這使得我對Windows的訊息迴圈機制有了更深刻的理解。首先來總結一下我今天的收穫,呵呵有收穫就是不錯的,說明我進步了,感謝這兩篇博文:

好了下面開始言歸正傳:

所謂的動態畫線,畫矩形,畫橢圓的本質就是在於消隱問題的解決以及對Windows訊息迴圈機制的理解,消隱問題:因為MFC中有一個函式SetROP2,通過將該函式的引數設定為R2—NOT(當前繪製的畫素值設為螢幕畫素值的反色,這裡面的“螢幕”二字是指你所繪製的圖形所佔據的那一部分螢幕區域,即直線所佔的螢幕區域就是直線所在的那一段線的區域),利用這一點通過在同一區域重複畫兩次便可以將該區域的形狀消隱。

而Windows訊息迴圈機制更好的體現於MouseMove訊息響應中,因為要實現動態畫線、畫矩形這就體現在滑鼠在繪圖區的移動上,滑鼠在繪圖區移動時,產生動態的效果,也就是說在mouse 移動的過程中始終在畫線、畫矩形,這就要求在MouseMove訊息響應中有畫線、畫矩形的相應函式的呼叫,但正是因為mouse移動的過程中畫了很多的線、矩形,所以我們就要在mouse移動的過程中將之前畫出的線、矩形消隱掉,才能保證實現了自己所要實現的功能——動態畫線、畫矩形,但又沒有產生多餘的線和矩形。

消隱的問題和動態畫圖的問題關鍵在於MouseMove訊息響應中的函式呼叫的順序:

1.首先將上次所畫的圖形消隱掉

2.畫出臨時的圖形

3.訊息迴圈的機制:迴圈執行上述程式碼(這是Windows迴圈的機制,不需要自己程式碼實現)

在最後的LButtonUp訊息響應中,需要將上面的MouseMove訊息響應中迴圈的最後一次中最後所畫的臨時圖形消隱掉,之後根據LButtonUp訊息響應中point引數畫出最終的圖形。綜上可知:MouseMove中的程式碼和LButtonUp中消隱臨時圖形的程式碼所要實現的功能就是動態這一過程,而圖形的最終繪製還在與LButtonUp訊息響應及其point引數。

程式碼如下:

  1. private:  
  1. //......
  2.     HCURSOR m_HCross;  
  3.     UINT
     m_drawType;  
  4.     CPoint m_OldPoint;  
  5.     CPoint m_startPoint;  
  6.     BOOL m_startRect;  
  1. CGISView::CGISView()  
  2. {  
  3.     // TODO: add construction code here
  4.     //....
  5.     m_startRect=FALSE;  
  6.     m_startPoint=0;  
  7.     m_OldPoint=0;  
  8.     m_drawType=0;  
  9.     //初始化m_HCross為十字游標
  10.     m_HCross=AfxGetApp()->LoadStandardCursor(IDC_CROSS);  
  11. }  
  1. void CGISView::OnLButtonDown(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default
  4.     m_startRect=TRUE; //滑鼠左鍵單擊,設定可以開始繪製矩形框
  5.     m_startPoint=point; //記錄起始點
  6.     m_OldPoint=point;//設定老點也為起始點
  7.     //設定游標為十字游標
  8.     ::SetCursor(m_HCross);  
  9.     CView::OnLButtonDown(nFlags, point);  
  10. }  
  1. void CGISView::OnMouseMove(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default
  4.     CClientDC dc(this); //獲取裝置控制代碼
  5.     dc.SetROP2(R2_NOT);//此為關鍵
  6.     dc.SetROP2(R2_NOT);//所繪製的圖形並沒有消失,所以可以驗證下面的連續兩次顏色取反不是在一次相應中完成
  7.     //SetRop2 Specifies the new drawing mode.(MSDN)
  8.          //R2_NOT   Pixel is the inverse of the screen color.(MSDN)
  9.          //即:該函式用來定義繪製的顏色,而該引數則將顏色設定為原螢幕顏色的反色
  10.     //這樣,如果連續繪製兩次的話,就可以恢復原來螢幕的顏色了(如下)
  11.     //但是,這裡的連續兩次繪製卻不是在一次訊息響應中完成的
  12.     //而是在第一次拖動響應的繪製可以顯示(也就是看到的),第二次拖動繪製實現擦出(也就看不到了)
  13.     dc.SelectStockObject(NULL_BRUSH);//不使用畫刷
  14.     if(TRUE==m_startRect) //根據是否有單擊判斷是否可以畫矩形
  15.     {  
  16.         switch(m_drawType)  
  17.         {  
  18.                  case 1://Rectangle
  19.                 ::SetCursor(m_HCross);  
  20.                         dc.Rectangle(CRect(m_startPoint,m_OldPoint));  
  21.                         dc.Rectangle(CRect(m_startPoint,point));  
  22.                 m_OldPoint=point;  
  23.                 break;  
  24.              case 2: //Line
  25.                 ::SetCursor(m_HCross);  
  26.                 //擦去上一次繪製的臨時線
  27.                 dc.MoveTo(m_startPoint);  
  28.                      dc.LineTo(m_OldPoint);     
  29.                 //繪製這一次的臨時線
  30.                        dc.MoveTo(m_startPoint);  
  31.                 dc.LineTo(point);  
  32.                 //將臨時線的終點複製給m_OldPoint,
  33.                 //使其在訊息迴圈的過程中將該值傳遞到
  34.                 //擦去上一次畫線的過程中,以便擦去上一次所畫的線
  35.                 m_OldPoint=point;  
  36.                 break;  
  37.              case 3:  //Circle
  38.                 ::SetCursor(m_HCross);  
  39.                                //擦去上一次繪製的臨時圓
  40.                 //設定該圓的y座標,因為要保證兩點的x之差等於y之差
  41.                 m_OldPoint.y=m_OldPoint.x-m_startPoint.x+m_startPoint.y;  
  42.                 dc.Ellipse(CRect(m_startPoint,m_OldPoint));  
  43.                 //繪製臨時圓
  44.                 point.y=point.x-m_startPoint.x+m_startPoint.y;  
  45.                 dc.Ellipse(CRect(m_startPoint,point));  
  46.                 m_OldPoint=point;  
  47.                 break;  
  48.              case 4:  //Ellipse
  49.                 ::SetCursor(m_HCross);  
  50.                 dc.Ellipse(CRect(m_startPoint,m_OldPoint));  
  51.                 dc.Ellipse(CRect(m_startPoint,point));  
  52.                 m_OldPoint=point;  
  53.                 break;  
  54.              case 5:   //Dot
  55.                 break;  
  56.     }  
  1. void CGISView::OnLButtonUp(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default
  4.     m_startRect=FALSE;//重置繪製矩形框標誌
  5.     ::ClipCursor(NULL);//解鎖游標,即將游標恢復為預設游標
  6.     //消隱最後的一個矩形
  7.     CClientDC dc(this);//獲取裝置控制代碼
  8. //  dc.SetROP2(R2_NOT); //在MouseMove訊息響應中使用過該函數了,所以在這裡再一次使用會使得其恢復為螢幕的顏色
  9.     dc.SelectStockObject(NULL_BRUSH);  //設定畫刷為空畫刷
  10.     switch(m_drawType)  
  11.     {  
  12.     case 1: //Retangle
  13.         //利用當前畫刷繪製矩形,內部由當前空畫刷(NULL_BRUSH)填充。
  14.         //擦去MouseMove訊息響應中的臨時矩形
  15.         dc.Rectangle(CRect(m_startPoint,m_OldPoint));  
  16.         //繪製固定矩形
  17.         dc.Rectangle(CRect(m_startPoint,point));  
  18.         //m_drawType=0;  //該行的可以使得每畫一次都要選擇所畫的形狀
  19.               break;  
  20.           case 2:  //Line
  21.         //擦去MouseMove訊息響應中繪製的最後一次臨時線
  22.          dc.MoveTo(m_startPoint);  
  23.                    dc.LineTo(m_OldPoint);  
  24.          //繪製固定線
  25.          dc.MoveTo(m_startPoint);  
  26.          dc.LineTo(point);  
  27.         break;  
  28.      case 3:  //Circle
  29.         dc.Ellipse(CRect(m_startPoint,m_OldPoint));  
  30.         dc.Ellipse(CRect(m_startPoint,point));  
  31.         break;  
  32.      case 4:  //Ellipse
  33.         dc.Ellipse(CRect(m_startPoint,m_OldPoint));  
  34.         dc.Ellipse(CRect(m_startPoint,point));  
  35.         break;  
  36.      case 5:  //Dot
  37.                   dc.SetPixel(point,RGB(0,0,0));  
  38.         break;  
  39.     }  
  40.     CView::OnLButtonUp(nFlags, point);  
  41. }  
  1. void CGISView::OnRectangle()   
  2. {  
  3.     // TODO: Add your command handler code here
  4.     m_drawType=1;//設定所畫的為矩形
  5. }  
  6. void CGISView::OnLine()   
  7. {  
  8.     // TODO: Add your command handler code here
  9.     m_drawType=2;  
  10. }  
  11. void CGISView::OnEllipse()   
  12. {  
  13.     // TODO: Add your command handler code here
  14.     m_drawType=4;  
  15. }  
  16. void CGISView::OnDot()   
  17. {  
  18.     // TODO: Add your command handler code here
  19.     m_drawType=5;  
  20. }  
  21. void CGISView::OnCircle()   
  22. {  
  23.     // TODO: Add your command handler code here
  24.     m_drawType=3;  
  25. }  

以上為自己根據實際程式設計練習和對博文的學習所領悟到的,如果有哪裡理解的不對,還望大家指正,謝謝哈!(程式碼沒有問題,可以正常執行。)

注:程式碼的排版,我多次修改,並確保整齊,但是一旦我發表後,程式碼的排版就會發生改變,有幾行程式碼就會變得不規則。