mfc简单绘图程序设计报告.docx

上传人:b****0 文档编号:9936297 上传时间:2023-05-22 格式:DOCX 页数:14 大小:85.77KB
下载 相关 举报
mfc简单绘图程序设计报告.docx_第1页
第1页 / 共14页
mfc简单绘图程序设计报告.docx_第2页
第2页 / 共14页
mfc简单绘图程序设计报告.docx_第3页
第3页 / 共14页
mfc简单绘图程序设计报告.docx_第4页
第4页 / 共14页
mfc简单绘图程序设计报告.docx_第5页
第5页 / 共14页
mfc简单绘图程序设计报告.docx_第6页
第6页 / 共14页
mfc简单绘图程序设计报告.docx_第7页
第7页 / 共14页
mfc简单绘图程序设计报告.docx_第8页
第8页 / 共14页
mfc简单绘图程序设计报告.docx_第9页
第9页 / 共14页
mfc简单绘图程序设计报告.docx_第10页
第10页 / 共14页
mfc简单绘图程序设计报告.docx_第11页
第11页 / 共14页
mfc简单绘图程序设计报告.docx_第12页
第12页 / 共14页
mfc简单绘图程序设计报告.docx_第13页
第13页 / 共14页
mfc简单绘图程序设计报告.docx_第14页
第14页 / 共14页
亲,该文档总共14页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

mfc简单绘图程序设计报告.docx

《mfc简单绘图程序设计报告.docx》由会员分享,可在线阅读,更多相关《mfc简单绘图程序设计报告.docx(14页珍藏版)》请在冰点文库上搜索。

mfc简单绘图程序设计报告.docx

mfc简单绘图程序设计报告

中原工学院计算机学院

 

MFC课程设计报告

 

网络工程091班

路林生

 

2010年12月30日

 

一、简单的绘图应用程序

1.1.设计内容

能够利用所学的基本知识,设计一个简单的绘图应用程序,具有以下功能:

①具备基本的图形绘制功能:

直线、圆、矩形;(必须实现的功能)②编辑功能包括:

具有橡皮拉线功能,允许鼠标拖放,能双击选中图形元素,能删除和剪切图形元素,能撤消最近的修改等;(这部分功能选做)③数据保存功能:

能够把图形数据保存到文件中必须实现的功能)。

1.2.设计目的

1 了解Windows编程的基础知识,掌握MFC应用程序的基本知识;

2 基本掌握面向对象程序设计的基本思路和方法;

3 掌握用VC++开发应用程序的的一般步骤和方法;

1.3.设计要求

1 用VC++进行编码,实现应用程序的功能。

注重编码质量,代码要有适当的注释;

2.详细设计与实现

2.1.基本思路

单文档,添加三个菜单项,直线、矩形、圆、添加一个变量区分点击相关菜单项,添加三个变量,一个记录起点,一个记录终点,一个记录类型。

创建序列化类,保存图形信息。

2.2.设计步骤及主要代码

//主要函数代码

afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);

afx_msgvoidOnLButtonUp(UINTnFlags,CPointpoint);

afx_msgvoidOnCancelMode();

afx_msgvoidOnDrawrectangle();

afx_msgvoidOnDrawround();

afx_msgvoidOnDrawline();

//保存起点

voidCTestdrawView:

:

OnLButtonDown(UINTnFlags,CPointpoint)

{

m_ptOrigin=point;

CView:

:

OnLButtonDown(nFlags,point);

}

//绘图

voidCTestdrawView:

:

OnLButtonUp(UINTnFlags,CPointpoint)

{

CClientDCdc(this);

CRectrectEllipse(m_ptOrigin,point);

intr=(int)sqrt((point.x-m_ptOrigin.x)*(point.x-m_ptOrigin.x)+

(point.y-m_ptOrigin.y)*(point.y-m_ptOrigin.y));//定义圆的半径

CRectrect(m_ptOrigin.x-r,m_ptOrigin.y-r,m_ptOrigin.x+r,m_ptOrigin.y+r);

dc.SelectStockObject(NULL_BRUSH);//定义一个正方形

switch(m_nType)

{

case1:

dc.Rectangle(rectEllipse);//矩形

break;

case2:

dc.Ellipse(rect);//圆

//dc.Arc(rectEllipse,m_ptOrigin,m_ptOrigin);

break;

case3:

dc.MoveTo(m_ptOrigin);//直线

dc.LineTo(point);

break;

}

}

//序列化保存

//定义的类支持序列化,分为五步:

1.从CObject或其派生类派生出用户的类

2.在类声明文件中,加入DECLARE_SERIAL宏。

编译时,编译器将扩充该宏,这是串行化对象所必需的。

3.重载Serialize()成员函数,加入必要的代码,用以保存对象的数据成员到CArchive对象以及从CArchive对象载入对象的数据成员状态。

4.定义一个不带参数的构造函数。

5.在实现文件中加入IMPLEMENT_SERIAL宏。

//设计步骤

步骤1:

新建一个MFC单文档应用程序。

步骤2:

在资源面板中修改原来的标准菜单,新插入一个菜单名为“绘图”,下面有3个菜单项

在CTestdrawView类中添加两个成员变量CPointm_ptOrigin和intm_nType,分别表示绘图的起点和绘图的类型,并在构造函数中初始化为0和-1。

在CTestdrawView中加入3个菜单项消息的响应函数,在消息响应函数中设置变量m_nType的值。

m_nType为1,表示矩形;m_nType为2,表示画圆;m_nType为3,表示画画线。

在CTestdrawView类中加入WM_LBUTTONDOWN和WM_LBUTTONUP的消息响应函数OnLButtonDown和OnLButtonUp 。

在OnLButtonDown中保存鼠标按下的点;在OnLButtonUp中,根据m_nType的值画相应的图形。

步骤3:

给工程添加一个可序列化的类CGraph。

1.新建一个类CGraph,从CObject派生。

打开工作台ClassView页面,鼠标右击最顶层的EX08_00classes,在弹出的快捷方式菜单中选择NewClass,在弹出的NewClass对话框上,在Classtype中要选GenericClass,在类名Name中输入CGraph,单击Baseclass下面列表框中DerivedFrom下面高亮显示的第一栏,输入将要派生的基类CObject,后面类型为publice,如图8-01所示,然后单击OK。

图8-01添加新类CGraph

当单击OK按钮添加该类时,会弹出一个如图8-02所示的对话框,该对话框提示ClassWizard无法为从CObject派生出的CGraph类找到合适的头文件。

我们不用理会它,在此消息框中单击确定按钮即可,因为合适的头文件已经包含在CGraph类中。

2.在CGraph类中重载Serialize()成员函数。

我们要实现序列化,先对其进行改造,在工作台的ClassView页面中选择CGraph类,单击鼠标右键,选择AddMemberFunction增加一个成员函数,在弹出的对话框中FunctiongType中输入void,在FunctionDeclaretion编辑框中输入Serialize(CArchive&ar),然后选择Public,按OK即可。

然后在ClassView中可以看到这个函数。

图8-02创建新类时的警告信息

在类CGraph的头文件中,加入DECLARE_SERIAL宏,代码如下:

classCGraph:

publicCObject

{

public:

voidSerialize(CArchive&ar);

CGraph();

virtual~CGraph();

DECLARE_SERIAL(CGraph)

};

要对CGraph类实现序列化,需要在类的.h文件中加入宏DECLARE_SERIAL的调用,这个宏不需要加分号,并且后面有一个参数表示添加序列化特性的类名。

4.定义一个不带参数的构造函数。

打开工作台的CGraph类,可以看到,不带参数的构造函数已经存在于类中了,这是我们最开始创建CGraph这个新类时自动添加的。

MFC在从磁盘文件载入对象状态并重建对象时,需要有一个缺省的不带任何参数的构造函数。

序列化对象将用该构造函数生成一个对象,然后调用Serialize()函数,用重建对象所需的值来填充对象的所有数据成员变量。

5.在类CGraph实现文件中加入IMPLEMENT_SERIAL宏。

打开类CGraph的实现文件,在该类的构造函数前添加MPLEMENT_SERIAL宏,代码如下:

//Graph.cpp:

implementationoftheCGraphclass.

//

//////////////////////////////////////////////////////////////////////

#include"stdafx.h"

#include"testdraw.h"

#include"Graph.h"

#include"math.h"

#ifdef_DEBUG

#undefTHIS_FILE

staticcharTHIS_FILE[]=__FILE__;

#definenewDEBUG_NEW

#endif

//////////////////////////////////////////////////////////////////////

//Construction/Destruction

//////////////////////////////////////////////////////////////////////

IMPLEMENT_SERIAL(CGraph,CObject,1)

CGraph:

:

CGraph()

{

}

可见,将该宏的调用添加在构造函数前,也不需要分号。

IMPLEMENT_SERIAL宏用于定义一个从CObject派生的可序列化类的各种函数。

宏的第一和第二个参数分别代表可序列化的类名和该类的直接基类。

第三个参数是对象的版本号,它是一个大于或等于零的整数。

MFC序列化代码在将对象读入内存时检查版本号。

如果磁盘文件上的对象的版本号和内存中的对象的版本号不一致,MFC将抛出一个CArchiveException异常,阻止程序读入一个不匹配版本的对象。

现在,我们就可以象使用标准MFC类一样使用CGraph的序列化功能了。

步骤4:

构造CGraph类,做准备工作。

在类CGraph的头文件中添加三个成员变量m_ptOrigin、m_ptEnd、m_nType。

我们既然想保存下来所画的图形,那么至少要保留住关于这些图形的一些信息,不管用户画的是线、矩形还是椭圆,它们都有一个共同点:

就是由两点决定这个图形,那么从起点到终点画的到底是什么图形,就要看m_nType的值了,因此这里定义了两个CPoint型的变量,用于保存用户所画的一组图形的各个起点和终点;另一个为int型变量用来指定所画的每个图形的类型。

classCGraph:

publicCObject

{

public:

CPointm_ptOrigin;//记录起始点

CPointm_ptEnd;//记录终点

intm_nType;//记录画图类型

voidSerialize(CArchive&ar);

CGraph();

virtual~CGraph();

DECLARE_SERIAL(CGraph)

};

给类CGraph添加一个带参数的构造函数

鼠标右击CGraph类,在弹出的快捷方式菜单中选择AddMemberFunction,函数类型(FunctionType)编辑框中什么都不填,因为构造函数没有返回值,函数声明(FunctionDeclaration)为CGraph(intm_drawType,CPointm_ptFrom,CPointm_ptTo),编辑这个带参数的构造函数,添加如下代码:

CGraph:

:

CGraph(intm_drawType,CPointm_ptFrom,CPointm_ptTo)

{

m_nType=m_drawType;

m_ptOrigin=m_ptFrom;

m_ptEnd=m_ptTo;

}

在这个对象构造函数中,用传递到构造函数的画图类型、起点和终点三个参数来初始化类CGraph中相应意义的三个变量。

步骤5:

在文档类CTestdrawDoc中定义一个成员变量,用于保存每一个图形对象。

现在已经有了一个可以用来表示用户所绘图形的对象,那么接下来的重点是如何将这些对象保存下来。

当用户画一个图形,就产生一个这样的图形对象,因此,这个对象是动态的不断增长的。

CObArray类是一个对象数组类,它可以动态调整自己的大小以适应放在它里面的元素的个数。

它可以存放任何从CObject类派生出的对象(如前面的CGraph对象),它的大小只受系统的内存空间的限制。

MFC中其他动态数组类包括CStringArray、CByteArray、CWordArray、CDWordArray、CPtrArray,它们的不同之处在于存放的对象的类型。

这里,我们鼠标右击CEX08_00Doc类,在弹出的快捷方式菜单中选择AddMemberVariable,变量类型为CObArray,变量名为m_obArray。

步骤6:

将用户画的每一个图形对象保存到m_obArray中。

要将图形对象保存到对象数组m_obArray中,首先就要得到对象的绘图类型和起点、终点,然后创建一个新的图形对象,并把它加入到对象数组m_obArray中。

我们知道,当用户按下鼠标左键,然后随之拖动出一个图形,最后当鼠标抬起的时候,那么就是这个图形对象生成的时候,因此,应该在CEX08_00View:

:

OnLButtonUp函数中保存图形对象。

在OnLButtonUp函数中的原来代码的尾部添加如下代码:

voidCTestdrawView:

:

OnLButtonUp(UINTnFlags,CPointpoint)

{……

CGraph*pGraph=newCGraph(m_nType,m_ptOrigin,point);

GetDocument()->m_obArray.Add(pGraph);

CView:

:

OnLButtonUp(nFlags,point);

}

这段代码中,首先声明一个CGraph类的一个指针对象,并且用该类的带参数的构造函数来构建这个对象,构造函数中的参数就是OnLButtonUp函数中用于画图的类型和起点、终点。

用户再回头看一看CGraph类中带参数的构造函数,就会明白,实际上构造函数传递过来的参数是为了初始化CGraph类的三个成员变量m_ptOrigin、m_ptEnd、m_nType,这三个成员变量构成了一个CGraph类对象,然后将该对象通过m_obArray.Add保存到对象数组中。

由于对象数组是在文档类中定义的,在视图类中不能直接引用,因此,前边需要调用GetDocument函数来取得访问文档类的权利。

最后别忘了在视图类的实现文件中添加#include"Graph.h",将类CGraph的头文件包含进来。

步骤7:

在CGraph类中完成绘图功能。

CGraph类对象中包含着三个重要的画图参数,因此,这个对象是可以绘制自身的,当视图类需要重绘图形时,它只需要向该类发送一条消息,告诉它要绘制自己就可以了。

鼠标右击CGraph类,选择AddMemberFunction,函数类型(FunctionType)为void,函数声明(FunctionDeclaration)为Draw(CDC*pDC),在该函数中添加如下代码:

voidCGraph:

:

Draw(CDC*pDC)

{

pDC->SelectStockObject(NULL_BRUSH);

intr=(int)sqrt((m_ptEnd.x-m_ptOrigin.x)*(m_ptEnd.x-m_ptOrigin.x)+

(m_ptEnd.y-m_ptOrigin.y)*(m_ptEnd.y-m_ptOrigin.y));

CRectrect(m_ptOrigin.x-r,m_ptOrigin.y-r,m_ptOrigin.x+r,m_ptOrigin.y+r);

switch(m_nType)

{

case1:

pDC->Rectangle(m_ptOrigin.x,m_ptOrigin.y,m_ptEnd.x,m_ptEnd.y);

break;

case2:

pDC->Ellipse(rect);

break;

case3:

pDC->MoveTo(m_ptOrigin);

pDC->LineTo(m_ptEnd);

break;

}

}

在CGraph类中绘图,Draw函数中用到三个绘图参数就是CGraph类的三个成员变量。

步骤8:

在CEX08_00View:

:

OnDraw函数中绘图,在OnDraw函数中添入如下代码:

voidCTestdrawView:

:

OnDraw(CDC*pDC)

{

CTestdrawDoc*pDoc=GetDocument();

if(pDoc->m_obArray.GetSize())

{

for(inti=0;im_obArray.GetSize();i++)

{

((CGraph*)pDoc->m_obArray.GetAt(i))->Draw(pDC);

}

}

}

在这个函数中,首先判断数组对象中是否有元素,即是否有图形需要绘制,如果没有就什么都不做,如果有元素,那么就通过for循环从文档类的数组对象中依次取出图形对象(包括三个重要绘图参数),然后调用图形对象的Draw函数,即第7步骤中的Draw函数。

到现在,这个绘图程序就具备了重绘的功能,无论窗口怎样改变,用户所绘制的图形依然显示在窗口上。

下面我们继续给它添加保存和再显示的功能。

步骤9:

保存和再显示图形。

打开CEX08_00Doc:

:

Serialize函数,将原来的代码删除,添加如下代码:

voidCTestdrawDoc:

:

Serialize(CArchive&ar)

{

m_obArray.Serialize(ar);

}

这里利用了CObArray类的功能。

在文档类的Serialize函数中调用对象数组的Serialize函数,该对象数组将会把指令向下传递到对象数组中,并调用每个对象的Serialize函数。

因此,下面我们将完善CGraph类的Serialize函数。

完善CGraph:

:

Serialize()函数,代码如下:

voidCGraph:

:

Serialize(CArchive&ar)

{

if(ar.IsStoring())

ar<

else

ar>>m_nType>>m_ptOrigin>>m_ptEnd;

}

在上面的代码中我们用到了>>和<<,在这里对它们作一个介绍,>>和<<是一种操作符,用来指示向CArchive对象读取还是保存数据,必要时我们可以重载重定向符。

如ar>>m_nType>>m_ptOrigin>>m_ptEnd;这一句,其中>>表示从ar中读出数据m_nType,m_ptOrigin和m_ptEnd,这个符号及>>可以连用,亦可以分开来用,如ar>>m_nType;ar>>m_ptOrigin;同样ar<

需要注意的是,三个变量读取和保存的顺序一定要和在类CGraph中带参数的构造函数中三个参数的声明顺序是一致的。

现在编译运行这个程序,随意画几个图形,然后选择菜单“文件”|“保存”,在弹出的“保存”对话框中输入文件名将所画图形保存到文件中,然后关闭应用程序,再重新运行该应用程序,选择“文件”|“打开”菜单,在弹出的“打开”对话框上双击先前保存有图形的文件,就可以看到先前保存的图形再一次显示在窗口上了。

//工程信息

//工程文件信息

2.运行调试

3.心得体会

通过对本系统的设计,我进一步熟悉了,绘图的相关函数,以及文档序列化保存,序列化类的概念。

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2