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引數。
程式碼如下:
- private:
- //......
- HCURSOR m_HCross;
-
UINT
- CPoint m_OldPoint;
- CPoint m_startPoint;
- BOOL m_startRect;
- CGISView::CGISView()
- {
- // TODO: add construction code here
- //....
- m_startRect=FALSE;
- m_startPoint=0;
- m_OldPoint=0;
- m_drawType=0;
- //初始化m_HCross為十字游標
- m_HCross=AfxGetApp()->LoadStandardCursor(IDC_CROSS);
- }
- void CGISView::OnLButtonDown(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
- m_startRect=TRUE; //滑鼠左鍵單擊,設定可以開始繪製矩形框
- m_startPoint=point; //記錄起始點
- m_OldPoint=point;//設定老點也為起始點
- //設定游標為十字游標
- ::SetCursor(m_HCross);
- CView::OnLButtonDown(nFlags, point);
- }
- void CGISView::OnMouseMove(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
- CClientDC dc(this); //獲取裝置控制代碼
- dc.SetROP2(R2_NOT);//此為關鍵
- dc.SetROP2(R2_NOT);//所繪製的圖形並沒有消失,所以可以驗證下面的連續兩次顏色取反不是在一次相應中完成
- //SetRop2 Specifies the new drawing mode.(MSDN)
- //R2_NOT Pixel is the inverse of the screen color.(MSDN)
- //即:該函式用來定義繪製的顏色,而該引數則將顏色設定為原螢幕顏色的反色
- //這樣,如果連續繪製兩次的話,就可以恢復原來螢幕的顏色了(如下)
- //但是,這裡的連續兩次繪製卻不是在一次訊息響應中完成的
- //而是在第一次拖動響應的繪製可以顯示(也就是看到的),第二次拖動繪製實現擦出(也就看不到了)
- dc.SelectStockObject(NULL_BRUSH);//不使用畫刷
- if(TRUE==m_startRect) //根據是否有單擊判斷是否可以畫矩形
- {
- switch(m_drawType)
- {
- case 1://Rectangle
- ::SetCursor(m_HCross);
- dc.Rectangle(CRect(m_startPoint,m_OldPoint));
- dc.Rectangle(CRect(m_startPoint,point));
- m_OldPoint=point;
- break;
- case 2: //Line
- ::SetCursor(m_HCross);
- //擦去上一次繪製的臨時線
- dc.MoveTo(m_startPoint);
- dc.LineTo(m_OldPoint);
- //繪製這一次的臨時線
- dc.MoveTo(m_startPoint);
- dc.LineTo(point);
- //將臨時線的終點複製給m_OldPoint,
- //使其在訊息迴圈的過程中將該值傳遞到
- //擦去上一次畫線的過程中,以便擦去上一次所畫的線
- m_OldPoint=point;
- break;
- case 3: //Circle
- ::SetCursor(m_HCross);
- //擦去上一次繪製的臨時圓
- //設定該圓的y座標,因為要保證兩點的x之差等於y之差
- m_OldPoint.y=m_OldPoint.x-m_startPoint.x+m_startPoint.y;
- dc.Ellipse(CRect(m_startPoint,m_OldPoint));
- //繪製臨時圓
- point.y=point.x-m_startPoint.x+m_startPoint.y;
- dc.Ellipse(CRect(m_startPoint,point));
- m_OldPoint=point;
- break;
- case 4: //Ellipse
- ::SetCursor(m_HCross);
- dc.Ellipse(CRect(m_startPoint,m_OldPoint));
- dc.Ellipse(CRect(m_startPoint,point));
- m_OldPoint=point;
- break;
- case 5: //Dot
- break;
- }
- void CGISView::OnLButtonUp(UINT nFlags, CPoint point)
- {
- // TODO: Add your message handler code here and/or call default
- m_startRect=FALSE;//重置繪製矩形框標誌
- ::ClipCursor(NULL);//解鎖游標,即將游標恢復為預設游標
- //消隱最後的一個矩形
- CClientDC dc(this);//獲取裝置控制代碼
- // dc.SetROP2(R2_NOT); //在MouseMove訊息響應中使用過該函數了,所以在這裡再一次使用會使得其恢復為螢幕的顏色
- dc.SelectStockObject(NULL_BRUSH); //設定畫刷為空畫刷
- switch(m_drawType)
- {
- case 1: //Retangle
- //利用當前畫刷繪製矩形,內部由當前空畫刷(NULL_BRUSH)填充。
- //擦去MouseMove訊息響應中的臨時矩形
- dc.Rectangle(CRect(m_startPoint,m_OldPoint));
- //繪製固定矩形
- dc.Rectangle(CRect(m_startPoint,point));
- //m_drawType=0; //該行的可以使得每畫一次都要選擇所畫的形狀
- break;
- case 2: //Line
- //擦去MouseMove訊息響應中繪製的最後一次臨時線
- dc.MoveTo(m_startPoint);
- dc.LineTo(m_OldPoint);
- //繪製固定線
- dc.MoveTo(m_startPoint);
- dc.LineTo(point);
- break;
- case 3: //Circle
- dc.Ellipse(CRect(m_startPoint,m_OldPoint));
- dc.Ellipse(CRect(m_startPoint,point));
- break;
- case 4: //Ellipse
- dc.Ellipse(CRect(m_startPoint,m_OldPoint));
- dc.Ellipse(CRect(m_startPoint,point));
- break;
- case 5: //Dot
- dc.SetPixel(point,RGB(0,0,0));
- break;
- }
- CView::OnLButtonUp(nFlags, point);
- }
- void CGISView::OnRectangle()
- {
- // TODO: Add your command handler code here
- m_drawType=1;//設定所畫的為矩形
- }
- void CGISView::OnLine()
- {
- // TODO: Add your command handler code here
- m_drawType=2;
- }
- void CGISView::OnEllipse()
- {
- // TODO: Add your command handler code here
- m_drawType=4;
- }
- void CGISView::OnDot()
- {
- // TODO: Add your command handler code here
- m_drawType=5;
- }
- void CGISView::OnCircle()
- {
- // TODO: Add your command handler code here
- m_drawType=3;
- }
以上為自己根據實際程式設計練習和對博文的學習所領悟到的,如果有哪裡理解的不對,還望大家指正,謝謝哈!(程式碼沒有問題,可以正常執行。)
注:程式碼的排版,我多次修改,並確保整齊,但是一旦我發表後,程式碼的排版就會發生改變,有幾行程式碼就會變得不規則。