【計算機圖形學課程】二.MFC滑鼠響應函式模擬畫圖軟體

Eastmount發表於2016-11-20
        上一篇文章我們講述MFC繪製圖形的基本函式,包括繪製直線、繪製矩形、繪製橢圓及繪製文字,同時通過繞圓旋轉和矩形平移簡單的理解了圖形學知識。這篇文章我將介紹滑鼠響應和鍵盤響應,通過這些事件讓學生實現一個類似畫圖的簡單軟體,同時充分發揮學生想象,自己創作東西。
        前文:
       【計算機圖形學課程】一.MFC基本繪圖函式使用方法




一. MFC工程建立及滑鼠響應

        新建一個MFC 單文件的應用程式"MousePic"。



        然後,選擇"View(檢視)"->"建立類嚮導",快鍵鍵是Ctrl+W。這是MFC非常重要的一個知識點,對話方塊或單文件設定按鈕操作、響應函式都是通過該操作實現。


        在MFC ClassWizard中選擇建立工程的"CMousePicView"類名,然後再"Message"中選擇"WM_LBUTTONDOWN",滑鼠左鍵按下響應操作。同時,雙擊它新增函式OnLButtonDown()。


        滑鼠常見訊息響應:
        WM_LBUTTONDBCLK 雙擊滑鼠左鍵
        WM_LBUTTONDOWN 按下滑鼠左鍵
        WM_LBUTTONUP 釋放滑鼠左鍵
        WM_MOUSEMOVE 在客戶區移動滑鼠
        WM_RBUTTONDBCLK 雙擊滑鼠右鍵
        WM_RBUTTONDOWN 按下滑鼠右鍵
        WM_RBUTTONUP 釋放滑鼠右鍵
        


二. MFC實現滑鼠響應操作

        1.滑鼠左鍵按下
        雙擊函式會定位到"MousePicView.cpp"檔案,現在可以對OnLButtonDown()函式進行編輯。其中CPoint point引數記錄當前滑鼠左鍵按下的位置,nFlags表示掩碼。




        然後新增程式碼如下:
//定義一個點型別的變數,用來儲存當使用者點選介面時點選的位置
CPoint m_point;

//滑鼠左鍵按下
void CMousePicView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	//把當前點選的點的位置賦給點m_point
	m_point = point;
	CView::OnLButtonDown(nFlags, point);
}

        2.滑鼠左鍵釋放
        通過同樣的方法在"類嚮導"中實現滑鼠左鍵釋放函式,如下圖所示。


        新增程式碼主要是滑鼠釋放(彈起):

//滑鼠釋放:記錄當前座標
void CMousePicView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	//繪製圖形
	CDC *p = GetDC();
	p->MoveTo(m_point);    //滑鼠移動到左鍵按下點
	p->LineTo(point);      //繪製一條直線 終點為滑鼠釋放點
	CView::OnLButtonUp(nFlags, point);
}
        此時滑鼠繪製圖形如下所示,但是存在兩個問題:繪製過程中不可見、繪製結果只是直線。



        所以,需要藉助滑鼠移動函式實現,在滑鼠移動過程中就進行繪製,同時引入bool型別的變數,判斷滑鼠按下或釋放,按下的時候進行繪製操作。


        3.滑鼠左鍵移動
        通過同樣的方法在"類嚮導"中實現滑鼠左鍵釋放函式。



        完整程式碼如下所示:
//定義一個點型別的變數,用來儲存當使用者點選介面時點選的位置
CPoint m_point;

//定義布林型變數 m_click=true表示滑鼠點選 false表示滑鼠釋放
bool m_click;

//滑鼠左鍵按下
void CMousePicView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	//把當前點選的點的位置賦給點m_point
	m_point = point;
	m_click = true;
	CView::OnLButtonDown(nFlags, point);
}


//滑鼠釋放:記錄當前座標
void CMousePicView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	//繪製圖形
	/*
	CDC *p = GetDC();
	p->MoveTo(m_point);    //滑鼠移動到左鍵按下點
	p->LineTo(point);      //繪製一條直線 終點為滑鼠釋放點
	*/
	m_click = false;
	CView::OnLButtonUp(nFlags, point);
}

//滑鼠移動繪製圖形
void CMousePicView::OnMouseMove(UINT nFlags, CPoint point) 
{
	//定義畫筆並選擇
	CDC *p=GetDC();
	CPen pen(PS_SOLID, 4, RGB(255,0,0));
	p->SelectObject(pen);

	//滑鼠按下進行繪製
	if(m_click==true) {
		p->MoveTo(m_point);
		p->LineTo(point);
		m_point = point;
	}
	CView::OnMouseMove(nFlags, point);
}
        繪製結果如下所示,相當於一個簡單的畫圖軟體。


        4.補充知識
        如果在OnMouseMove()滑鼠移動函式if判斷中缺少程式碼m_point = point,它會出現意想不到的效果,因為你需要每次繪製,滑鼠移動當前點座標point都需要賦值給下次繪製的起始座標,供p->MoveTo(m_point)使用。


        同時,你可以繪製圓形、矩形等相關形狀,不僅僅限定於直線。

//滑鼠移動繪製圖形
void CMousePicView::OnMouseMove(UINT nFlags, CPoint point) 
{
	//定義畫筆並選擇
	CDC *p=GetDC();
	CPen pen(PS_SOLID, 1, RGB(255,0,0));
	p->SelectObject(pen);

	//滑鼠按下進行繪製
	if(m_click==true) {
		p->MoveTo(m_point);
		//p->LineTo(point);
		p->Rectangle(point.x, point.y,point.x+20, point.y+30);
		m_point = point;
	}
	CView::OnMouseMove(nFlags, point);
}
        輸出如下所示:


        繪製中,定義了畫筆Pen,正確的方法需要在繪製完成後,進行釋放該畫筆。核心程式碼如下:

	//定義畫筆繪製矩形  
    CPen MyPen, *OldPen;   
    MyPen.CreatePen(PS_DASH, 2, RGB(0,0,255)); //虛線 粗2 藍色  
    OldPen = pDC->SelectObject(&MyPen);        //舊畫筆賦值  

	//繪製圖形


	//清除  
    pDC->SelectObject(OldPen);  
    MyPen.DeleteObject();  


三. MFC鍵盤響應函式

        1.基礎知識
        Windows對每個按鍵定義了與裝置無關的編碼,這種編碼叫做虛擬碼。有了這個虛擬碼,Windwos程式設計師可以使用該虛擬碼進行程式設計。其中鍵盤上部分按鍵的虛擬碼如下圖所示:


        Windows按鍵訊息常見如下:
        WM_CHAR 敲擊鍵盤上的字元鍵時,產生該訊息
        WM_KEYDOWN 任意鍵(包括字元鍵)被按下時都產生該訊息,如果被按下的是字元鍵,在產生訊息的同時還產生字元訊息
        WM_KEYUP 任意角(包括字元鍵)被釋放都產生該訊息 
        WM_SYSKEYDOWN F10被按下或者Alt與另一個鍵被同時按下
        WM_SYSKEYUP F10被釋放或者Alt與另一個鍵被同時釋放

        2.按鍵響應操作
        同樣,通過類嚮導建立按鍵按下函式。


        然後新增如下程式碼,按下任意一個鍵,繪製的矩形向右平移40距離。
//滑鼠按鍵
void CMousePicView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	
	CDC *p = GetDC();
	p->MoveTo(m_point);       //鍵盤按下
	m_point.x += 40;          //水平平移40
	p->Rectangle(m_point.x, m_point.y, m_point.x+20, m_point.y+30);
	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
        繪製圖形如下所示:


        3.響應不同鍵盤的操作
        需要將UINT nChar轉換為Char字元型,然後進行盤,WASD進行上下左右移動繪製橢圓。

//滑鼠按鍵
void CMousePicView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	
	CDC *p = GetDC();
	char cChar;               //當前被按下的字元
    cChar = char(nChar);      //將按下的鍵轉換為字元

	//定義畫筆  
    CPen MyPen, *OldPen;   
    MyPen.CreatePen(PS_DASH, 2, RGB(0,0,255));  //虛線 粗2 藍色  
    OldPen = p->SelectObject(&MyPen);           //舊畫筆賦值  
  
    //畫刷  
    CBrush MyBrush, *OldBrush;  
    MyBrush.CreateSolidBrush(RGB(0,255,0));  
    OldBrush = p->SelectObject(&MyBrush);  


    if (cChar == 'D') {
		p->MoveTo(m_point);       //D鍵按下
		m_point.x += 40;          //水平向右平移40
		p->Ellipse(m_point.x, m_point.y, m_point.x+20, m_point.y+40);
	}
	if (cChar == 'A') {
		p->MoveTo(m_point);       //A鍵按下
		m_point.x -= 40;          //水平向左平移40
		p->Ellipse(m_point.x, m_point.y, m_point.x+20, m_point.y+40);
	}
	if (cChar == 'S') {
		p->MoveTo(m_point);       //S鍵按下
		m_point.y += 50;          //豎直向下平移50
		p->Ellipse(m_point.x, m_point.y, m_point.x+20, m_point.y+40);
	}
	if (cChar == 'W') {
		p->MoveTo(m_point);       //W鍵按下
		m_point.y -= 50;          //豎直向上平移50
		p->Ellipse(m_point.x, m_point.y, m_point.x+20, m_point.y+40);
	}
	

	//清除  
    p->SelectObject(OldPen);  
    MyPen.DeleteObject();  
    p->SelectObject(OldBrush);  
    MyBrush.DeleteObject(); 

	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
        繪製如下圖所示:


        4.按鍵游標選擇
//滑鼠按鍵
void CMousePicView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	//游標操作
    char cChar;               //當前被按下的字元
    HCURSOR hCursor = 0;      //顯示游標控制程式碼
    HCURSOR hPrevCursor = 0;  //以前的游標控制程式碼
    cChar = char(nChar);      //將按下的鍵轉換為字元
    if (cChar == 'A'){
        //載入箭頭游標
        hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
    }
    if (cChar == 'B'){
        //載入箭頭游標
        hCursor = AfxGetApp()->LoadStandardCursor(IDC_IBEAM);
    }
    if (cChar == 'C'){
        //載入箭頭游標
        hCursor = AfxGetApp()->LoadStandardCursor(IDC_WAIT);
    }    
    if (cChar == 'X'){
        hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
        hPrevCursor = SetCursor(hCursor);
        if (hPrevCursor)
            DestroyCursor(hPrevCursor);
    }
    else{
        if (hCursor){
            hPrevCursor = SetCursor(hCursor);
            if (hPrevCursor)
                DestroyCursor(hPrevCursor);
        }
    }

	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}


四. MFC滑鼠繪製-學生作業展示

        最後展示學生做的成果,雖然程式碼非常簡單,原理也很簡單,但是學生做得真的挺好的,原來程式設計還可以這樣上啊,一方面提升學生的學習興趣,另一方面增加他們的程式設計能力。

  


  

  

    

        還是那句話,非常佩服學生的創造力及想象力吧!而且程式設計課原來可以這麼進行,提升學生的程式設計能力的同時也培養了學生的興趣。希望文章對你有所幫助~
        (By:Eastmount 2016-11-20 半夜2點半 http://blog.csdn.net/eastmount/ )



相關文章