複製內容到剪貼板
代碼:
#include <afxwin.h>
#include "resource.h"
#include <afxtempl.h>
#include <afxext.h>
#include <math.h> //增加math標頭檔
class GraphicObject : public CObject
{ //儲存形狀物件的類別,衍生自CObject類別以便具備儲存(Serialize)功能
public:
int shapenum; //形狀代號
BOOL fill; //是否填滿
COLORREF FillColor, LineColor; //填滿顏色與外框顏色
int width; //外框寬度
CPoint StartPnt, EndPnt; //形狀的起點與終點
GraphicObject(){} //預設建構子
//一般建構子
GraphicObject(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) {}
GraphicObject(GraphicObject & g) //複製建構子
: shapenum(g.shapenum), fill(g.fill), FillColor(g.FillColor),
LineColor(g.LineColor), width(g.width), StartPnt(g.StartPnt),
EndPnt(g.EndPnt) {}
//過載=運算子
GraphicObject & operator= (GraphicObject & g){
shapenum = g.shapenum;
fill = g.fill;
FillColor = g.FillColor;
LineColor = g.LineColor;
width = g.width;
StartPnt = g.StartPnt;
EndPnt = g.EndPnt;
return *this;
}
//GraphicObejct::Serialize
void Serialize(CArchive & ar)
{
CObject::Serialize(ar);
if(ar.IsStoring()) //判斷是否為存檔
{ //輸出至檔案
ar << shapenum << fill << FillColor << LineColor
<< width << StartPnt << EndPnt;
}
else
{ //從檔案輸入
ar >> shapenum >> fill >> FillColor >> LineColor
>> width >> StartPnt >> EndPnt;
}
}
DECLARE_SERIAL(GraphicObject) //宣告為可Serialize的類別
};
//宣告GraphicObject為可Serialize的類別
IMPLEMENT_SERIAL(GraphicObject, CObject, 1)
class Shape //形狀類別的基礎類別
{
protected:
CPoint StartPnt, EndPnt; //定義形狀的終點與起點
int shapenum; //形狀代號
friend class MyView; //將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; //設定終點
return *this;
}
//Shape::draw
virtual void draw(CDC & aDC, COLORREF color, COLORREF fcolor,
int width,BOOL Filled = false) = 0;
//Shape::GetShapeNum
int GetShapeNum() //取得形狀代號
{ return shapenum; }
//Shape::SetPoint
void SetPoint(CPoint SPnt, CPoint EPnt) //設定形狀的起點、終點
{
StartPnt = SPnt;
EndPnt = EPnt;
}
};
class Line : public Shape //直線類別
{
public:
friend class MyView;
//預設建構子
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物件
dc.MoveTo(StartPnt); //移至直線起點
dc.LineTo(EndPnt); //移至直線終點
dc.SelectObject(oldPen); //還原選取的畫筆物件
}
};
class ellipse : public Shape //橢圓形類別
{
public:
//預設建構子
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;
}
//ellipse::draw 繪出橢圓
void draw(CDC & dc, COLORREF color, COLORREF fcolor,
int width,BOOL Filled = false)
{
CRect rect(StartPnt, EndPnt); //建立CRect物件
CPen pen(PS_SOLID, width, color); //建立畫筆物件
CPen *oldPen = dc.SelectObject(&pen); //設定DC物件使用pen物件
dc.SelectStockObject(NULL_BRUSH); //設定DC物件不使用畫筆
dc.Ellipse(rect); //繪出橢圓形
dc.SelectObject(oldPen); //還原畫筆物件
}
};
class rectangle : public Shape //矩形類別
{
public:
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;
}
//rectangle ::draw 繪出矩形
void draw(CDC & dc, COLORREF color, COLORREF fcolor,
int width, BOOL Filled = false)
{
CRect rect(StartPnt, EndPnt); //建立CRect物件
CPen pen(PS_SOLID, width , color); //建立畫筆物件
CPen *oldPen = dc.SelectObject(&pen); //設定DC物件使用pen物件
dc.SelectStockObject(NULL_BRUSH); //設定DC物件不使用無畫刷
dc.Rectangle(rect); //繪出矩形
dc.SelectObject(oldPen); //還原畫筆物件
}
};
class MyDocument : public CDocument
{
private:
CArray<GraphicObject , GraphicObject> gArray;
//儲存GraphicObject物件的CArray容器物件
public:
MyDocument() {}
//MyDocument::AddObject
void AddObject(GraphicObject & g) //增加GraphicObject物件
{
SetModifiedFlag(true); //設定檔案已被修改
gArray.Add(g);
}
//MyDocument::GetObject 取得容器中第i個GraphicObject物件
GraphicObject & GetObject(int i){ return gArray[i]; }
//MyDocument::GetSize
int GetSize() //取得CArray容器目前儲存的元素數目
{ return gArray.GetSize(); }
//MyDoucment::Serialize
void Serialize(CArchive & ar)
{
CObject::Serialize(ar); //呼叫CObject::Serialize
gArray.Serialize(ar); //呼叫CArray::Serialize儲存容器中的元素
}
//MyDocument::DeleteContents
void DeleteContents()
{
gArray.RemoveAll(); //刪除容器中所有元素
CDocument::DeleteContents(); //呼叫CDocument::DeleteContents
}
DECLARE_DYNCREATE(MyDocument)
DECLARE_MESSAGE_MAP()
};
IMPLEMENT_DYNCREATE(MyDocument, CDocument)
BEGIN_MESSAGE_MAP(MyDocument, CDocument)
END_MESSAGE_MAP()
class MyFrame : public CFrameWnd //視窗框架類別
{
protected:
CMenu * menu;
public:
CToolBar toolbar; //視窗框架中的工具列物件
CStatusBar statusbar; //視窗框架中的狀態列物件
//建構子與解構子
MyFrame(){}
~MyFrame(){}
//MyFrame::OnCreate,回應OnCreate的函數
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if(CFrameWnd::OnCreate(lpCreateStruct))
return 1;
toolbar.Create(this); //建立工具列物件
toolbar.LoadToolBar(IDR_MyFrame); //載入工具列資源
toolbar.EnableDocking(CBRS_ALIGN_ANY);
//設定工具列在視窗中可停靠的位置
toolbar.SetBarStyle( toolbar.GetBarStyle() | CBRS_TOOLTIPS |
CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
//設定工具列的形式
EnableDocking(CBRS_ALIGN_ANY); //設定視窗可讓工具列停靠的位置
DockControlBar(&toolbar); //將工具列加入視窗框架
//建立與狀態列對應之字串資源代號
static UINT indicators[] =
{
ID_SEPARATOR,
IDS_Color,
IDS_Shape,
IDS_Width //顯示筆寬
};
statusbar.Create(this); //在目前的視窗框架裡,建立一個狀態列
statusbar.SetIndicators(indicators, sizeof(indicators) / sizeof(UINT));
//連結狀態列欄位與字串資源代號
return 0;
}
DECLARE_DYNCREATE(MyFrame) //宣告為Run-Time類別
DECLARE_MESSAGE_MAP()
};
IMPLEMENT_DYNCREATE(MyFrame, CFrameWnd)
//宣告MyFrame為Run-Time類別
BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)
ON_WM_CREATE() //回應建立視窗的訊息
END_MESSAGE_MAP()
class MyView : public CView
{
private:
COLORREF lcolor, fcolor;
//lcolor為形狀外框的顏色,fcolor為填滿形狀內部的顏色
Shape* aShape; //指向欲繪製之形狀類別的物件指標
Shape* rdShape; //rdShape為重繪視窗時,從Document中取得形狀物件
int width; //形狀的外框寬度
public:
//建構子
MyView()
{
lcolor = RGB(255,0,0); //設定外框顏色的起始值
aShape = new Line; //設定形狀的起始值
fcolor = RGB(0,0,0); //設定填滿顏色的起始值
width = 2; //形狀的外框寬度的起始值
}
//解構子
~MyView() { }
//MyView::GetWidth
int GetWidth() { return width;} //傳出MyView物件設定的筆寬
//MyView::OnSetWidth
afx_msg void OnSetWidth(); //定義函數的程式片段在SWidthDlg類別後
//MyView::OnEllipse
afx_msg void OnEllipse()
{
aShape = new ellipse; //產生橢圓形物件
((MyFrame *)GetParentFrame())->statusbar.SetPaneText(2,"Ellipse");
//設定狀態列IDS_Shape欄位的顯示文字
}
//MyView::OnRect
afx_msg void OnRect()
{
aShape = new rectangle; //產生矩形物件
((MyFrame *)GetParentFrame())->statusbar.SetPaneText(2,"Rectangle");
//設定狀態列IDS_Shape欄位的顯示文字
}
//MyView::OnLine
afx_msg void OnLine()
{
aShape = new Line; //產生直線物件
((MyFrame *)GetParentFrame())->statusbar.SetPaneText(2,"Line");
//取得Document物件,並呼叫CStatusBar::SetPaneText設定狀態列
//IDS_Shape欄位的顯示文字
}
//MyView::OnDraw
afx_msg void OnDraw(CDC * aDC) //回應重繪視窗訊息的函數
{
MyDocument *doc = (MyDocument *)GetDocument();
//取得目前的Document物件
int num = doc->GetSize(); //取得目前Document物件中儲存的形狀物件個數
CView::OnDraw(aDC); //呼叫CView類別的OnDraw成員函數
int i;
for(i = 0; i < num; ++i) //取得儲存於Document物件中的形狀物件
{
GraphicObject * object = &(doc->GetObject(i));
//建立指向繪圖物件的指標,並指向由Document物件中的形狀物件
switch(object->shapenum){ //判別從Document物件取得哪種形狀物件
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; //刪除前面產生的形狀物件
}
}
//MyView::OnLButtonDown
afx_msg void OnLButtonDown(UINT, CPoint point)
{
SetCapture(); //取得滑鼠訊息的接收權
if (this == GetCapture()) //判斷滑鼠游標是否在正在執行的視窗中
(*aShape).StartPnt = (*aShape).EndPnt = point;
//設定形狀物件的起點、終點
}
//MyView::OnMouseMove
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); //再畫出形狀物件
}
}
//MyView::OnLButtonUp
afx_msg void OnLButtonUp(UINT, CPoint point)
{
if (this == GetCapture()) //判斷滑鼠游標是否在正在執行的視窗中
{
CClientDC aDC(this); //建立畫布
(*aShape).EndPnt = point;
//設定形狀物件的終點
(*aShape).draw(aDC, lcolor, fcolor, width); //畫出形狀物件
GraphicObject object(aShape->GetShapeNum(), true,
fcolor, lcolor, width,aShape->StartPnt,aShape->EndPnt);
//建立GraphicObject物件,以儲存繪於視窗工作區的形狀物件
MyDocument *doc = (MyDocument *)GetDocument();
//取得目前的Document物件
doc->AddObject(object); //將GraphicObject物件儲存進Document物件
ReleaseCapture(); //釋放滑鼠訊息接收權
}
}
//MyView::OnRed
afx_msg void OnRed()
{
lcolor = RGB(255, 0, 0); //設定圖形外框為紅色
((MyFrame *)GetParentFrame())->statusbar.SetPaneText(1,"Red");
//設定狀態列IDS_Color欄位的顯示文字
}
//MyView::OnBlue
afx_msg void OnBlue()
{
lcolor = RGB(0, 0, 255); //設定圖形外框為藍色
((MyFrame *)GetParentFrame())->statusbar.SetPaneText(1,"Blue");
//設定狀態列IDS_Color欄位的顯示文字
}
//MyView::OnGreen
afx_msg void OnGreen()
{
lcolor = RGB(0, 255, 0); //設定圖形外框為綠色
((MyFrame *)GetParentFrame())->statusbar.SetPaneText(1,"Green");
//設定狀態列IDS_Color欄位的顯示文字
}
//控制設定形狀物件的UI元件
//MyView::OnUpdateEllipse
afx_msg void OnUpdateEllipse(CCmdUI * aCmdUI)
{ aCmdUI->SetCheck((*aShape).shapenum == 1); }
//MyView::OnUpdateRect
afx_msg void OnUpdateRect(CCmdUI * aCmdUI)
{ aCmdUI->SetCheck((*aShape).shapenum == 2); }
//MyView::OnUpdateLine
afx_msg void OnUpdateLine(CCmdUI * aCmdUI)
{ aCmdUI->SetCheck((*aShape).shapenum == 0); }
//控制設定形狀物件的UI元件
//MyView::OnUpdateRed
afx_msg void OnUpdateRed(CCmdUI * aCmdUI)
{ aCmdUI->SetCheck(lcolor == RGB(255, 0, 0)); }
//MyView::OnUpdateGreen
afx_msg void OnUpdateGreen(CCmdUI * aCmdUI)
{ aCmdUI->SetCheck(lcolor == RGB(0, 255, 0)); }
//MyView::OnUpdateBlue
afx_msg void OnUpdateBlue(CCmdUI * aCmdUI)
{ aCmdUI->SetCheck(lcolor == RGB(0, 0, 255)); }
DECLARE_DYNCREATE(MyView) //宣告Run-Time物件
DECLARE_MESSAGE_MAP()
};
IMPLEMENT_DYNCREATE(MyView, CView)
//宣告MyView為Run-Time物件
BEGIN_MESSAGE_MAP(MyView, CView)
ON_COMMAND(IDM_Width, OnSetWidth) //設定筆寬
//回應滑鼠訊息
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_Rect, OnRect)
//回應UI元件狀態控制訊息
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_Rect, OnUpdateRect)
END_MESSAGE_MAP()
class SWidthDlg : public CDialog //與IDD_SWidthDlg對話盒對應之類別
{
private:
int width; //筆寬
CEdit * wEdit; //編輯控制項物件
public:
//建構子
SWidthDlg(CWnd *parent) : CDialog(IDD_SWidthDlg, parent)
//將IDD_SWidthDlg對話盒與SWidthDlg類別連結
{ width = 2; }
//SWidthDlg::Getwidth 傳出使用者設定之欄寬
int GetWidth() { return width;}
//SWidthDlg::OnInitDialog IDD_SWidthDlg對話盒起始設定
BOOL OnInitDialog()
{
char strWidth[5];
CDialog::OnInitDialog(); //呼叫CDialog::OnInitDialog
wEdit = (CEdit *)GetDlgItem(IDC_Width);
//將IDD_SWidthDlg對話盒的IDC_Width編輯控制項與wEdit物件連結
MyView *view = (MyView *)m_pParentWnd;
//取得目前的View物件
wsprintf(strWidth, "%d", view->GetWidth());
//將目前View物件設定的筆寬輸出strWidth字串中
wEdit->ReplaceSel(strWidth);
//將View物件目前設定的筆寬顯示在IDC_Width編輯控制項中
return TRUE;
}
//SWidthDlg::OnOK
void OnOK()
{
CString strWidth;
wEdit->GetWindowText(strWidth); //取得使用者設定的筆寬
try{
width = StrToInt(strWidth); //將目前的筆寬由文字轉換為數字
if (width > 20) //如果筆寬大於20則都出例外
throw ("Width is greater than 20.");
CDialog::OnOK(); //呼叫CDialog::OnOK
}
catch(const char * str) //如果產生字串例外,則蹦現顯示錯誤訊息的訊息方塊
{ MessageBox(str,"Input Error", MB_OK); }
}
//SWidthDlg::StrToInt
int StrToInt(CString & str)
{
int len = str.GetLength(); //先取得字串長度,做為數字位數
int res = 0; //轉換結果
for (int i = 0; i < len; ++i)
{
switch(str[i]) //將字串的每個文字至換成數字
{
case '0':
break;
case '1':
res += (int) pow(10, (len-i-1)) * 1;
//將取得的數字,乘以其位數
break;
case '2':
res += (int) pow(10, (len-i-1)) * 2;
break;
case '3':
res += (int) pow(10, (len-i-1)) * 3;
break;
case '4':
res += (int) pow(10, (len-i-1)) * 4;
break;
case '5':
res += (int) pow(10, (len-i-1)) * 5;
break;
case '6':
res += (int) pow(10, (len-i-1)) * 6;
break;
case '7':
res += (int) pow(10, (len-i-1)) * 7;
break;
case '8':
res += (int) pow(10, (len-i-1)) * 8;
break;
case '9':
res += (int) pow(10, (len-i-1)) * 9;
break;
case'-': //如果讀取到負號,則丟例外
throw ("Don't input a nagtive number.");
break;
}
}
return res; //傳回轉換結果
}
};
//MyView::OnSetWidth
afx_msg void MyView::OnSetWidth()
{
SWidthDlg dlg(this);
//建立設定筆寬的對話盒物件,並傳入父視窗物件
char str[10];
if (dlg.DoModal() == IDOK) //使用者若按下確定按鈕則傳出IDOK
{
width = dlg.GetWidth(); //取得使用者設定的筆寬
wsprintf(str, "Width : %d ", width); //將筆寬輸出到str字串
((MyFrame *)GetParentFrame())->statusbar.SetPaneText(3,str);
//設定狀態列的IDS_Width欄位
}
}
class MyApp : public CWinApp //應用程式物件
{
public:
BOOL InitInstance()
{
CDocument *aDOC;
CSingleDocTemplate *aDocTemplate;
aDocTemplate = new CSingleDocTemplate( //建立單一文件框架
IDR_MyFrame,
RUNTIME_CLASS(MyDocument),
RUNTIME_CLASS(MyFrame),
RUNTIME_CLASS(MyView));
AddDocTemplate(aDocTemplate);
//將單一文件框架加入應用程式物件
aDOC = aDocTemplate->CreateNewDocument();
//建立Document物件
CFrameWnd *Frame = aDocTemplate->CreateNewFrame(aDOC, NULL);
//建立視窗框架物件
m_pMainWnd = Frame; //建立應用程式物件使用之視窗框架
aDocTemplate->InitialUpdateFrame(Frame, aDOC);
//起始化View物件
Frame->ShowWindow(SW_SHOW);
//顯示視窗框架
return true;
}
DECLARE_MESSAGE_MAP()
} a_app; //應用程式物件
BEGIN_MESSAGE_MAP(MyApp, CWinApp)
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) //開啟新檔
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) //開啟舊檔
END_MESSAGE_MAP()
[
本帖最後由 philxyz0316 於 2006-8-27 13:04 編輯 ]