visual c++ windows programming
DESCRIPTION
Visual C++ Windows Programming. 第五章 基本繪圖原理. 大綱. Windows 的基本繪圖原理 基本繪圖函式. Windows 的基本繪圖原理. 繪圖裝置介面 (GDI) 在視窗介面下,資料輸出的方式,相較於文字模式是較為複雜的,但也更具彈性且較多變。在視窗介面下顯示的所有資料,都被視為圖形,不論資料看起來是線段、圖形或者文字。 - PowerPoint PPT PresentationTRANSCRIPT
Visual C++ Windows Programming
第五章 基本繪圖原理
大綱• Windows 的基本繪圖原理• 基本繪圖函式
Windows 的基本繪圖原理• 繪圖裝置介面 (GDI)
– 在視窗介面下,資料輸出的方式,相較於文字模式是較為複雜的,但也更具彈性且較多變。在視窗介面下顯示的所有資料,都被視為圖形,不論資料看起來是線段、圖形或者文字。
– 在視窗程式裡,資料輸出均透過繪圖裝置介面 (graphics device interface; GDI) 來完成,由於運用 GDI 函式的關係,使得程式設計師只要運用相同的函式,就可以將資料輸出到不同的裝置上。換句話說,對於程式而言,將資料顯示在螢幕上,與將資料輸出到印表機的方法是一樣的。
應用程式
GDI
印表機 螢幕
印表機驅動程式 螢幕驅動程式
Windows 的基本繪圖原理 ( 續 )
• 裝置內文 (DC)– 當我們想要在視窗的工作區中繪製圖案,或者將工作區
中的資料列印出來時,都必須先獲得一個裝置內文 (device context; DC) 。
– 裝置 (device) 泛指各種與資料輸出有關的設備,例如:螢幕,印表機等,以及各種特定格式的檔案,如 BMP 圖檔。
– 所謂的內文 (context) ,是指將輸出於各種裝置的資料。當你需要將你建立的資料輸出至裝置時,就必須為這個裝置準備一個 DC ,以便儲存欲輸出的資料。而這些資料就是使用 GDI 函數繪圖的結果。
Windows 的基本繪圖原理 ( 續 )
– 裝置內文是一個用以溝通程式與裝置的媒介。– 不論是要在視窗客戶區顯示繪圖 , 或是將圖輸出到印表
機裡印出來 , 所需要做的就是為那個裝置產生一個 DC,然後利用 GDI 函數繪製圖形 . 透過 GDI 函數與 DC 的協助 , 可以讓我們不論將資料輸出到那個裝置 , 都使用相同的方法 .
• 顏色的定義• RGB 巨集• (0,0,0): 黑色 , (255,255,255): 白色• COLORREF color = RGB(255, 0, 0);
Windows 的基本繪圖原理 ( 續 )
• MFC 的 GDI Classes (CGdiObject)– CBitmap :用以建立操作點陣圖的物件。– CPen :用於建立操作畫筆的物件。– CBrush :用於建立操作畫刷的物件。– CFont :用於建立操作文字的物件。– CRgn :用於建立繪製圖形的物件。– CPalette :用於建立調色盤的物件。
•
Windows 的基本繪圖原理 ( 續 )
• MFC 的 DC Classes (CDC)– CClientDC :用於將資料輸出至視窗工作區。– CWindowDC :用於將資料輸出至視窗中,
包含工作區以外的區域。– CPaintDC :用於輸出回應 WM_PAINT 訊
息的資料。– CMetaFileDC :用於將資料輸出至特殊格式
的檔案中。
GDI's
DC's
基本繪圖函式• 畫點 (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);
基本繪圖函式 ( 續 )
• 畫弧 (arc) 函式與畫鐘 (chord) 函式BOOL CDC::Arc(int x1, int y1, int x2, int y2, int x3, int y3, in
t 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, in
t x4, int y4);
BOOL CDC::Pie(LPCRECT r, POINT Start, POINT End);
(x1,y1)
(x2,y2)
(x3,y3) (x4,y4)
Arc
AngleArc
(x,y)radius startAngle
sweepAngle
(x1,y1)
(x2,y2)
(x3,y3) (x4,y4)
Chord
(x1,y1)
(x2,y2)
(x3,y3) (x4,y4)
Pie
基本繪圖函式 ( 續 )
• 畫橢圓 (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
基本繪圖函式 ( 續 )
• 畫多邊形 (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);
物件 Collection
• CArray 樣板類別– 你可以用這個樣板將任何物件存在 array 內 ,
讓 array 可以視需要自動加大 .
CArray<ObjectType, ObjectType&> anArray
要存放的物件型態 成員函式的引數型態
Object1
Object2
Object3
Object4
Object5
Object6
Obj A
SetSize(5)
定義初始大小
自動增加
Index
0
1
2
3
4
5
6
GetAt(2)傳回物件
Add(Obj A)
存放物件
CList<ObjectType, ObjectType&> aList;
Object1
Object2
Object3
Object4
Obj B
Obj AAddHead(ObjA)
存放物件
傳回型態為 Position
的值
AddTail(ObjB)
大小的增加
是自動的
GetNext(aPos)
aPos
CMap<KeyType, KeyType&,ObjectType, ObjectType&> aMap;
Key1 Object1
Key2 Object2
Key3 Object3
Key4 Object4
aMap[Key2]=Object2
LookUp(Key3,AnObject)
#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; }} ;
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 = f
alse) = 0; //純虛擬函式 int GetShapeNum() { return shapenum; }//取得形狀代號 void SetPoint(CPoint SPnt, CPoint EPnt) { StartPnt = SPnt; EndPnt = EPnt; }// 設定起 ,終點} ;
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還原 }
} ;
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);
}
} ;
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()
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()
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;
}
}
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);
}
}
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 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()
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;
滑鼠訊息/視窗訊息
CMyView訊息處理方法
呼叫
形狀類別
繪圖方法
執行繪圖
視窗
1. 點選Afx_msg void MyView::OnRect
{
aShape = new rectangle;
}
3.拖曳2
Afx_msg MyView::OnMouseMove()
{
aShape->draw()
}
Virtual shape::draw()=0
Virtual rectangle:draw()
{}
3
4
5
6. 放開
7
Afx_msg MyView::OnLButtonUp()
{
aShape->draw()
}
調整視窗大小
重繪畫布
發出 WM_PAINT 訊息呼叫
MyView::OnDraw
存取MyDocument 中的 gArray
Class CGObject: public CObject
{
..
CGObject(){};
Void Serialize(CArchive & ar) { …};
DECLARE_SERIAL(CGObject);
};
IMPLEMENT_SERIAL(CGObject, CObject, 1)
1
2
3
4_1
4_2
Void CGObject::Serialize (CArchive & ar)
{
CObject::Serialize(ar);
If (ar.IsStoring())
{
ar << Shapenum << fill << fillcolor << linecolor
<< width << StartPnt << EndPnt;
}
Else
{ ar >> … }
}
Void CMyDocment::Serialize(CArchive & ar)
{
CObject::Serialize(ar);
gArray.Serialize(ar);
}
Void CMyDocument::AddObject(CGObject & g)
{
gArray.Add(g);
SetModifiedFlag(true);
}
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)