【電腦圖形學課程】一.MFC基本繪圖函數使用方法__函數

來源:互聯網
上載者:User

        這是最近我《電腦圖形學》課程實踐編程課介紹的相關知識,主要是想通過MFC C++繪圖,讓學生體會下圖形學相關的編程及簡單的圖形繪製,同時非常佩服學生的想象力,他們做得真的不錯。希望這篇基礎文章對你有所協助吧。尤其是有這門課程的學生或編程愛好者,如果文章存在錯誤或不足之處,還請海涵。
        參考書籍:孔令德·《電腦圖形學基礎教程(Visual C++版)》
        學生繪製的圖形還是非常有創新的,表示很滿意,哈哈哈~
   


一. MFC繪圖基礎知識 CDC類

        PS:這部分主要引入孔令德老師的知識,這篇文章以後面的編程為主。         VC++具有強大的繪圖功能,雖然基於對話方塊的應用我推薦大家使用C# Winform程式,但是電腦圖形和映像的基礎知識,還是強烈推薦使用VC++ MFC實現。這有助於讓你深入的理解圖形變換、影像處理等知識。
        在Windows平台下,GDI(Graphics Device Interface)圖形裝置介面被抽象為上下文CDC類(Device Context,DC)。Windows平台直接接收圖形資料資訊的不是顯示器和印表機等硬體裝置,而是CDC對象。MFC中,CDC類定義裝置上下文對象的基類,封裝了所需的成員函數,調用CDC類的成員函數,繪製和列印圖形及文字。

        CDC類派生出CClientDC類、CMetaFileDC類、CPaintDC類和CWindowDC類,請讀者自行學習,同時推薦閱讀原書。
        MFC常用CPoint、CRect、CSize等資料類型。
        (1) CPoint類:存放點座標(x,y);
        (2) CRect類:存放矩形左上頂點和右下角頂點的座標(top、left、right、bottom),其中(top,left)為矩形的左上方點,(right,bottom)為矩形的右下角點;
        (3) CSzie類:存放矩形的寬度和高度的座標(cx,cy),其中cx為矩形的寬度,cy為矩形的高度。

        
        MFC繪圖工具類包括CGdiObject、CBitmap、CBrush、CFont、CPallette、CPen和CRgn等。常用的包括:
        (1) CBitmap:封裝了一個GDI位元影像,提供位元影像操作的介面;
        (2) CFont:封裝了GDI字型,可以選作裝置上下文中的當前字型;
        (3) CBrush:封裝了GDI畫刷,選作裝置上下文的當前畫刷,畫刷用於填充圖形內部;
        (4) CPen:封裝了GDI畫筆,選作裝置上下文的當前畫筆,畫筆用於繪製圖形邊界線;
        (5) CPallette:封裝了GDI調色盤,提供應用程式和顯示器之間的顏色介面;
        (6) CGdiObject:GDI繪圖工具的基類,一般不能直接使用。


二. MFC單文檔編程介紹

        首先建立MFC項目,選擇"MFC AppWizard"工程,命名為"test01"。


        然後選擇"單文檔"格式,其中"基於對話方塊"是Dialog對話方塊工程。



        建立完工程,在工作區間主要包括:ClassView(類別檢視)、ResourceView(資源檢視)和FileView(檔案視圖)。其中類別檢視主要包含各個類,檔案視圖包括源檔案.cpp和標頭檔.h。

  
        開啟資源ResourceView視圖如下所示:


       MFC寫代碼通常在xxxView.cpp檔案下,在"test01View.cpp"中找到OnDraw()函數,用於繪圖:

/////////////////////////////////////////////////////////////////////////////// CTest01View drawingvoid CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data here}
       下面將詳細介紹MFC基礎繪圖函數。



三. MFC繪圖函數及擴充
1.MFC繪圖函數

        (1)繪製直線
        CDC::MoveTo(int x, int y)

        將畫筆移動到當前位置,即座標(x, y)處,並沒有畫線。
        CDC::LineTo(int x, int y)
        畫筆從當前位置繪製一條子線到(x, y)點,但不包含(x, y)點。

void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);pDC->MoveTo(100,150);pDC->LineTo(300,400);// TODO: add draw code for native data here}
        繪製圖形如下所示,座標(100, 150)表示距離左邊100,距離頂部150。


        注意:繪製圖形主要調用CDC* pDC方法實現,MFC可以補充提示函數。



        (2) 設定畫筆
        通常可以設定繪製圖形的顏色及線條屬性,函數為:
        CPen::CreatePen(int nPenStyle, int nWidth, COLORREF color)
       其中第一個參數為畫筆的風格,實現、虛線等,第二個參數為畫筆粗細,第三個參數使畫筆的顏色,採用RGB(255, 255, 255)賦值。


        CPen::SelectObject(Cpen *pen)
        調用CPen選中畫筆對象指標,即將畫筆指向新畫筆,同時指向指標。
void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);//繪製直線pDC->MoveTo(100,150);pDC->LineTo(300,400);//定義畫筆繪製直線CPen pen(PS_DASH, 4, RGB(255,0,0)); //虛線 粗4 紅色pDC->SelectObject(&pen);pDC->MoveTo(100,150);pDC->LineTo(400,300);//方法二 CreatePen定義畫筆CPen pen2;   pen2.CreatePen(PS_DASHDOTDOT, 1, RGB(0,255,0)); //雙點畫線 粗2 綠色pDC->SelectObject(&pen2);pDC->MoveTo(100,150);pDC->LineTo(500,200);}
        運行結果如下圖所示,注意定義畫筆後需要選擇畫筆SelectObject(),才能使用。



        (3) 繪製矩形
        CDC::Rectangle(int x1, int y1, int x2, int y2)

        參數x1、y1表示矩形左上方座標,參數x2、y2表示矩形右下角座標。
void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);//定義畫筆繪製矩形CPen pen(PS_DASH, 2, RGB(0,0,255)); //虛線 粗2 藍色pDC->SelectObject(&pen);//定義座標點CPoint point1(100,150);CPoint point2(400,300);//繪製矩形pDC->Rectangle(point1.x, point1.y, point2.x, point2.y);}
        運行結果如下圖所示,同時定義點是CPoint,可以調用point.x和point.y擷取座標。


        (4) 設定畫刷填顏色
        CBrush::CreateSolidBrush(COLORREF crColor) 

        參數為畫刷顏色,主要用於填充圖形。
        CBrush::SelectObject(CBrush* pBrush)
        選擇畫刷,填充顏色,參數pBrush為選中CBrush對象的指標。
        CGdiObject::DelectObject()
        把已成自由狀態的畫刷從系統記憶體中清除,此函數同刪除畫筆函數。
void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);//定義畫筆繪製矩形CPen pen(PS_DASH, 2, RGB(0,0,255)); //虛線 粗2 藍色pDC->SelectObject(&pen);CBrush bush;bush.CreateSolidBrush(RGB(255,0,0));pDC->SelectObject(bush);//定義座標點CPoint point1(100,150);CPoint point2(400,300);//繪製矩形pDC->Rectangle(point1.x, point1.y, point2.x, point2.y);}
        選擇畫刷填充如下圖所示:



         (5) 清除畫筆及畫刷
        真實操作中,通常會在畫筆和畫刷使用完畢時,把已成為自由狀態的畫筆和畫刷從系統記憶體中刪除。
void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);//定義畫筆繪製矩形CPen MyPen, *OldPen; MyPen.CreatePen(PS_DASH, 2, RGB(0,0,255)); //虛線 粗2 藍色OldPen = pDC->SelectObject(&MyPen);        //舊畫筆賦值//畫刷CBrush MyBrush, *OldBrush;MyBrush.CreateSolidBrush(RGB(255,0,0));OldBrush = pDC->SelectObject(&MyBrush);//定義座標點CPoint point1(100,150);CPoint point2(400,300);//繪製矩形pDC->Rectangle(point1.x, point1.y, point2.x, point2.y);//清除pDC->SelectObject(OldPen);MyPen.DeleteObject();pDC->SelectObject(OldBrush);MyBrush.DeleteObject();}

        (6) 繪製橢圓函數
        CDC::Ellipse(int x1, int y1, int x2, int y2)

        參數x1、y1是繪製橢圓外接矩形左上方的座標,x2、y2是外接矩形的右下角座標。當繪製的外接矩形長和寬相同,即繪製的是圓。
void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);//定義畫筆CPen MyPen, *OldPen; MyPen.CreatePen(PS_DASH, 2, RGB(0,0,255)); //虛線 粗2 藍色OldPen = pDC->SelectObject(&MyPen);        //舊畫筆賦值//畫刷CBrush MyBrush, *OldBrush;MyBrush.CreateSolidBrush(RGB(255,0,0));OldBrush = pDC->SelectObject(&MyBrush);//定義座標點CPoint point1(100,150);CPoint point2(400,300);//繪製橢圓pDC->Ellipse(point1.x, point1.y, point2.x, point2.y);//繪製圓pDC->Ellipse(0, 0, 100, 100);//清除pDC->SelectObject(OldPen);MyPen.DeleteObject();pDC->SelectObject(OldBrush);MyBrush.DeleteObject();}
        輸出如下圖所示:


        注意:還有些方法,包括繪製圓弧、繪製多邊形,方法類似,只是注意下參數即可。

        (7) 繪製文字
        CDC::TextOut(int x, int y, const CString & str)

        參數x、y是文本的起點座標,參數str是CString對象,文字內容。同時可以結合Format格式控制字元串輸出變數。
void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);//定義畫筆CPen MyPen, *OldPen; MyPen.CreatePen(PS_DASH, 2, RGB(0,0,255)); //虛線 粗2 藍色OldPen = pDC->SelectObject(&MyPen);        //舊畫筆賦值//畫刷CBrush MyBrush, *OldBrush;MyBrush.CreateSolidBrush(RGB(255,0,0));OldBrush = pDC->SelectObject(&MyBrush);//定義座標點CPoint point1(100,150);CPoint point2(400,300);//繪製橢圓pDC->Ellipse(point1.x, point1.y, point2.x, point2.y);pDC->TextOut(405,305,_T("繪製橢圓"));//繪製圓pDC->Ellipse(0, 0, 100, 100);//使用Format寫文字CString str1 = "繪製圓 半徑=";int r = 50;CString data;data.Format("%s %d", str1,r);pDC->TextOut(105,105,data);//清除pDC->SelectObject(OldPen);MyPen.DeleteObject();pDC->SelectObject(OldBrush);MyBrush.DeleteObject();}
        輸出如下圖所示:



2.擴充知識

        第一個擴充是,繪製直線過程中,如果圍繞一個圓心進行迴圈繪製,可以得到很好看的圓形直線。

#include <math.h>void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);//定義畫筆並選擇CPen pen(PS_SOLID,4,RGB(120,32,240));pDC->SelectObject(&pen);//定義點繪製一條豎直直線CPoint p0(300,300);CPoint p1(300,550);pDC->MoveTo(p0);pDC->LineTo(p1);//半徑和PIint R = 250;float pi = 3.14f;//定義150個點 迴圈按照圓形繪製CPoint p[100];for(int i=0;i<100;i++){p[i].x = int(p0.x+R*sin((pi+i+1)/20));  //x座標 sin涉及數學知識p[i].y = int(p0.y+R*cos((pi+i+1)/20));  //y座標//先移動到圓形p0(300,300) 再繪製直線pDC->MoveTo(p0);pDC->LineTo(p[i]);}}
輸出如下圖所示:


        該內容就是常見的圖形旋轉知識,核心內容:計算新座標,通過sin和cos數學知識,同時圓形不變,每次迴圈先MoveTo(p0)即可。
        第二段代碼涉及圖形平移,就是繪製矩形圖形平移操作。
void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);//定義畫筆並選擇CPen pen(PS_SOLID,4,RGB(120,32,240));pDC->SelectObject(&pen);CBrush brush(RGB(250,12,30));pDC->SelectObject(&brush);//迴圈繪製矩形int x1=100,y1=100,x2=300,y2=400;for(int j=0; j<100; j=j+3){pDC->Rectangle(x1+j, y1+j, x2+j, y2+j);}}
        輸出如下所示:


四. 學產生果及創新

        下面的代碼是做得比較好的同學的,感覺還是不錯的。
        夏KH同學:

#include <math.h>void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereint d,k,x1,x2,y1,y2;float pi,a,e;CPen pen;pen.CreatePen(PS_SOLID,1,RGB(155,0,0));CPen *pOldPen = pDC->SelectObject(&pen);pi = 3.1415926f;d = 80;for (a = 0; a<=2 * pi; a+= pi/360){e = d * (1+0.25*sin(4*a));e = e * (1 + sin(8*a));x1 = int(320+e*cos(a));x2 = int(320+e*cos(a + pi/8));y1 = int(200+e*sin(a));y2 = int(200+e*sin(a + pi/8));pDC->MoveTo(x1,y1);pDC->LineTo(x2,y2);}}
        輸出如下所示:

        李N同學:
void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data here//定義畫筆CPen pen(PS_SOLID,2,RGB(0,255,0));pDC->SelectObject(&pen);CPoint p0(400,200);int R=200;CPoint p1(400,600);pDC->MoveTo(p0);pDC->LineTo(p1);float pi=3.14f;CPoint p[126];for(int i=0;i<126;i++){p[i].x=int(p0.x + R*sin((pi+i+1)/20));p[i].y=int(p0.y + R*cos((pi+i+1)/20));pDC->MoveTo(p0);pDC->LineTo(p[i]);}CBrush bush(RGB(255,255,0));pDC->SelectObject(&bush);int x1=700,y1=100,x2=900,y2=400;for(int j=0;j<50;j++){pDC->Rectangle(x1+j,y1+j, x2+j, y2+j);}}
        輸出如下所示:


        楊J同學:
void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCPen pen(PS_SOLID,1,RGB(255,0,0));pDC->SelectObject(&pen);   CPoint p0(400,300);int R=200;CPoint p1;p1.x=p0.x;p1.y=p0.y+R; pDC->MoveTo(p0);pDC->LineTo(p1);CPoint p2;float pi=3.14f;p2.x=int(p0.x+R*sin(pi/20));p2.y=int(p0.y+R*cos(pi/20));pDC->MoveTo(p0);pDC->LineTo(p2);CPoint p[1000];for(int i=0;i<1000;i++){p[i].x=int(p0.x+R*sin((pi+i+1)/20));p[i].y=int(p0.y+R*cos((pi+i+1)/20));pDC->MoveTo(p0);pDC->LineTo(p[i]);}CBrush bush(RGB(0,255,255));pDC->SelectObject(&bush);for(int j=0;j<200;j=j+3){pDC->Rectangle(600+j,100+j,800+j,400+j);}}
        輸出如下圖所示:
        張J同學:
#include <math.h>void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCPen pen(PS_SOLID,1,RGB(255,80,0));pDC->SelectObject(&pen);CPoint p0(200,200);CPoint p1;int R=200,P=100;p1.x=p0.x;p1.y=p0.y+R;pDC->MoveTo(p0);pDC->LineTo(p1);float pi=3.14;CPoint p[200];for(int i=0,h=1;i<200,i<200;i=i+2,h=h+2){p[i].x=int(R*sin((pi+i)/20)+p0.x);p[i].y=int(R*cos((pi+i)/20)+p0.y);        p[h].x=int(P*sin((pi+h)/20)+p0.x);p[h].y=int(P*cos((pi+h)/20)+p0.y);pDC->MoveTo(p0);pDC->LineTo(p[i]);pDC->MoveTo(p0);pDC->LineTo(p[h]);}CBrush bush(RGB(255,190,0));pDC->SelectObject(&bush);int x1=500,y1=100,x2=600,y2=300;for(int j=0;j<100;j++){pDC->Rectangle(500-j,100+j,600+j,300-j);}    int x3=700,y3=100,x4=800,y4=300;for(int k=0;k<100;k++){pDC->Ellipse(700-k,100+k,800+k,300-k);}int x5=900,y5=100,x6=1000,y6=300;for(int l=0;l<100;l++){pDC->Rectangle(900+l,100+l,1000+l,300+l);}}
        輸出如下圖所示:

        鄭DD同學:

#include <math.h>void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCPen pen(PS_SOLID,1,RGB(0,255,0,));pDC->SelectObject(&pen);CPoint p1,p2;int R=200;p1.x=200;p1.y=300;p2.x=100;p2.y=p1.y+R;pDC->MoveTo(p1);pDC->MoveTo(p2);float pi=3.14f;CPoint p[400];for(int i=0;i<400;i++){p[i].x = int(R*sin((pi+i+1)/3)+p1.x);p[i].y = int(R*cos((pi+i+1)/6)+p1.y);pDC->MoveTo(p1);pDC->LineTo(p[i]);}pDC->TextOut(190,280,_T("wow")),RGB(255,0,0);float ph=3.14f;    for(int h=0;h<400;h++){p[h].x = int(R*sin((ph+h+1)/6)+p1.x);p[h].y = int(R*cos((ph+h+1)/3)+p1.y);pDC->MoveTo(p1);pDC->LineTo(p[i]);}}
        輸出如下圖所示:




        趙BL同學:
#include <math.h>void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data here//定義畫筆CPen pen(PS_SOLID,2,RGB(255,32,150));    pDC->SelectObject(&pen);//定義點CPoint p0(300,400);CPoint p1(300,600);pDC->MoveTo(p0);pDC->LineTo(p1);float pi=3.14f;int R=200;CPoint p[249];for(int i=0; i<249; i++){p[i].x = int(p0.x + R*cos((pi+i+1)/20));p[i].y = int(p0.y + R*tan((pi+i+1)/20));pDC->MoveTo(p0);pDC->LineTo(p[i]);}CBrush bush(RGB(255,166,123));pDC->SelectObject(bush);int x=600,y=100;int x2=900,y2=300;pDC->Rectangle(x,y,x2,y2);for(int j=0;j<100;j=j+4){pDC->Rectangle(x+j,y+j,x2+j,y2+j);}}
        輸出如下圖所示:

        陳Y同學:
void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCPen pen(PS_SOLID,8,RGB(132,255,255));pDC->SelectObject(&pen);CPoint p0(220,300);int R=200;CPoint p1;p1.x=p0.x;p1.y=p0.y+R;pDC->MoveTo(p0);pDC->LineTo(p1);CPoint p2;float pie=3.14f;CPoint p[45];for(int i=0;i<60;i++) { p2.x=int(p0.x+R*sin((pie-i)/10));p2.y=int(p0.y+R*tan((pie-i)/10));pDC->MoveTo(p0); pDC->LineTo(p2);}}
        輸出如下圖所示:



        文FB同學代碼:
#include <math.h>void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCPen pen(PS_SOLID, 3, RGB(0, 0, 255));pDC->SelectObject(&pen);CPoint p0(350, 200);int r = 200;CPoint p1(350, 300 + r);pDC->MoveTo(p0);pDC->LineTo(p1);CPoint p2;float PI = 3.14f;p2.x = int(p0.x + r*sin(PI / 10));p2.y = int(p0.y + r*cos(PI / 10));pDC->MoveTo(p0);pDC->LineTo(p2);CPoint p[1000];for (int i = 0; i <300; i++){p[i].x = int(p0.x + r*sin((PI + i + 1) / 10));p[i].y = int(p0.y + r*cos((PI + i + 1) / 10));r--;pDC->MoveTo(p0);pDC->LineTo(p[i]);}}
        輸出如下圖所示:


        劉JL同學代碼如下:
void CTest01View::OnDraw(CDC* pDC){CTest01Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCPen pen(PS_SOLID,2,RGB(255,0,0));pDC->SelectObject(&pen);CPoint p0(300,200);int R=170;CPoint p1(350,400);pDC->MoveTo(p0);pDC->LineTo(p1);float pi=3.14f;CPoint p[45];for(int i=0;i<45;i++){p[i].x=int(p0.x*sin((pi+i)/20));p[i].y=int(p0.y*cos((pi+i)/20)+R);pDC->MoveTo(p0);pDC->LineTo(p[i]);}}
        輸出如下圖所示:


        希望文章對你有所協助,上課內容還需要繼續探索,這篇文章主要講述MFC繪製圖形的基礎知識,再結合電腦圖形學的旋轉和平移應用進行擴充。原來課程可以這麼上,挺有意思的,同時學生的想象力真實厲害,而且也很優秀。下周專家就來了,真的很忙,但是再忙,寫部落格的時候自己都是最放鬆最享受的時候,上課也是一樣。加油~
         

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.