1 / 35

Visual C++ Windows Programming

Visual C++ Windows Programming. 第五章 基本繪圖原理. 大綱. Windows 的基本繪圖原理 基本繪圖函式. Windows 的基本繪圖原理. 繪圖裝置介面 (GDI) 在視窗介面下,資料輸出的方式,相較於文字模式是較為複雜的,但也更具彈性且較多變。在視窗介面下顯示的所有資料,都被視為圖形,不論資料看起來是線段、圖形或者文字。

misty
Download Presentation

Visual C++ Windows Programming

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Visual C++ Windows Programming 第五章 基本繪圖原理

  2. 大綱 • Windows 的基本繪圖原理 • 基本繪圖函式

  3. Windows 的基本繪圖原理 • 繪圖裝置介面 (GDI) • 在視窗介面下,資料輸出的方式,相較於文字模式是較為複雜的,但也更具彈性且較多變。在視窗介面下顯示的所有資料,都被視為圖形,不論資料看起來是線段、圖形或者文字。 • 在視窗程式裡,資料輸出均透過繪圖裝置介面 (graphics device interface; GDI) 來完成,由於運用 GDI 函式的關係,使得程式設計師只要運用相同的函式,就可以將資料輸出到不同的裝置上。換句話說,對於程式而言,將資料顯示在螢幕上,與將資料輸出到印表機的方法是一樣的。

  4. 應用程式 GDI 印表機驅動程式 螢幕驅動程式 印表機 螢幕

  5. Windows 的基本繪圖原理 (續) • 裝置內文 (DC) • 當我們想要在視窗的工作區中繪製圖案,或者將工作區中的資料列印出來時,都必須先獲得一個裝置內文 (device context; DC) 。 • 裝置 (device) 泛指各種與資料輸出有關的設備,例如:螢幕,印表機等,以及各種特定格式的檔案,如 BMP 圖檔。 • 所謂的內文 (context) ,是指將輸出於各種裝置的資料。當你需要將你建立的資料輸出至裝置時,就必須為這個裝置準備一個 DC ,以便儲存欲輸出的資料。而這些資料就是使用 GDI 函數繪圖的結果。

  6. Windows 的基本繪圖原理 (續) • 裝置內文是一個用以溝通程式與裝置的媒介。 • 不論是要在視窗客戶區顯示繪圖,或是將圖輸出到印表機裡印出來,所需要做的就是為那個裝置產生一個DC,然後利用GDI函數繪製圖形.透過GDI函數與DC的協助,可以讓我們不論將資料輸出到那個裝置,都使用相同的方法. • 顏色的定義 • RGB巨集 • (0,0,0):黑色, (255,255,255):白色 • COLORREF color = RGB(255, 0, 0);

  7. Windows 的基本繪圖原理 (續) • MFC 的 GDI Classes (CGdiObject) • CBitmap:用以建立操作點陣圖的物件。 • CPen:用於建立操作畫筆的物件。 • CBrush:用於建立操作畫刷的物件。 • CFont:用於建立操作文字的物件。 • CRgn:用於建立繪製圖形的物件。 • CPalette:用於建立調色盤的物件。

  8. Windows 的基本繪圖原理 (續) • MFC 的 DC Classes (CDC) • CClientDC:用於將資料輸出至視窗工作區。 • CWindowDC:用於將資料輸出至視窗中,包含工作區以外的區域。 • CPaintDC:用於輸出回應 WM_PAINT 訊息的資料。 • CMetaFileDC:用於將資料輸出至特殊格式的檔案中。

  9. DC's GDI's

  10. 基本繪圖函式 • 畫點 (point) 函式 COLORREF CDC::SetPixel(int x, int y, COLORREF color); COLORREF CDC::SetPixel(POINT point, COLORREF color); COLORREF CDC::GetPixel(int x, int y) const; COLORREF CDC::GetPixel(POINT point) const; virtual BOOL CDC::PtVisible(int x, int y) const; virtual BOOL CDC::PtVisible(POINT point) const; //如果此像點恰好被其它視窗遮住就看不到了. • 畫線 (line) 函式 BOOL CDC::MoveTo(int x, int y); BOOL CDC::MoveTo(POINT point); BOOL CDC::LineTo(int x, int y); BOOL CDC::LineTo(POINT point);

  11. 基本繪圖函式 (續) • 畫弧 (arc) 函式與畫鐘 (chord) 函式 BOOL CDC::Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4); BOOL CDC::Arc(LPCRECT r, POINT Start, POINT End); BOOL CDC::AngleArc(int x, int y, int radius, float startAngle, float sweepAngle); BOOL CDC::Chord(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4); BOOL CDC::Chord(LPCRECT r, POINT Start, POINT End); • 畫餅 (pie) 函式 BOOL CDC::Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4); BOOL CDC::Pie(LPCRECT r, POINT Start, POINT End);

  12. Chord Arc (x1,y1) (x1,y1) (x4,y4) (x3,y3) (x4,y4) (x3,y3) (x2,y2) (x2,y2) Pie AngleArc (x1,y1) (x4,y4) sweepAngle (x3,y3) radius startAngle (x,y) (x2,y2)

  13. 基本繪圖函式 (續) • 畫橢圓 (ellipses) 函式 BOOL CDC::Ellipses(int x1, int y1, int x2, int y2); BOOL CDC::Ellipses(LPCRECT rect); • 畫矩形 (rectangle) 函式 BOOL CDC::Rectangle(int x1, int y1, int x2, int y2); BOOL CDC::Rectangle(LPCRECT rect); void CDC::FrameRect(LPCRECT lpRect, CBrush *pBrush); void CDC::InvertRect(LPCRECT lpRect);//不會畫出任何東西,只是把指定矩形中所有像點都作一次NOT運算而已. BOOL CDC::RoundRect(int x1, int y1, int x2, int y2, int x3, int y3); BOOL CDC::RoundRect(LPCRECT lpRect, POINT point); BOOL CDC::RectVisible(LPCRECT rect) const;//只要有一丁點露出來,就是T

  14. 基本繪圖函式 (續) • 畫多邊形 (polygon) 函式 BOOL CDC::Polygon(LPPOINT lpPoints, int nCount); //多邊形 BOOL CDC::Polyline(LPPOINT lpPoints, int nCount); //不會封閉 BOOL CDC::PolyPolygon(LPPOINT lpPoints, LPINT lpPolyCounts, int nCount); //好幾個多邊形 BOOL CDC::PolylineTo(const POINT *lpPoints, int nCount); //類似Polyline,但會改變游標之值,像是作了一大串的LineTo BOOL CDC::PolyBezier(const POINT *lpPoints, int nCount);

  15. 物件Collection • CArray樣板類別 • 你可以用這個樣板將任何物件存在array內,讓array可以視需要自動加大. CArray<ObjectType, ObjectType&> anArray 成員函式的引數型態 要存放的物件型態

  16. Index Object1 0 Object2 1 GetAt(2) SetSize(5) 定義初始大小 Object3 2 傳回物件 Object4 3 Object5 4 Add(Obj A) Object6 5 存放物件 Obj A 6 自動增加

  17. CList<ObjectType, ObjectType&> aList; AddHead(ObjA) Obj A 存放物件 傳回型態為Position 的值 Object1 大小的增加 是自動的 Object2 aPos Object3 GetNext(aPos) Object4 AddTail(ObjB) Obj B

  18. Object1 Object2 Object3 Object4 Key1 Key2 Key3 Key4 CMap<KeyType, KeyType&,ObjectType, ObjectType&> aMap; aMap[Key2]=Object2 LookUp(Key3,AnObject)

  19. #include <afxwin.h> #include <afxtempl.h> #include <afxext.h> #include "resource.h" class CGObject : public CObject {//儲存形狀物件的類別,衍生自CObject類別以便具備儲存(serialize)的功能 public: int shapenum; //形狀代號 BOOL fill; //是否填滿 COLORREF FillColor, LineColor; //填滿顏色與外框顏色 int width; //外框寛度 CPoint StartPnt, EndPnt; //形狀的起點與終點 CGObject() { }//預設建構子 CGObject(int shapenum, BOOL fill, COLORREF FillColor, COLORREF LineColor, int width, CPoint StartPnt, CPoint EndPnt) : shapenum(shapenum), fill(fill), FillColor(FillColor), LineColor(LineColor), width(width), StartPnt(StartPnt), EndPnt(EndPnt) { } //一般建構子 CGObject(CGObject &g) : //複製建構子 shapenum(g.shapenum), fill(g.fill), FillColor(g.FillColor), LineColor(g.LineColor), width(g.width), StartPnt(g.StartPnt), EndPnt(g.EndPnt) { } //過載 = 運算子 CGObject & operator = (CGObject &g) { shapenum = g.shapenum; fill = g.fill; FillColor = g.FillColor; LineColor = g.LineColor; width = g.width; StartPnt = g.StartPnt; EndPnt = g.EndPnt; return *this; } } ;

  20. class Shape { //形狀類別的基礎類別 protected: CPoint StartPnt, EndPnt; //定義形狀的起點與終點 int shapenum; //形狀代號 friend class CMyView; //將MyView設為friend類別,方便資料存取 public: //一般建構子 Shape(CPoint StartPnt, CPoint EndPnt, int shapenum) : StartPnt(StartPnt), EndPnt(EndPnt), shapenum(shapenum) { } //複製建構子 Shape(Shape &s) : StartPnt(s.StartPnt), EndPnt(s.EndPnt), shapenum(s.shapenum) { } Shape() { } //預設建構子 //過載 = 運算子 Shape & operator = (Shape &s) { StartPnt = s.StartPnt; EndPnt = s.EndPnt; //shapenum = s.shapenum; return *this; } virtual void draw(CDC &aDC, COLORREF color, COLORREF fcolor, int width, BOOL Filled = false) = 0; //純虛擬函式 int GetShapeNum() { return shapenum; }//取得形狀代號 void SetPoint(CPoint SPnt, CPoint EPnt) { StartPnt = SPnt; EndPnt = EPnt; }//設定起,終點 } ;

  21. class Line : public Shape { //直線類別 public: friend class CMyView; Line() { shapenum = 0; } //預設建構子 Line(CPoint StartPnt, CPoint EndPnt) : Shape(StartPnt, EndPnt, 0) { } //一般建構子 Line(Line &l) : Shape(l.StartPnt, l.EndPnt, 0) { } //複製建構子 Line & operator = (Line &l) { //過載 = 運算子 StartPnt = l.StartPnt; EndPnt = l.EndPnt; return *this; } //Line::draw 繪出直線 void draw(CDC &dc, COLORREF color, COLORREF fcolor, int width, BOOL Filled = false) { CPen pen(PS_SOLID, width, color); //建立畫筆物件 CPen *oldPen = dc.SelectObject(&pen); //設定DC物件使用pen物件,並將舊的default pen物件儲存起來 dc.MoveTo(StartPnt); //移到直線起點 dc.LineTo(EndPnt); //畫到直線終點 dc.SelectObject(oldPen); //將原來的pen還原 } } ;

  22. class ellipse : public Shape { public: friend class CMyView; ellipse() { shapenum = 1; } ellipse(CPoint StartPnt, CPoint EndPnt) : Shape(StartPnt, EndPnt, 1) { } ellipse(ellipse &e) : Shape(e.StartPnt, e.EndPnt, 1) { } ellipse & operator = (ellipse &e) { StartPnt = e.StartPnt; EndPnt = e.EndPnt; return *this; } void draw(CDC &dc, COLORREF color, COLORREF fcolor, int width, BOOL Filled = false) { CRect rect(StartPnt, EndPnt); CPen pen(PS_SOLID, width, color); CPen *oldPen = dc.SelectObject(&pen); dc.SelectStockObject(NULL_BRUSH); //設定DC物件不使用畫刷 dc.Ellipse(rect); dc.SelectObject(oldPen); } } ; class rectangle : public Shape { public: friend class CMyView; rectangle() { shapenum = 2; } rectangle(CPoint StartPnt, CPoint EndPnt) : Shape(StartPnt, EndPnt, 2) { } rectangle(rectangle &r) : Shape(r.StartPnt, r.EndPnt, 2) { } rectangle & operator = (rectangle &r) { StartPnt = r.StartPnt; EndPnt = r.EndPnt; return *this; } void draw(CDC &dc, COLORREF color, COLORREF fcolor, int width, BOOL Filled = false) { CRect rect(StartPnt, EndPnt); CPen pen(PS_SOLID, width, color); CPen *oldPen = dc.SelectObject(&pen); dc.SelectStockObject(NULL_BRUSH); dc.Rectangle(rect); dc.SelectObject(oldPen); } } ;

  23. class CMyDocument : public CDocument { private: CArray<CGObject, CGObject&> gArray; //儲存CGObject物件的CArray容器物件 public: void AddObject(CGObject &g) { gArray.Add(g); } CGObject & GetObject(int i) { return gArray[i]; } int GetSize() { return gArray.GetSize(); } DECLARE_DYNCREATE(CMyDocument) DECLARE_MESSAGE_MAP() } ; IMPLEMENT_DYNCREATE(CMyDocument, CDocument) BEGIN_MESSAGE_MAP(CMyDocument, CDocument) END_MESSAGE_MAP()

  24. class CMyFrame : public CFrameWnd { protected: CMenu *menu; public: CToolBar RGBBar, ShapeBar; CStatusBar statusbar; CMyFrame() { } ~CMyFrame() { } // afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct) { if(CFrameWnd::OnCreate(lpCreateStruct)) return -1; RGBBar.Create(this); RGBBar.LoadToolBar(IDR_TBRGB); RGBBar.EnableDocking(CBRS_ALIGN_ANY); RGBBar.SetBarStyle(RGBBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); ShapeBar.Create(this); ShapeBar.LoadToolBar(IDR_TBSHAPE); ShapeBar.EnableDocking(CBRS_ALIGN_ANY); ShapeBar.SetBarStyle(RGBBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&RGBBar); DockControlBar(&ShapeBar); static UINT indicators[] = { ID_SEPARATOR, IDS_RED, IDS_LINE } ; statusbar.Create(this); statusbar.SetIndicators(indicators, sizeof(indicators) / sizeof(UINT)); return 0; } DECLARE_DYNCREATE(CMyFrame) DECLARE_MESSAGE_MAP() } ; IMPLEMENT_DYNCREATE(CMyFrame, CFrameWnd) BEGIN_MESSAGE_MAP(CMyFrame, CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP()

  25. class CMyView : public CView { private: COLORREF lcolor, fcolor;// lcolor為形狀外框的顏色,fcolor為填滿內部的顏色 Shape *aShape; //指向欲繪製之形狀類別的物件指標 Shape *rdShape; //為重繪視窗時,從Document中取得形狀物件 int width; //形狀外框的寬度 HCURSOR hcursor; public: CMyView() { lcolor = RGB(255, 0, 0); aShape = new Line; fcolor = RGB(0, 0, 0); width = 2; } ~CMyView() { } afx_msg void OnEllipse() { CString resstr; aShape = new ellipse; resstr.LoadString(IDS_ELLIPSE); ((CMyFrame *) GetParentFrame())->statusbar.SetPaneText(2, resstr.GetBuffer(80)); } afx_msg void OnRect() { CString resstr; aShape = new rectangle; resstr.LoadString(IDS_RECTANGLE); ((CMyFrame *) GetParentFrame())->statusbar.SetPaneText(2, resstr.GetBuffer(80)); } afx_msg void OnLine() { CString resstr; aShape = new Line; resstr.LoadString(IDS_LINE); ((CMyFrame *) GetParentFrame())->statusbar.SetPaneText(2, resstr.GetBuffer(80)); } afx_msg void OnDraw(CDC *aDC) { CMyDocument *doc = (CMyDocument *) GetDocument(); int num = doc->GetSize(); //取得目前Document物件中儲存的形狀物件個數 CView::OnDraw(aDC); int i; for(i = 0; i < num; i++) { CGObject *object = &(doc->GetObject(i)); switch(object->shapenum) { case 0: rdShape = new Line; break; case 1: rdShape = new ellipse; break; case 2: rdShape = new rectangle; break; } rdShape->SetPoint(object->StartPnt, object->EndPnt); rdShape->draw((*aDC), object->LineColor, object->FillColor, object->width); delete rdShape; } }

  26. afx_msg void OnLButtonUp(UINT, CPoint point) { if(this == GetCapture()) { CClientDC aDC(this); (*aShape).EndPnt = point; (*aShape).draw(aDC, lcolor, fcolor, width); CGObject object(aShape->GetShapeNum(), true, fcolor, lcolor, width, aShape->StartPnt, aShape->EndPnt); CMyDocument *doc = (CMyDocument *) GetDocument(); doc->AddObject(object); ReleaseCapture(); } } afx_msg void OnRed() { CString resstr; lcolor = RGB(255, 0, 0); resstr.LoadString(IDS_RED); ((CMyFrame *) GetParentFrame())->statusbar.SetPaneText(1, resstr.GetBuffer(80)); } afx_msg void OnGreen() { CString resstr; lcolor = RGB(0, 255, 0); resstr.LoadString(IDS_GREEN); ((CMyFrame *) GetParentFrame())->statusbar.SetPaneText(1, resstr.GetBuffer(80)); } afx_msg void OnBlue() { CString resstr; lcolor = RGB(0, 0, 255); resstr.LoadString(IDS_BLUE); ((CMyFrame *) GetParentFrame())->statusbar.SetPaneText(1, resstr.GetBuffer(80)); } afx_msg void OnLButtonDown(UINT, CPoint point) { SetCapture(); if(this == GetCapture()) { (*aShape).StartPnt = (*aShape).EndPnt = point; switch((*aShape).shapenum) { case 0: hcursor = AfxGetApp()->LoadCursor(IDC_LINE); ::SetCursor(hcursor); break; case 1: hcursor = AfxGetApp()->LoadCursor(IDC_ELLIPSE); ::SetCursor(hcursor); break; case 2: hcursor = AfxGetApp()->LoadCursor(IDC_RECT); ::SetCursor(hcursor); break; } } } afx_msg void OnMouseMove(UINT, CPoint point) { if(this == GetCapture()) { CClientDC aDC(this); aDC.SetROP2(R2_NOT); (*aShape).draw(aDC, lcolor, fcolor, width); (*aShape).EndPnt = point; (*aShape).draw(aDC, lcolor, fcolor, width); } }

  27. afx_msg void OnUpdateEllipse(CCmdUI *aCmdUI) { aCmdUI->SetCheck((*aShape).shapenum == 1); } afx_msg void OnUpdateRect(CCmdUI *aCmdUI) { aCmdUI->SetCheck((*aShape).shapenum == 2); } afx_msg void OnUpdateLine(CCmdUI *aCmdUI) { aCmdUI->SetCheck((*aShape).shapenum == 0); } afx_msg void OnUpdateRed(CCmdUI *aCmdUI) { aCmdUI->SetCheck(lcolor == RGB(255, 0, 0)); } afx_msg void OnUpdateGreen(CCmdUI *aCmdUI) { aCmdUI->SetCheck(lcolor == RGB(0, 255, 0)); } afx_msg void OnUpdateBlue(CCmdUI *aCmdUI) { aCmdUI->SetCheck(lcolor == RGB(0, 0, 255)); } DECLARE_DYNCREATE(CMyView) DECLARE_MESSAGE_MAP() } ; IMPLEMENT_DYNCREATE(CMyView, CView) BEGIN_MESSAGE_MAP(CMyView, CView) ON_WM_LBUTTONDOWN() ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() ON_COMMAND(IDM_RED, OnRed) ON_COMMAND(IDM_GREEN, OnGreen) ON_COMMAND(IDM_BLUE, OnBlue) ON_COMMAND(IDM_LINE, OnLine) ON_COMMAND(IDM_ELLIPSE, OnEllipse) ON_COMMAND(IDM_RECTANGLE, OnRect) ON_UPDATE_COMMAND_UI(IDM_RED, OnUpdateRed) ON_UPDATE_COMMAND_UI(IDM_GREEN, OnUpdateGreen) ON_UPDATE_COMMAND_UI(IDM_BLUE, OnUpdateBlue) ON_UPDATE_COMMAND_UI(IDM_LINE, OnUpdateLine) ON_UPDATE_COMMAND_UI(IDM_ELLIPSE, OnUpdateEllipse) ON_UPDATE_COMMAND_UI(IDM_RECTANGLE, OnUpdateRect) END_MESSAGE_MAP()

  28. class CMyApp : public CWinApp { public: BOOL InitInstance() { CDocument *aDOC; CSingleDocTemplate *aDocTemplate; aDocTemplate = new CSingleDocTemplate(IDR_MENU, RUNTIME_CLASS(CMyDocument), RUNTIME_CLASS(CMyFrame), RUNTIME_CLASS(CMyView)); AddDocTemplate(aDocTemplate); aDOC = aDocTemplate->CreateNewDocument(); CFrameWnd *Frame = aDocTemplate->CreateNewFrame(aDOC, NULL); m_pMainWnd = Frame; aDocTemplate->InitialUpdateFrame(Frame, aDOC); Frame->ShowWindow(SW_SHOW); return true; } } ; CMyApp a_app;

  29. 視窗 形狀類別 執行繪圖 繪圖方法 呼叫 滑鼠訊息/視窗訊息 CMyView 訊息處理方法

  30. 1.點選 2 Afx_msg void MyView::OnRect { aShape = new rectangle; } 3.拖曳 6.放開 3 7 Afx_msg MyView::OnMouseMove() { aShape->draw() } Afx_msg MyView::OnLButtonUp() { aShape->draw() } 4 Virtual shape::draw()=0 Virtual rectangle:draw() {} 5

  31. 調整視窗大小 重繪畫布 發出WM_PAINT訊息呼叫 MyView::OnDraw 存取MyDocument中的gArray

  32. 1 Class CGObject: public CObject { .. CGObject(){}; Void Serialize(CArchive & ar) { …}; DECLARE_SERIAL(CGObject); }; IMPLEMENT_SERIAL(CGObject, CObject, 1) 2 3 4_1 4_2

  33. Void CGObject::Serialize (CArchive & ar) { CObject::Serialize(ar); If (ar.IsStoring()) { ar << Shapenum << fill << fillcolor << linecolor << width << StartPnt << EndPnt; } Else { ar >> … } }

  34. Void CMyDocment::Serialize(CArchive & ar) { CObject::Serialize(ar); gArray.Serialize(ar); } Void CMyDocument::AddObject(CGObject & g) { gArray.Add(g); SetModifiedFlag(true); }

  35. New Open Save Save as ID_FILE_NEW ID_FILE_OPEN ID_FILE_SAVE ID_FILE_SAVE_AS ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)

More Related