《面向对象可视化编程》课程设计
总结报告
院 (系):计算机科学学院
专业班级:
学 号:
姓 名:
指导教师:
课设时间:
课设地点:
目录
一、课程设计目的
二、课程设计的内容与设计思路
三、程序实现过程与细节
(一)创建MFC应用程序
(二)类的设计和编写
1.类的设计
2.绘图原理
3.类的编写
(三)对话框控件
四、运行效果
五、设计小结
六、主要代码清单
指导老师意见:
一、课程设计目的
参加本课程设计的我们已经学习了《C语言程序设计》和《面向对象可视化编程》两门课程,现在需要通过一个相对实际性的开发过程来巩固与鉴定一下学习成效,可以查看离实际需要还有哪些部分没有完全掌握,需要加强;另外本课程设计可以提供一个稍微具有规模的程序开发的例子,让我们可以体会到程序的构思、编码以及调试的完整过程,最后并总结课程设计的过程。
二、课程设计的内容与设计思路
要求编制一个简单的图形编辑的系统,可以添加、修改与删除图形元素,以形成图形画面。功能:
(1) 通过菜单项添加图形
(2) 双击右键删除图形
(3) 将图形保存到文件中
(4) 打开图形文件
(5) 新建文件
(6) 双击左键修改图形
(7) 按ctrl+鼠标左键添加图形。
简而言之,系统的功能是创建,修改,删除图形,具体的程序和用户的交互逻辑是按住 Ctrl键 + 点击鼠标左键来创建图形,鼠标左键双击编辑修改图形,鼠标右键双击删除图形。
此程序的开发工作量较大,编写此程序时,可分多个阶段进行。每个开发阶段实现一些相关的功能,然后测试,这样可以及时纠正设计和编码过程中产生的问题,避免问题积累过多而导致难以着手解决。
a.采用单文档方式,文档中存储图形画面的各个图元数据,视图负责图形的绘制。
b.文档支持图形的序列化(连载),提供新建、打开、保存等操作。
c.视图除了绘制图形,还提供图形交互,能够按住Ctrl键再鼠标左键单击来创建图元,鼠标左键双击编辑修改图元属性,鼠标右键双击删除图元。
d.图元创建与修改时的参数由参数对话框来编辑。创建时以鼠标左击时光标的所在位置作为基点来创建图元。
e.使用图元基础类shape作为所有六个图元类的基类,设计派生各个具体的图形类,要求支持上述功能。
我们的最终目的是显示一个单文档窗口,且可利用从对话框中输入的数据绘制图形。所以,首先建立一个单文档程序,先从Shape类入手,逐步实现六个图形的绘制, 然后再实现序列化和文件打开与保存等功能。最后,实现6个图形类的IsMatched()方法及创建对话框,并给对话框中的各控件添加消息响应函数,进行控件关联,并利用枚举型使参数传递,逐渐完善图形属性对话框CShapeDlg类,最终完成设计任务。
Shape类设计如下图:
三、程序实现过程与细节
(一)创建MFC应用程序
打开VS2017,新建一个项目,点击 文件 —> 新建 —> 项目,使用 Visual C++ 模版中的 MFC 模版,选择 MFC应用程序,输入解决方案名称(Drawing)和项目名称(Drawing),然后点击确定即可。
接着使用 MFC 的应用程序向导(可以帮助我们快速搭建 MFC 应用程序所需的框架文件,我们通过它,可以更改 MFC 应用向导默认的项目设置)来创建我们的 MFC 应用程序。
根据我们的课程设计任务书上的要求,我们的应用程序类型是单个文档类型,项目样式是MFC standard,我们改一下。注意这个 文档/视图结构支持 需要选中,因为视图是我们绘图的地方,文档是我们存放图形的地方。
文档模版属性,主框架标题的名称和我们项目的名称一样,文档类型的名称也是,我们不需要改什么,直接点击下一步。
用户界面功能与高级功能按照VS2017默认即可。最后一步,生成的类,这里我们可以看到生成了四个类,CDrawingView,CDrawingApp,CDrawingDoc,CMainFrame。
其实应用程序还帮我们创建了一个说明本程序的关于对话框类,CAboutDlg,这个类在 Drawing.cpp 文件中,我们在后面会详细讲解这个对话框类。
在下面我们可以清楚的看到这四个类对应的 类名,基类,.h 头文件 和 .cpp 源文件。
CDrawingView 的基类,默认是 CView 基类,我们可以选择带垂直和水平滚动条的 CScrollView 类,它是从 CView 类继承过来的。
将基类的CView改为CScrollView,
注:
CDrawingApp应用程序类:负责启动和初始化Windows程序;创建CMainFrame类主框架窗口、CDrawingDoc类文档和CDrawingView类视图,以及框架窗口、文档、视图之间的连接;创建程序菜单,并将“文件-新建”、“文件-打开”、“帮助-关于”等菜单消息映射到对应的成员函数。
CMainFrame主框架窗口类:在SDI中,作为应用程序的主窗口,负责创建框架窗口的工具栏、状态栏。
CDrawingDoc文档类:负责存储文档的内部数据对象(本例为正方形、矩形、圆、椭圆、正三角形、文字等6种图形对象),并提供序列化*(Serialize)技术实现文档内部数据对象的文件读、写操作。
CDrawingView视图类:负责对文档数据对象的显示,以及对象数据的编辑等用户交互操作。
最后,点击完成。
至此,MFC应用程序成功创建。可以点击运行程序,我们会看到有一个Windows 窗口程序的样子。
(二)类的设计和编写
1.类的设计
我们要用面向对象的思想来看我们这个应用程序,我们要在计算机中绘制某个图形,我们是不是可以把这个图形看成一个对象,这个对象有什么特点,就是我们类中的成员变量,或者说是属性,我们对这个对象的操作就是类中的成员函数、或者说是方法。
先来分析类所需要的属性,我们需要绘制正方形,矩形,圆形,椭圆形,正三角形,文本六种类型的图形,看一看这些图形的特点。
图上的黑点给图元的原点,w为宽度width,h为高度height,r为半径radius,a为字符角度angle。这些为这些图元需要保存的参数,另外,每个图元是否填充,用什么模式填充
可以找到了图形之间的相同点,也发现了图形之间的差异,类的设计就是抽出这些异同点。
2.绘图原理
在 Windows 系统中,我们看到的每一个图像都是绘制出来的,绘制过程和平时画图类似。大致的步骤为:获取设备环境,设置坐标映射,创建绘图工具,调用绘图函数绘图。显示器、打印机都是设备环境,显示器有大有小,分辨率也有高低,硬件环境很复杂。而我们编程人员,并不需要关注太多底层的信息,我们使用这些设备要通过操作系统来间接调用,Windows 系统为我们封装了绘制图形的相关函数,我们只需要学会使用他们。前面说到 MFC 是对 WIndows API 函数的一种封装,MFC 中当然也封装了有和绘图相关的类。设备环境类 CDC,用于设置绘图的属性(例如边框类型和填充类型)和绘制图形。绘图对象类 CBrush,CFont,Cpen等,根据设备环境类的设置绘制具体的图形。和我们在纸上画图一样,我们知道了图形怎么画,还要给要画的图形定个位置,也就是图形坐标。在 Windows 坐标系中,X 轴正方向向右,Y轴正方向向下。Windows 坐标系分为逻辑坐标系和设备坐标系两种,这是两种不同的记录位置的方式。设备坐标系要考虑物理设备具体的大小,以物理设备的一个像素点位单位设置坐标的单位长度。
而逻辑坐标系不考虑物理设备的具体大小,也是我们我们写程序时绘制图形采用的坐标系,而图形在绘制时,Windows 在把逻辑坐标转换为设备坐标。关于绘图的相关知识,可以在CSDN看看这篇文章,MFC GDI 绘图基础。(可以打开该链接)
3.类的编写
(1)编写一个基类,其他图形类继承该类。
添加Shape.h和Shape.cpp。因为要绘制不同图形,每一个图形就是一个对象,所以程序中要给出描述图形对象共性的类的定义,即要给出图形类的定义。打算用Shape.h存放图形类的声明,Shape.cpp存放图形类的定义。
(2)声明和定义基类CShape。本程序要绘制六种图形,六种图形有一些相同的属性和操作,例如绘制时都要指定画笔颜色、风格、宽度,指定画刷的填充图案、填充颜色,指定图形的位置等,都有绘图操作等。为了便于使用统一的接口操作六种图形,可为六个图形类定义一个基类,基类中包含图形类的共性,六个图形类从基类派生。这样可以提高代码的利用率,也方便程序扩充。
基类中的属性肯定是所有图形子类共有的属性,其中包括绘图位置的坐标点X、Y,边框的颜色、线型、宽度,填充的颜色,类型。公共的方法有绘图的方法,修改图形的方法,删除图形的方法,还有保存的方法。
绘图位置的坐标点X、Y,不要求绘制图形时位置多么精准,坐标使用 int 类型即可
边框的颜色,填充的颜色,使用 MFC 中的数据类型 COLORREF
线型、宽度,类型,都使用 int 类型
注意:在第一阶段CShape类可不需要IsMatched 和Serialize函数。
MFC的中的基本类CObject中有序列化函数 Serialize() 专门是针对对象保存的,我们可以让图形类的基类继承该类,然后在子类中实现序列化函数。但是要想使用序列化函数,还需要声明和实现序列化的方法,这样该类才能被序列化。序列化包括将具体的对象保存成二进制文件,也可称为是保存文件操作;还有将二进制文件中的对象信息读取出来,可称为读取文件。但是我们想把对象保存起来,还需要知道对象的类型,便于区分各个对象的类型,所以我们还需要在基类的属性中加上图形的类型。
图形的类型是有限的,这里我们可以用枚举类型来表示图形的类型。为了便于子类的继承,我们把基类的共有属性和共有方法都用 public 修饰符修饰。
(3)声明和定义CSquare类(任务书上的代码是CSquare的声明,注意Shape.cpp中要包含#include"stdafx.h" 和 #include"Shape.h"(VS2017自动生成),CSquare类的Draw函数的代码见指导书)
(4)在文档类CDrawingDoc中声明一个存储所有图形对象的成员CObArray m_Elements;选用动态数组存储较好。
(5)为“正方形”菜单项添加代码。DrawingView.cpp中应包含#include “Shape”。
(6)编写CDrawingView类中的OnDraw函数
(7)实现右键双击删除图形的功能
(i)在Shape.h中的CShape和CSquare类的声明中增加IsMatched函数的声明
(ii)在Shape.cpp中添加CSquare::IsMatched函数的定义
(iii)为CDrawingView类添加双击右键的WM_RBUTTONDBLCLK消息函数
(8)首先要使图形类支持序列化,一个类要支持支持序列化Serialize,必须从CObject派生,并且在类的声明(.h文件)中包含DECLARE_SERIAL申明,在类的实现(.cpp)中包含IMPLEMENT_SERIAL申明(见任务书)。文档的存储主要通过文档类重载成员函数Serialize来实现。
(9)实现新建文件功能。要在DrawingDoc.cpp文件中添加#include"Shape.h"
为CDrawingDoc类重写DeleteContents函数,在函数内添加代码。
在CDrawingDoc::OnNewDocument函数中调用CDocument::SetModifiedFlag()。
(10)实现双击左键修改图形的功能
a.在项目中添加一个名字为ShapeDlg的对话框
b.设计对话框界面,设置组合框、列表框的控件属性(Data\Sort)
c.为对话框添加一个类CShapeDlg
d.为对话框中的组合框、编辑框、列表框、颜色控件添加变量。
e.在类CShapeDlg中声明访问权限为public的成员变量。
f.为对话框上的组合框、列表框、颜色控件添加事件处理程序
g.为CShape类添加成员函数
h.为CSQuare类添加成员函数
i.为CShapeDlg添加函数
j.为CShapeDlg::OnInitDialog函数添加代码
k.将对话框的“确定”按钮的ID改为IDOK,为“取消”按钮添加代码
l.为CDrawingView类添加双击左键的WM_LBUTTONDBLCLK消息函数
(11)实现按ctrl+鼠标左键添加图形功能,为CDrawingView类添加WM_LBUTTONDOWN消息函数。
(12)以上就是用MFC应用程序实现画正方形,后面的还有五种类型的图形的绘制步骤类似于绘制正方形的步骤,其中的代码将在第六步给出。
(三)对话框控件
资源视图中 Dialog 资源看一看,有个我们刚刚创建的对话框资源,点击,可以看到一个初始的对话框,点击预览按钮,就可以看到对话框运行起来的模样。课程设计任务书中,给我们一个对话框的参考图,我们可以仿着这个图来做。这个界面上的这些东西,我们称之为控件,这个示例图上是由不同类型的控件组成的界面。我们先来认识一下这些控件,图上的图元类型、原点X、宽度、线宽、填充风格等这些都是用的静态文本框控件,静态文本框控件用来放一些说明性的文字。图元类型后面的是下拉框控件,可以下拉选择不同的选项,后面我们会将控件的相关使用。
下面这个是文本编辑框控件,可以在这里面输入值,就像我们在网页登录都见过文本编辑框,在里面输入文字。静态文本框和文本域框外面是控件组合框,把相关的多个控件包围起来,好看一点。用来选择线色的这个是颜色选择框,可以选择不同的颜色。用来选择线型和填充风格的这些是列表框。
最下面的这两个确定和取消按钮是按钮控件。
下面就仿照任务书搭建出我们的对话框界面,使用我们上面的控件。
打开我们的工具箱视图,这里面由我们要用的各种控件,下面即为常用的各种控件。
Button:普通的按钮控件,这个大家平时见的很多了。
Check Box:单选框,比如我们在选择性别的时候,用的就是单选框,也就是说只能选一个。
Edit Control:文本编辑框,比如我们输入用户名和密码的时候用的就是文本编辑框。
Combo Box:下拉框,可以下拉选择不同的内容,比如我们选择院系的时候可以用这个。
List Box:列表框,选项直接显示出来,便于选择。
Group Box:控件组框,包围多个同组的控件。
Radio Button:复选框,可以选择多个选项,比如我们人的爱好可以有很多,我们就可以用这个。
Static Text:静态文本框,常用来显示说明性的文字。
Picture Control:图片控件,用来图片的显示。
List Control:列表控件,可以用来做表格或者带滚动条的文字列表。
Tree Control:树形控件,可以用来以树形结构显示文件夹的包含关系。
Tab Control:选项卡,可以在一个页面切换不同的选项,显示不同的内容,在网页上很常见。
MFC ColorButton Control:MFC 颜色控件,可以用来选择不同的颜色。
只要我们分清这些控件,把相应的控件拖到界面上,来搭建我们的对话框界面。
首先是我们的图元类型,是一个静态文本框,后面是一个下拉框,控件的各个属性是在属性视图更改的,我们可以把静态文本的内容改一改,也就是改控件的 Caption 属性,在前面我们也说过。
形状参数中,我们要把用户输入的项都考虑到,原点X,原点Y,宽度,高度,文本,文本角度都要有,后面我们还会根据用户的选择让一些控件隐藏或者显示。因为我们除了绘制文本时才需要用到文本和文本角度,在其他时候,我们就可以把这几项隐藏。边框风格,包括线宽,线色,边框类型,边框类型我们用下拉框或者列表框都是可以的。
搭建好了对话框,我们可以预览一下,但此时我们的下拉框、边框类型、填充类型里面都还没内容。打开对话框类的源文件,找到 OnInitDialog() 函数,在这个函数中完成对话框界面显示的初始化。我们先来初始化下拉框中的内容,每个控件也都是一个对象,是包含在对话框这个大对象中的小对象,对话框控件对应的 MFC 类为 CComboBox。
使用指针指向这个下拉框对象,要得到对话框可以使用这个资源标识符,找到下拉框对象,从而对下拉框操作。
如果要看创建的这个下拉框的资源标识符可以打开对话框构建界面,在属性视图的 ID 后面就是这个控件的资源标识符。
在头文件 Resource.h 文件中查看所有的资源标识符(打开 Resource.h 文件),我们可以看到在这个文件中由很多的宏定义,宏名称就是资源标识符,后面的数字是具体的编号,它们是一一对应的关系。
使用GetDlgItem() 函数,参数为控件的资源标识符,我们就可以找到具体的控件对象,然后使用指针调用控件对象中的值。使用InsertString() 函数来向下拉框中按照固定的顺序插入对象,和数组下标类似,从0号开始。把正方形选项作为第一个选项,也就是默认选项。列表框对应的 MFC 类是CListBox,与下拉框的添加内容类似,也用InsertString() 函数插入内容,默认第一个选项被选择。因为我们默认的图形选项是正方形,所以为了提高用户体验性,可以把文本输入框和文本角度框隐藏,当选项是文本时,再把这些控件显示。得到文本输入框对象后,使用ShowWindow() 函数,参数为SW_HIDE 时隐藏,参数为SW_SHOW时显示。
接着我们来处理当选择文本时的显示,打开界面构建图,选中下拉框控件,右键选择添加事件处理程序,选择第一个消息类型,添加编辑,也可以双击下拉框控件直接进行事件处理函数的编写。添加下拉框内容那样,先用资源标识符获取到下拉框对象,然后调用GetCurSel() 函数就可以得到下拉框选项。
在界面构建下,选中下拉框控件,右键选择添加变量。在添加成员变量向导中,填写变量名,在类别一项,可选项有Control和Value。选择Control类别,则变量就是控件类别的,可以直接用该变量调用该控件的函数,下拉框控件我们就添加Control类别的变量。而选择Value类别,变量就是值类别的,可以直接获得该变量的值内容。比如文本输入框,添加一个值类别的变量,就可以来获取这个控件的值。一个控件是可以既有Control类别,又有Value类别的变量名的。
预览对话框,对话框的初始化是无法看到,所以还要在后面的实际运行中看到效果。
一步步调试程序没有错误后,再点击“本地Windows调试器”,接着会弹出程序框体,按住Ctrl键+点击鼠标左键来创建图形,鼠标左键双击编辑修改图形,鼠标右键双击删除图形。
四、运行效果
五、设计小结
通过这个项目的学习,让我学习到了很多知识,弥补了很多漏洞,终于感到掌握了些许了,但想更加熟练的使用,也必须付出更多的时间。我发现在编程过程中要一步一步走,慢慢来,走一步调试一步,确保每一步走的正确,走的准确。当然也要有大局观,编程过程中明确这段代码的作用,在整个程序中充当着什么样的角色,并综合多方面进行考虑。这个老师口中所谓简单的应用程序,对我来说却付出了很多时间和精力,同时让我也体会到了MFC相比与单纯的C++的优越性。程序编译过程中的有些困难有的自己无法解决,上网查询或者通过寻求同学的帮助基本上都可以解决。例如绘制圆、椭圆、三角形的函数,线形与填充风格代码的编写,我看书和上网查询并经过修改后得到的;对于实现不同图形需要对话框里显示其属性,不显示该图形不需要的属性,我还不熟悉,经过寻求同学的帮助,才得以实现。这个项目的学习也让我体会到了不会的及时上网查询或寻求老师或同学的帮助,也许他们的点拨与教导对自己起到很大的帮助。同时,也意识到自己对知识的运用不够灵活,不熟练,这也成了我学习和理解知识的动力,极大地增加了我对编程的兴趣,迫使我在编程的道路上能更坚定的走下去。
六、主要代码清单
具体属性设计类型:
int OrgX; //原点坐标 int OrgY; COLORREF BorderColor; //边界颜色 int BorderType; //边界线型--实线、虚线、虚点线等 int BorderWidth; //边界宽度 COLORREF FillColor; //填充颜色 int FillType; //填充类型--实心、双对角、十字交叉等
最终的基类:
enum ElementType { NOTSET, SQUARE, RECTANGLE, CIRCLE, ELLIPSE, TRIANGLE, TEXT }; class CShape : public CObject { public: CShape(); virtual ~CShape(); virtual void Draw(CDC*pDC) = 0; //绘制图元 virtual bool IsMatched(CPoint pnt) = 0; //点是否落在图形内部 virtual void Serialize(CArchive& ar) = 0; void SetPen(COLORREF penColor = RGB(0, 0, 0), int penType = PS_SOLID, int penWidth = 1); //默认:黑色水笔 void SetBrush(COLORREF fillColor = RGB(0, 0, 255), int fillType = HS_DIAGCROSS + 1); //默认:蓝色水刷 void GetPen(COLORREF &penColor, int &penType, int &penWidth); void GetBrush(COLORREF &fillColor, int &fillType); virtual void SetValue(int x, int y, int w_r, int h, CString s) = 0; virtual void GetValue(int&type, int &x, int &y, int &w_r , int &h, CString &s) = 0; protected: ElementType Type; //图元类型 int OrgX; //原点坐标 int OrgY; COLORREF BorderColor; //边界颜色 int BorderType; //边界线型--实线、虚线、虚点线等 int BorderWidth; //边界宽度 COLORREF FillColor; //填充颜色 int FillType; //填充类型--实心、双对角、十字交叉等 };
正方形、长方形和圆的代码:(椭圆、三角形和文本都与此类似,就不给出了)
class CSquare : public CShape //正方形 { public: CSquare(); CSquare(int x, int y, int w); void Draw(CDC*pDC); //绘制正方形 bool IsMatched(CPoint pnt); //重载点pnt是否落在图元内 void Serialize(CArchive& ar); //序列化正方形图元 void SetValue(int x, int y, int w_r, int h, CString s); void GetValue(int&type, int &x, int &y, int &w_r , int &h, CString &s); ~CSquare(); private: int width; DECLARE_SERIAL(CSquare) //声明类CSquare支持序列化 }; class CRectangle :public CShape { //长方形 public: CRectangle(); CRectangle(int x, int y, int w, int h); void Draw(CDC*pDC); //绘制长方形 bool IsMatched(CPoint pnt); //重载点pnt是否落在图元内 virtual void Serialize(CArchive& ar); //序列化长方形图元 void SetValue(int x, int y, int w_r, int h, CString s); void GetValue(int&type, int &x, int &y, int &w_r, int &h, CString &s); ~CRectangle(); private: int width; int height; DECLARE_SERIAL(CRectangle) //声明类CRectangle支持序列化 }; class CCircle :public CShape { //圆形 public: CCircle(); CCircle(int x, int y, int r); void Draw(CDC*pDC); //绘制圆形 bool IsMatched(CPoint pnt); //重载点pnt是否落在图元内 virtual void Serialize(CArchive& ar); //序列化圆形图元 void SetValue(int x, int y, int w_r, int h, CString s); void GetValue(int&type, int &x, int &y, int &w_r, int &h, CString &s); ~CCircle(); private: int radius; DECLARE_SERIAL(CCircle) //声明类CCircle支持序列化 };
保存原画笔和原刷子:(以便下次绘制图形时使用)
(下面给出的是绘制正方形所需的函数代码,其他的图形的绘图函数有点复杂,但是网上都有)
void CSquare::Draw(CDC*pDC) //绘制图形函数 { CPen pen, *pOldPen; pen.CreatePen(BorderType, BorderWidth, BorderColor); //画笔样式 画笔的线宽 画笔颜色 pOldPen = (CPen*)pDC->SelectObject(&pen); //保存原来画笔 CBrush brush, *pOldBrush; //创建画刷 进行颜色填充 if (FillType >= HS_HORIZONTAL && FillType <= HS_DIAGCROSS) brush.CreateHatchBrush(FillType, FillColor); //创建阴影画刷 else brush.CreateSolidBrush(FillColor); //创建图案画刷 pOldBrush = (CBrush*)pDC>SelectObject(&brush); //保存原来画刷 pDC->Rectangle(OrgX - width / 2.0, OrgY - width / 2.0, OrgX + width / 2.0, OrgY + width / 2.0); //BOOL Rectangle(HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); //设备句柄 左上角X坐标 左上角Y坐标 右下角X坐标 右下角Y坐标 pDC->SelectObject(pOldPen); //恢复画笔 //pDC->SelectObject(pOldBrush); //恢复画刷 }
判断坐标点是否在图形中:
bool CSquare::IsMatched(CPoint pnt) //图元匹配函数 { if (pnt.x >= (OrgX - width / 2.0) && pnt.y >= (OrgY - width / 2.0) && pnt.y <= (OrgY + width / 2.0) && pnt.x <= (OrgX + width / 2.0)) return TRUE; else return FALSE; }
序列化要考虑是保存操作还是读取操作,通过 IsStoring() 函数的布尔值来判断:
void CSquare::Serialize(CArchive &ar) //序列化函数 { if (ar.IsStoring()) { //保存文件 ar << (WORD)Type; ar << OrgX << OrgY; //原点坐标 ar << BorderColor; //边界颜色 ar << BorderType; //边界线型 ar << BorderWidth; //边界宽度 ar << FillColor; //填充颜色 ar << FillType; //填充类型 ar << width; //正方形边长 } else { //读取文件 WORD w; ar >> w; Type = (ElementType)w; ar >> OrgX >> OrgY; //原点坐标 ar >> BorderColor; //边界颜色 ar >> BorderType; //边界线型 ar >> BorderWidth; //边界宽度 ar >> FillColor; //填充颜色 ar >> FillType; //填充类型 ar >> width; //正方形边长 } }
利用枚举的下标通过if语句与switch case语句判断图形类型:(只给出index == 0的,后面五种与此类似)
void CShapeDlg::OnSelchangeCombo2() { // TODO: 在此添加控件通知处理程序代码 int index; CWnd *pWnd; index = ((CComboBox*)GetDlgItem(IDC_COMBO2))->GetCurSel(); if (index == 0) { ((CStatic*)GetDlgItem(IDC_STATIC3))->SetWindowTextW(L"宽度W"); pWnd = GetDlgItem(IDC_EDIT3); pWnd->EnableWindow(TRUE); pWnd = GetDlgItem(IDC_EDIT5); pWnd->EnableWindow(FALSE); pWnd = GetDlgItem(IDC_EDIT6); pWnd->EnableWindow(FALSE); } void CShapeDlg::OnClickedIdok() { // TODO: 在此添加控件通知处理程序代码 int num = m_ctlType.GetCurSel(); switch (num) { case 0:m_Type = SQUARE; break; case 1:m_Type = RECTANGLE; break; case 2:m_Type = CIRCLE; break; case 3:m_Type = ELLIPSE; break; case 4:m_Type = TRIANGLE; break; case 5:m_Type = TEXT; break; } m_brush_type = m_ctlbrush_type.GetCurSel(); m_pen_type = m_ctlpen_type.GetCurSel(); UpdateData(TRUE); CDialog::OnOK(); }
线形与填充风格代码:
CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST1); pListBox->ResetContent(); //清空所有项 pListBox->AddString(_T("PS_SOLID")); pListBox->AddString(_T("PS_DASH")); pListBox->AddString(_T("PS_DOT")); pListBox->AddString(_T("PS_DASHDOT")); pListBox->AddString(_T("PS_DASHDOTDOT")); pListBox->AddString(_T("PS_NULL")); pListBox->AddString(_T("PS_INSIDEFRAME")); pListBox = (CListBox*)GetDlgItem(IDC_LIST2); pListBox->AddString(_T("HS_HORIZONTAL")); pListBox->AddString(_T("HS_VERTICAL")); pListBox->AddString(_T("HS_FDIAGONAL")); pListBox->AddString(_T("HS_BDIAGONAL")); pListBox->AddString(_T("HS_CROSS")); pListBox->AddString(_T("HS_DIAGCROSS")); pListBox->AddString(_T("SOLID"));
判断是否按下Ctrl进行左键单击弹出对话框:(左键双击修改与右键双击删除略)
void CDrawingView::OnLButtonDown(UINT nFlags, CPoint point) //左键单击 { // TODO: 在此添加消息处理程序代码和/或调用默认值 if ((nFlags&MK_CONTROL) == MK_CONTROL) //判断是否按下Ctrl键 { CDrawingDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; CClientDC dc(this); CPoint pntLogical = point; OnPrepareDC(&dc); dc.DPtoLP(&pntLogical);//DP->LP进行转换 shapeDlg.m_x = pntLogical.x; shapeDlg.m_y = pntLogical.y; shapeDlg.m_Type = false; if (shapeDlg.DoModal() == IDOK) { CShape*p = NULL; switch (shapeDlg.m_Type) { case 0: p = new CSquare(shapeDlg.m_x, shapeDlg.m_y, shapeDlg.m_w); break; case 1: p = new CRectangle(shapeDlg.m_x, shapeDlg.m_y, shapeDlg.m_w, shapeDlg.m_h); break; case 2: p = new CCircle(shapeDlg.m_x, shapeDlg.m_y, shapeDlg.m_w); break; case 3: p = new CEllipse(shapeDlg.m_x, shapeDlg.m_y, shapeDlg.m_w, shapeDlg.m_h); break; case 4: p = new CTriangle(shapeDlg.m_x, shapeDlg.m_y, shapeDlg.m_w); break; case 5: p = new CText(shapeDlg.m_x, shapeDlg.m_y, shapeDlg.m_h, shapeDlg.m_w, shapeDlg.m_text); } if (p) { p->SetPen(shapeDlg.m_pen_color, shapeDlg.m_pen_type, shapeDlg.m_pen_width); p->SetBrush(shapeDlg.m_brush_color, shapeDlg.m_brush_type); pDoc->m_Elements.Add(p); pDoc->SetModifiedFlag(); pDoc->UpdateAllViews(NULL); } }
这里给出了部分代码,在这里展示的效果不太好,请谅解!
指导老师意见:
成绩: 教师签名:
年 月 日