简易画图板设计报告.docx
- 文档编号:11918915
- 上传时间:2023-06-03
- 格式:DOCX
- 页数:17
- 大小:90.48KB
简易画图板设计报告.docx
《简易画图板设计报告.docx》由会员分享,可在线阅读,更多相关《简易画图板设计报告.docx(17页珍藏版)》请在冰点文库上搜索。
简易画图板设计报告
设计报告:
Graphic简易画图板
-----韩伟谢程焜肖越周峰
电科二班
1设计目的
设计一个单文档类型的MFCAppWizard(exe)工程,工程取名为:
Graphic。
此程序将实现简单的绘图功能,包括点、直线、矩形、椭圆、扇形和连续线的绘制。
并且能实现绘图的控制,包括线宽、线型和颜色的设置,图形的保存和打开以及笔刷的使用。
2总体设计
设计图如图6
图6
3详细设计
首先,新建一个单文档类型的MFCAppWizard(exe)工程,工程取名为:
Graphic。
为此程序添加一个子菜单,菜单名称为“绘图”,并为其添加六个菜单项,分别用来控制不同图形的绘制。
当用户选择其中的一个菜单项后,程序将按照当前的选择进行相应图形的绘制。
添加的六个菜单项的ID及名称如表1所示。
然后分别为这六个菜单项添加命令响应,本程序让视类(CGraphicView)对这些菜单命令进行响应,这六个响应函数的名称分别如表1所示。
表1添加的菜单项
菜单项ID
菜单项名称
菜单项命令响应函数
IDM_DOT
点
OnDot
IDM_LINE
直线
OnLine
IDM-RECTANGLE
矩形
OnRectangle
IDM_ELLIPSE
椭圆
OnEllipse
IDM_SHANXING
扇形
OnShanxing
IDM_LIANXUXIAN
连续线
OnLianxuxian
在程序运行以后,当用户单击某个菜单项时,应该把用户的选择保存起来,以便随后的绘图操作使用。
因此在CGraphicView类中添加一个私有变量m_nDrawType;用来保存用户的选择,该变量的定义如下所述:
private:
UINTm_nDrawType;
接着,在视类的构造函数中将此变量初始化为0,程序代码如下:
CGraphicView:
:
CGraphicView()
{
//TODO:
addconstructioncodehere
m_nDrawType=0;
}
利用switch/case语句,来分别完成相应图形的绘制。
当用户选择【绘图】菜单下的不同子菜单项时,将变量m_nDrawType设置为不同的值。
程序代码如下:
voidCGraphicView:
:
OnDot()
{
//TODO:
Addyourcommandhandlercodehere
m_nDrawType=1;
}
voidCGraphicView:
:
OnLine()
{
//TODO:
Addyourcommandhandlercodehere
m_nDrawType=2;
}
voidCGraphicView:
:
OnRectangle()
{
//TODO:
Addyourcommandhandlercodehere
m_nDrawType=3;
}
voidCGraphicView:
:
OnEllipse()
{
//TODO:
Addyourcommandhandlercodehere
m_nDrawType=4;
}
voidCGraphicView:
:
OnShanxing()
{
//TODO:
Addyourcommandhandlercodehere
m_nDrawType=5;
}
voidCGraphicView:
:
OnLianxuxian()
{
//TODO:
Addyourcommandhandlercodehere
m_nDrawType=6;
}
3.1点、直线、矩形、椭圆的绘制(周峰谢程焜)
对于直线、矩形和椭圆,在绘制时都可有两点来确定其图形。
当鼠标左击时得到一个点,当鼠标左键松开时得到另外一个点。
为视类CGraphicView分别捕获鼠标左键按下和弹起这两个消息。
另外当鼠标左键按下时,需要将鼠标当前按下点保存,因此我们为CGraphicView再增加一个CPoint类型的私有成员变量:
m_ptOrigin,在视类的构造函数中将此变量初始化为0。
在鼠标按下消息响应函数中,保存该点,代码如下:
voidCGraphicView:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
m_ptOrigin=point;//保存鼠标按下得到点,也是绘制一个点
CView:
:
OnLButtonDown(nFlags,point);
}
在鼠标左键弹起消息响应函数中实现绘图,代码如下:
voidCGraphicView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
//创建并获得设备描述
CClientDCdc(this);
switch(m_nDrawType)
{
case1:
dc.SetPixel(point,RGB(255,0,0));/*绘制点*/
break;
case2:
/*绘制直线*/
dc.MoveTo(m_ptOrigin);/*调用MoveTo函数移动到原点*/
dc.LineTo(point);/*调用LineTo函数绘制到终点。
*/
break;
case3:
/*绘制矩形*/
dc.Rectangle(CRect(m_ptOrigin,point));
break;
case4:
/*绘制椭圆*/
dc.Ellipse(CRect(m_ptOrigin,point));
break;
CView:
:
OnLButtonUp(nFlags,point);
}
在上述程序中,设置一个点,用到的函数是SetPixel,这也是CDC类的一个成员方法,该函数的生命形式如下:
COLORREFSetPixel(POINTpoint,COLORREFcrColor);该函数是在指定的点设置一个像素。
其中第一个参数(point)是指定的点,第二个参数(crColor)是指定的颜色。
在程序中设定的颜色在系统颜色表中可能不存在,但系统会选择一种和这个颜色最接近的颜色。
RGB是一个宏,它有三个参数,分别代表红、绿、蓝三种颜色的值。
这三个参数BYTE类型,取值范围为0~255。
RGB(0,0,0)是黑色,RGB(255,255,255)是白色,将这三个分量设置成为0~255之间的任意值,从而得到各种不同的颜色。
这里的RGB(255,0,0)是红色。
绘制直线时,首先调用MoveTo函数移动到原点,然后调用LineTo函数绘制到终点。
绘制矩形时使用Rectangle函数,该函数声明形式为:
BOOLRectangle(LPCRECTlpRect);
该函数有一个指向Crect对象的参数,后者可以利用两个点来构造。
需要注意的是该函数需要的是指向Crect对象的指针,而上述代码中传递的却是Crect对象,但运行编译时也能成功通过,运行时也不会报错,这是为什么呢?
我们知道C系列的语言都是强类型语言,如果类型不匹配的话,需要进行强制类型转换。
但这里为什么没有进行这样的强制类型转换程序也可以通过呢?
实际上,Crect类提供了这样一个成员函数:
重载LPCRECT操作符,其作用是将Crect转换为LPCRECT类型。
因此,当在程序中给Rectangle函数的参数赋值时,如果它发现该参数是一个Crect对象,它就会隐式地调用LPCRECT操作符,将Crect类型的对象转换为LPRECT类型。
因此,在给函数传递参数时,如果我们看到的传递的数值类型和所需要的类型不匹配,但编译和运行都正确的情况时,就要想想这其中的缘由了。
当然,有的情况下可能是这些类型之间本来就可以互相转换,例如short类型和int类型。
但是参数是对象类的话,就要考虑了,它选择的对象的构造方法进行的隐式转换,还是有其他重载的操作符。
当用户选择椭圆菜单项时,调用Ellipes函数绘制一个椭圆。
3.2连续线和扇形的绘制(周峰谢程焜)
Windows系统为我们提供了一个画图程序,在该程序中,利用画笔可以绘制连续的线条,下面我们设计绘制连续线和扇形。
为了绘制连续的线条,首先要得到线条的起点,这在前面已经实现。
然后需要捕获鼠标移动过程中的每一个点,这可以通过捕获鼠标移动消息(WM_MOUSEMOVE)来实现。
在此消息响应函数中,在依次捕获的各个点之间绘制一条条非常短的线段,从而就可以绘制出一条连续的线条。
遵照这一思路,我们开始增加程序的功能。
首先为视类增加鼠标移动消息(WM_MOUSEMOVE)的响应函数(OnMouseMove)。
这样,只要鼠标在应用程序窗口中移动时都会进入到这个消息响应函数中。
但这并不是我们所期望的,我们希望在鼠标左键按下后开始绘图。
因此,我们需要有一个变量来表示鼠标左键是否按下这一状态,然后在鼠标移动消息响应函数中对这一变量进行判断。
当此变量为真,即鼠标左键已经按下去,我们开始绘图。
于是,为视类添加一个BOOL型的私有变量m_bDraw,当鼠标左键按下去时,此变量为真;当鼠标左键弹起时,此变量为假,这时,我们就不再绘制线条了。
该变量在视类头文件中的定义代码如下:
Private:
BOOLm_bDraw;
接下来在视类的构造函数中,将此变量初始化为FALSE。
m_bdraw=FALSE;
当鼠标左键按下去时,在视类的OnLButtonDown函数中将此变量初始化为TRUE。
m_bdraw=TRUE;
当鼠标左键弹起时,在视类的OnLButton函数中将此变量初始化为假。
m_bdraw=FALSE;
然后在OnMouseMove函数中首先对m_bdraw变量进行判断,如果其值为真,说明鼠标左键已经按下去了,这时就可开始进行画线操作。
还有一点需要注意,因为每绘制一条线段后,下次应该从这条线段的终点开始继续绘制。
因此,绘制完当前线段后,应该修改线段的起点,将当前线段的终点作为下一条线段的起点,程序代码如下:
voidCGraphicView:
:
OnMouseMove(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
{
//创建并获得设备描述
CClientDCdc(this);
//创建宽度为1的实线红色画笔
CPenpen(PS_SOLID,1,RGB(255,0,0));
//把创建的画笔选入设备描述
CPen*pOldpen=dc.SelectObject(&pen);
if(m_bDraw==true)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
//修改线段的起点
m_ptOrigin=point;
}
//恢复设备描述
dc.SelectObject(pOldpen);
CView:
:
OnMouseMove(nFlags,point);
}
如果在上面绘制连续线条的程序中,保持每段小直线的起点不变,即以鼠标左键按下时的起点为起点不变,分别绘制到鼠标移动点的直线,这时就会出现扇形的效果。
也就是去掉上述代码OnMouseMove函数中修改线段起点的代码。
程序代码如下:
voidCGraphicView:
:
OnMouseMove(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
{
//创建并获得设备描述
CClientDCdc(this);
//创建宽度为1的实线红色画笔
CPenpen(PS_SOLID,1,RGB(255,0,0));
//把创建的画笔选入设备描述
CPen*pOldpen=dc.SelectObject(&pen);
if(m_bDraw==true)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
}
//恢复设备描述
dc.SelectObject(pOldpen);
CView:
:
OnMouseMove(nFlags,point);
}
3.3画刷(韩伟肖越)
再为此程序添加一个子菜单,菜单名称为“画刷”,并为其添加三个菜单项,分别用来控制不同的画刷。
MFC提供了一个CBrush类,可以用来创建画刷对象。
画刷通常用来填充一块区域。
简单画刷、位图画刷、透明画刷,程序代码如下:
voidCDrawView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
//创建一个红色画刷
CBrushbrush(RGB(255,0,0));
//创建并获得设备描述表
CClientDCdc(this);
//利用红色画刷填充鼠标拖曳过程中形成的矩形区域
dc.FillRect(CRect(m_ptOrigin,point),&brush);
//创建位图对象
CBitmapbitmap;
//加载位图资源
bitmap.LoadBitmap(IDB_BITMAP1);
//创建位图画刷
CBrushbrush(&bitmap);
//创建并获得设备描述表
CClientDCdc(this);
//利用红色画刷填充鼠标拖曳过程中形成的矩形区域
dc.FillRect(CRect(m_ptOrigin,point),&brush);
//创建并获得设备描述表
CClientDCdc(this);
//创建一个空画刷
CBrush*pBrush=CBrush:
:
FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
//将空画刷选入设备描述表
CBrush*pOldBrush=dc.SelectObject(pBrush);
//绘制一个矩形
dc.Rectangle(CRect(m_ptOrigin,point));
//恢复先前的画刷
dc.SelectObject(pOldBrush);
m_bDraw=FALSE;
CView:
:
OnLButtonUp(nFlags,point);
}
在简单画刷程序中,首先创建一个红色画刷;接着创建设备描述表对象;然后调用设备描述表对象的成员函数FillRect,利用指定的画刷填充一块指定的矩形区域,而鼠标拖动过程中的起点和终点就决定了需要填充的矩形区域,因此,代码中通过CRect类利用鼠标拖动的起点和终点构造了这快矩形区域。
CRect类提供了多个构造函数,这里使用的是下面这种构造函数,即通过指定矩形区域的左上角和右下角这两个点来构造一块矩形区域。
CRect(POINTtopLeft,POINTbottomRight);
代码中的CDC类的成员函数FillRect,该函数的功能是用指定的画刷填充一个矩形。
该函数将填充全部的矩形,包括上左边界,但不填充右底边界。
FillRect函数的声明如下:
voidFillRect(LPCRECTlpRect,CBrush*pBrush);
该函数有两个参数,lpRect是指向一个RECT结构体或CRect对象的指针,该结构体或对象中包含了要填充的矩形的逻辑坐标。
pBrush是指向用于填充矩形的画刷对象的指针。
在位图画刷程序中,CBrush类有下面这样一种构造函数。
CBrush(CBitmap*pBitmap);
该构造函数要求一个CBitmap类型的指针,CBitmap类是位图类,于是我们就会这样想:
利用这个构造函数是否就可以创建一个位图画刷呢?
事实确实如此。
创建CBitmap对象时,仅调用其构造函数并不能得到一个有用的位图对象,还需要调用一个初始化函数来初始化这个位图对象。
CBitmap类提供了多个初始化函数,例如,LoadBitmap、CreateBitmap、BitmapIndirect等。
这里用LoadBitmap函数来加载一副位图,该函数的声明如下:
BOOLLoadBitmap(LPCTSTRlpszResourceName);
BOOLLoadBitmap(UINTnIDResource);
其中第二种声明需要一个资源ID作为参数。
首先给程序增加一个位图资源。
为一个工程创建资源有多种实现方法,其中一种方法可以利用【Insert】菜单下的【Resource…】命令,在弹出的对话框中选择Bitmap资源类型,单击【New】按钮,即可创建一个默认名称为IDB_BITMAP1的位图资源,并在VC++集成开发环境右边的代码编辑区中打开位图编辑器。
可以利用编辑器右边的调色板和绘图工具来编辑位图资源,还可以通过拉伸位图编辑器中网格周围的蓝色方点来调整位图的大小。
在透明画刷程序中,我们利用GetStockObject这个函数来获取一个黑色或白色的画刷句柄。
这个函数是否能够获得一个透明画刷句柄呢?
从MSND提供的帮助信息中,可以看到该函数的参数取值之一可以是NULL_BRUSH,以获取一个空画刷。
那么,这个空画刷是否就是我们所需要的透明画刷呢?
结论是正确的。
但这时存在一个问题,我们获取的是句柄,而在进行绘制操作时需要的是一个画刷对象。
如何从画刷句柄转换为画刷对象呢?
CBrush类提供了一个FromHandle函数来实现这样的功能。
该函数的声明如下:
StaticCDC*PASCALFromHandle(HDChDC);
3.4设置对话框(韩伟肖越)
为程序添加一个设置对话框,允许用户指定画笔的类型、线宽,并让随后的绘图操作就使用用户指定的新设置值来进行绘制。
为了实现这一功能,首先需要为程序添加一个对话框资源,并按下表修改属性。
属性
值
ID
IDD_DLG_SETTING
Caption
Setting
Font
宋体
设置线型、线宽对话框的代码如下:
voidCGraphicView:
:
OnSetting()
{
//TODO:
Addyourcommandhandlercodehere
CSettingDlgdlg;
dlg.m_nLineWidth=m_nLineWidth;
dlg.m_nLineStyle=m_nLineStyle;
if(IDOK==dlg.DoModal())
{
m_nLineWidth=dlg.m_nLineWidth;
m_nLineStyle=dlg.m_nLineStyle;
}
}
3.5颜色(韩伟肖越)
颜色对话框看起来比较复杂。
实际上,MFC为我们提供了一个类:
CColorDialog,可以很方便的创建这样的一个颜色对话框。
voidCGraphicView:
:
OnColor()
{
//TODO:
Addyourcommandhandlercodehere
CColorDialogdlg;
dlg.m_cc.Flags|=CC_RGBINIT|CC_FULLOPEN;
dlg.m_cc.rgbResult=m_clr;
if(IDOK==dlg.DoModal())
{
m_clr=dlg.m_cc.rgbResult;
}
}
3.6打开与保存
voidCGraphicView:
:
OnFileOpen()
{
//TODO:
Addyourcommandhandlercodehere
HMETAFILEhmetaFile;
hmetaFile=GetMetaFile("meta.wmf");
m_dcMetaFile.PlayMetaFile(hmetaFile);
DeleteMetaFile(hmetaFile);
Invalidate();
}
voidCGraphicView:
:
OnFileSave()
{
//TODO:
Addyourcommandhandlercodehere
HMETAFILEhmetaFile;
hmetaFile=m_dcMetaFile.Close();
CopyMetaFile(hmetaFile,"meta.wmf");
m_dcMetaFile.Create();
DeleteMetaFile(hmetaFile);
}
4运行结果
运行结果如图7、8、9
图7
图8
图9
结论
其实学任何一种语言都是一样的。
需要勤奋+毅力+运气=成功,这是我认为的一个公式。
这里毅力和勤奋是个人因素,而运气这是先天的。
如果以前没有接触过编程语言的话,在接触VC前我建议你先学习一些基础语言,比如C等都是一些比较好学的基础语言,我当初就是从C语言过度学VC的。
学基础语言的目的是学习语法结构和如何编写概念,只有你理解和掌握了这些编程用的工具才能学习高级语言。
这些基础语言中我建议大家学C语言,其实VC就是C++也就是C语言的"儿子","父亲"学习起来比较容易上手,但遇到类似WINDOWS的程序的时候比较固执不容易沟通,在这种条件下才有了"儿子","儿子"比较开朗应变能力强,但是就因为他这些优点才使初学者难以掌握。
VC是C++语言,是一种面向对象的编程语言。
他于基础语言不同点在于,基础语言是一条路走到底的(中断技术除外),而面向对象是等待你的指令才往下走,是被动的编程语言。
这点是学习VC前必须扭转的概念。
通过这次学年设计,我了解vc++是Windows平台上的C++编程环境,学习VC要了解很多Windows平台的特性并且还要掌握MFC、ATL、COM等的知识,难度比较大。
Windows下编程需要了解Windows的消息机制以及回调(callback)函数的原理;MFC是Win32API的包装类,需要理解文档视图类的结构,窗口类的结构,消息流向等等;COM是代码共享的二进制标准,需要掌握其基本原理等等。
基于我们这次用VC++编写了一个简单的画图板,功能不是很多,但是从中的到不少收获。
主要有:
1.对项目和文档的了解,我们在编写程序时,要对不同的文件进行编写。
其中项目就是文件的集合,包括头文件、源代码文件、资源文件。
文档窗口也称编辑窗口,是用户进行输入或编辑头文件、源文件、资源的区域。
在编辑文件时,为了增加程序的可读性,系统用绿色显示注释语句,用蓝色显示关键字。
2.菜单:
我们绘制画图板时,就要建立一个“绘图”菜单。
对于“绘图”菜单下还有几个子菜单项,通过建立菜单同时让它实现菜单上的命令,这就要我们对每个菜单项进行设置,诸如,ID、标题、快捷键、热键等。
还有一些属性设置,设置不好,容易出错,所以每次建立菜单,都需谨慎设置,记住每个菜单对应的参数。
3.文件打开与保存,对于我们
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 简易 画图板 设计 报告