简易画图板设计报告 本文关键词:简易,报告,设计,画图板
简易画图板设计报告 本文简介:设计报告:Graphic简易画图板-----韩伟谢程焜肖越周峰电科二班1设计目的设计一个单文档类型的MFCAppWizard(exe)工程,工程取名为:Graphic。此程序将实现简单的绘图功能,包括点、直线、矩形、椭圆、扇形和连续线的绘制。并且能实现绘图的控制,包括线宽、线型和颜色的设置,图形的保
简易画图板设计报告 本文内容:
设计报告:Graphic简易画图板
-----韩伟
谢程焜
肖越
周峰
电科二班
1设计目的
设计一个单文档类型的MFC
AppWizard
(exe)工程,工程取名为:Graphic。此程序将实现简单的绘图功能,包括点、直线、矩形、椭圆、扇形和连续线的绘制。并且能实现绘图的控制,包括线宽、线型和颜色的设置,图形的保存和打开以及笔刷的使用。
2
总体设计
设计图如图6
简易画图板
文件
绘图
笔刷
打开
保存
点
直线
矩形
椭圆
扇形
连续线
设置
颜色
简单笔刷
位图笔刷
透明笔刷
线宽
线型
图6
3详细设计
首先,新建一个单文档类型的MFC
AppWizard
(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:
UINT
m_nDrawType;
接着,在视类的构造函数中将此变量初始化为0,程序代码如下:
CGraphicView::CGraphicView()
{
//
TODO:
add
construction
code
here
m_nDrawType=0;
}
利用switch/case语句,来分别完成相应图形的绘制。当用户选择【绘图】菜单下的不同子菜单项时,将变量m_nDrawType设置为不同的值。程序代码如下:
void
CGraphicView::OnDot()
{
//
TODO:
Add
your
command
handler
code
here
m_nDrawType=1;
}
void
CGraphicView::OnLine()
{
//
TODO:
Add
your
command
handler
code
here
m_nDrawType=2;
}
void
CGraphicView::OnRectangle()
{
//
TODO:
Add
your
command
handler
code
here
m_nDrawType=3;
}
void
CGraphicView::OnEllipse()
{
//
TODO:
Add
your
command
handler
code
here
m_nDrawType=4;
}
void
CGraphicView::OnShanxing()
{
//
TODO:
Add
your
command
handler
code
here
m_nDrawType=5;
}
void
CGraphicView::OnLianxuxian()
{
//
TODO:
Add
your
command
handler
code
here
m_nDrawType=6;
}
3.1点、直线、矩形、椭圆的绘制
(周峰
谢程焜)
对于直线、矩形和椭圆,在绘制时都可有两点来确定其图形。当鼠标左击时得到一个点,当鼠标左键松开时得到另外一个点。为视类CGraphicView分别捕获鼠标左键按下和弹起这两个消息。另外当鼠标左键按下时,需要将鼠标当前按下点保存,因此我们为CGraphicView再增加一个CPoint类型的私有成员变量:m_ptOrigin,在视类的构造函数中将此变量初始化为0。在鼠标按下消息响应函数中,保存该点,代码如下:
void
CGraphicView::OnLButtonDown(UINT
nFlags,CPoint
point)
{
//
TODO:
Add
your
message
handler
code
here
and/or
call
default
m_ptOrigin=point;
//保存鼠标按下得到点,也是绘制一个点
CView::OnLButtonDown(nFlags,point);
}
在鼠标左键弹起消息响应函数中实现绘图,代码如下:
void
CGraphicView::OnLButtonUp(UINT
nFlags,CPoint
point)
{
//
TODO:
Add
your
message
handler
code
here
and/or
call
default
//创建并获得设备描述
CClientDC
dc(this);
switch
(m_nDrawType)
{
case
1:
dc.SetPixel(point,RGB(255,0,0));
/*绘制点*/
break;
case
2:
/*绘制直线*/
dc.MoveTo(m_ptOrigin);/*调用MoveTo函数移动到原点*/
dc.LineTo(point);/*调用LineTo函数绘制到终点。*/
break;
case
3:
/*绘制矩形*/
dc.Rectangle(CRect(m_ptOrigin,point));
break;
case
4:
/*绘制椭圆*/
dc.Ellipse(CRect(m_ptOrigin,point));
break;
CView::OnLButtonUp(nFlags,point);
}
在上述程序中,设置一个点,用到的函数是SetPixel,这也是CDC类的一个成员方法,该函数的生命形式如下:COLORREF
SetPixel
(POINT
point,COLORREF
crColor);该函数是在指定的点设置一个像素。其中第一个参数(point)是指定的点,第二个参数(crColor)是指定的颜色。在程序中设定的颜色在系统颜色表中可能不存在,但系统会选择一种和这个颜色最接近的颜色。RGB是一个宏,它有三个参数,分别代表红、绿、蓝三种颜色的值。这三个参数BYTE类型,取值范围为0~255。RGB(0,0,0)是黑色,RGB(255,255,255)是白色,将这三个分量设置成为0~255之间的任意值,从而得到各种不同的颜色。这里的RGB(255,0,0)是红色。
绘制直线时,首先调用MoveTo函数移动到原点,然后调用LineTo函数绘制到终点。
绘制矩形时使用Rectangle函数,该函数声明形式为:BOOL
Rectangle
(LPCRECT
lpRect);
该函数有一个指向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:
BOOL
m_bDraw;
接下来在视类的构造函数中,将此变量初始化为FALSE。
m_bdraw=FALSE;
当鼠标左键按下去时,在视类的OnLButtonDown函数中将此变量初始化为TRUE。
m_bdraw=TRUE;
当鼠标左键弹起时,在视类的OnLButton函数中将此变量初始化为假。
m_bdraw=FALSE;
然后在OnMouseMove函数中首先对m_bdraw变量进行判断,如果其值为真,说明鼠标左键已经按下去了,这时就可开始进行画线操作。还有一点需要注意,因为每绘制一条线段后,下次应该从这条线段的终点开始继续绘制。因此,绘制完当前线段后,应该修改线段的起点,将当前线段的终点作为下一条线段的起点,程序代码如下:
void
CGraphicView::OnMouseMove(UINT
nFlags,CPoint
point)
{
//TODO:
Add
your
message
handler
code
here
and/or
call
default
{
//创建并获得设备描述
CClientDC
dc(this);
//创建宽度为1的实线红色画笔
CPen
pen
(PS_SOLID,1,RGB(255,0,0));
//把创建的画笔选入设备描述
CPenpOldpen=dc.SelectObject(
if(m_bDraw==true)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
//修改线段的起点
m_ptOrigin=point;
}
//恢复设备描述
dc.SelectObject(pOldpen);
CView::OnMouseMove(nFlags,point);
}
如果在上面绘制连续线条的程序中,保持每段小直线的起点不变,即以鼠标左键按下时的起点为起点不变,分别绘制到鼠标移动点的直线,这时就会出现扇形的效果。也就是去掉上述代码OnMouseMove函数中修改线段起点的代码。程序代码如下:
void
CGraphicView::OnMouseMove(UINT
nFlags,CPoint
point)
{
//TODO:
Add
your
message
handler
code
here
and/or
call
default
{
//创建并获得设备描述
CClientDC
dc(this);
//创建宽度为1的实线红色画笔
CPen
pen
(PS_SOLID,1,RGB(255,0,0));
//把创建的画笔选入设备描述
CPenpOldpen=dc.SelectObject(
if(m_bDraw==true)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
}
//恢复设备描述
dc.SelectObject(pOldpen);
CView::OnMouseMove(nFlags,point);
}
3.3画刷
(韩伟
肖越)
再为此程序添加一个子菜单,菜单名称为“画刷”,并为其添加三个菜单项,分别用来控制不同的画刷。
MFC提供了一个CBrush类,可以用来创建画刷对象。画刷通常用来填充一块区域。
简单画刷、位图画刷、透明画刷,程序代码如下:
void
CDrawView::OnLButtonUp(UINT
nFlags,CPoint
point)
{
//创建一个红色画刷
CBrush
brush(RGB(255,0,0));
//创建并获得设备描述表
CClientDC
dc(this);
//利用红色画刷填充鼠标拖曳过程中形成的矩形区域
dc.FillRect(CRect(m_ptOrigin,point),//创建位图对象
CBitmap
bitmap;
//加载位图资源
bitmap.LoadBitmap(IDB_BITMAP1);
//创建位图画刷
CBrush
brush(
//创建并获得设备描述表
CClientDC
dc(this);
//利用红色画刷填充鼠标拖曳过程中形成的矩形区域
dc.FillRect(CRect(m_ptOrigin,point),//创建并获得设备描述表
CClientDC
dc(this);
//创建一个空画刷
CBrushpBrush
=
CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
//将空画刷选入设备描述表
CBrushpOldBrush
=
dc.SelectObject(pBrush);
//绘制一个矩形
dc.Rectangle(CRect(m_ptOrigin,point));
//恢复先前的画刷
dc.SelectObject(pOldBrush);
m_bDraw
=
FALSE;
CView::OnLButtonUp(nFlags,point);
}
在简单画刷程序中,首先创建一个红色画刷;接着创建设备描述表对象;然后调用设备描述表对象的成员函数FillRect,利用指定的画刷填充一块指定的矩形区域,而鼠标拖动过程中的起点和终点就决定了需要填充的矩形区域,因此,代码中通过CRect类利用鼠标拖动的起点和终点构造了这快矩形区域。CRect类提供了多个构造函数,这里使用的是下面这种构造函数,即通过指定矩形区域的左上角和右下角这两个点来构造一块矩形区域。
CRect(POINT
topLeft,POINT
bottomRight);
代码中的CDC类的成员函数FillRect,该函数的功能是用指定的画刷填充一个矩形。该函数将填充全部的矩形,包括上左边界,但不填充右底边界。FillRect函数的声明如下:
void
FillRect
(LPCRECT
lpRect,CBrush*
pBrush);
该函数有两个参数,lpRect是指向一个RECT结构体或CRect对象的指针,该结构体或对象中包含了要填充的矩形的逻辑坐标。pBrush是指向用于填充矩形的画刷对象的指针。
在位图画刷程序中,CBrush类有下面这样一种构造函数。
CBrush
(CBitmap*
pBitmap);
该构造函数要求一个CBitmap类型的指针,CBitmap类是位图类,于是我们就会这样想:利用这个构造函数是否就可以创建一个位图画刷呢?事实确实如此。创建CBitmap对象时,仅调用其构造函数并不能得到一个有用的位图对象,还需要调用一个初始化函数来初始化这个位图对象。CBitmap类提供了多个初始化函数,例如,LoadBitmap、CreateBitmap、BitmapIndirect等。这里用LoadBitmap函数来加载一副位图,该函数的声明如下:
BOOL
LoadBitmap
(LPCTSTR
lpszResourceName);
BOOL
LoadBitmap
(UINT
nIDResource);
其中第二种声明需要一个资源ID作为参数。首先给程序增加一个位图资源。为一个工程创建资源有多种实现方法,其中一种方法可以利用【Insert】菜单下的【Resource…】命令,在弹出的对话框中选择Bitmap资源类型,单击【New】按钮,即可创建一个默认名称为IDB_BITMAP1的位图资源,并在VC++集成开发环境右边的代码编辑区中打开位图编辑器。可以利用编辑器右边的调色板和绘图工具来编辑位图资源,还可以通过拉伸位图编辑器中网格周围的蓝色方点来调整位图的大小。
在透明画刷程序中,我们利用GetStockObject这个函数来获取一个黑色或白色的画刷句柄。这个函数是否能够获得一个透明画刷句柄呢?从MSND提供的帮助信息中,可以看到该函数的参数取值之一可以是NULL_BRUSH,以获取一个空画刷。那么,这个空画刷是否就是我们所需要的透明画刷呢?结论是正确的。
但这时存在一个问题,我们获取的是句柄,而在进行绘制操作时需要的是一个画刷对象。如何从画刷句柄转换为画刷对象呢?CBrush类提供了一个FromHandle函数来实现这样的功能。该函数的声明如下:
Static
CDC*
PASCAL
FromHandle(HDC
hDC);
3.4设置对话框(韩伟
肖越)
为程序添加一个设置对话框,允许用户指定画笔的类型、线宽,并让随后的绘图操作就使用用户指定的新设置值来进行绘制。
为了实现这一功能,首先需要为程序添加一个对话框资源,并按下表修改属性。
属性
值
ID
IDD_DLG_SETTING
Caption
Setting
Font
宋体
设置线型、线宽对话框的代码如下:
void
CGraphicView::OnSetting()
{
//TODO:
Add
your
command
handler
code
here
CSettingDlg
dlg;
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,可以很方便的创建这样的一个颜色对话框。
void
CGraphicView::OnColor()
{
//
TODO:
Add
your
command
handler
code
here
CColorDialog
dlg;
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打开与保存
void
CGraphicView::OnFileOpen()
{
//
TODO:
Add
your
command
handler
code
here
HMETAFILE
hmetaFile;
hmetaFile=GetMetaFile(“meta.wmf“);
m_dcMetaFile.PlayMetaFile(hmetaFile);
DeleteMetaFile(hmetaFile);
Invalidate();
}
void
CGraphicView::OnFileSave()
{
//
TODO:
Add
your
command
handler
code
here
HMETAFILE
hmetaFile;
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.文件打开与保存,对于我们绘制出一幅图片,那么我们就要把它保存下来。如果我们无法保存,我们做了也就没没什么意义了。对于图形的保存于打开,我们还存在很多问题,自定义保存不同文件夹下尚未解决,所以还需要我们进一步的学习和了解,争取实现我们心里多希望的。
4.在编程时遇到了图像在变换大小时,原来的图形会消失,后来通过查看相关资料,这里涉及的一个重绘问题。经过多次修改,添加代码,才得以解决。所以我觉得学习VC++就要拿出那种坚持不懈的精神,做什么也是,只有你不放弃对它了解,才会实现我们自己想要的,这就要我们要不断的学习VC++,从中学习更多我们没了解到的知识。
5.对于CView视图,经过查询主要是负责内存数据与用户的交互。包括数据的显示、用户操作的响应(如菜单的选取、鼠标的响应)。最重要的是OnDraw(重画窗口),通常用CWnd::Invalidate()来启动它。另外,它通过消息映射表处理菜单、工具条、快捷键和其他用户消息。
最后通过学习VC++,从中受益匪浅,更多的知识,还有待于我们去挖掘实现更多有趣的东西,同样它也是一个很强大的软件。
16
篇2:Java面向对象课程设计报告画图板毕业设计(论文)
Java面向对象课程设计报告画图板毕业设计(论文)word格式 本文关键词:毕业设计,面向对象,课程设计,格式,报告
Java面向对象课程设计报告画图板毕业设计(论文)word格式 本文简介:《面向对象程序设计课程设计》指导书课程设计名称:面向对象程序设计课程设计指导老师:牛志毅课程设计周(时)数:2周指导方式:集体辅导与个别辅导相结合课程设计适用专业:信息与计算机科学课程设计教材及主要参考资料:《Java程序设计与案例》刘宝林主编,高等教育出版社服务课程名称:面向对象程序设计一、课程设
Java面向对象课程设计报告画图板毕业设计(论文)word格式 本文内容:
《面向对象程序设计课程设计》指导书
课程设计名称:面向对象程序设计课程设计
指导老师:牛志毅
课程设计周(时)数:2周
指导方式:集体辅导与个别辅导相结合
课程设计适用专业:信息与计算机科学
课程设计教材及主要参考资料:
《Java程序设计与案例》刘宝林主编,高等教育出版社
服务课程名称:面向对象程序设计
一、课程设计教学目的及基本要求
通过本课程设计,使学生了解面向对象程序的开发思想、方法和步骤,掌握开发工具的使用,提高综合运用所学的理论知识和方法独立分析和解决问题的能力,进一步提高其开发应用程序的能力。
要求明确本次课程设计所要用到的技术点并到网上搜索以及查阅相关的书籍来搜集资料。通过编写一个基于JAVA的应用系统综合实例,来掌握Java语言编程技巧。并学会编制结构清晰、风格良好的、数据结构适当的Java语言程序,从而具备解决综合性实际问题的能力。
二、设计题目及要求(二选一)
⑴
设计一个图书信息管理系统
①图书信息包括图书编号、书名、作者、出版社、出版日期、图书简介及图书类别等。
②本系统功能描述:
图书信息录入功能;
图书信息浏览功能;
查询功能(至少一种查询方式);
图书信息修改功能;
及其它你认为必要的功能。
⑵
设计一个画图软件
①用户界面友好;
②能绘制基本形状的图形;
③可设置图形的颜色、线条的粗细和填充等属性;
④可将画好的图保存至文件,并能从文件中读取。
三、设计报告的要求
设计结束后要写出课程设计报告,以作为整个课程设计评分的书面依据和存档材料。设计报告以规定格式的电子文档书写、打印并装订,排版及图、表要清楚、工整。内容及要求如下:
封面:题目、班级、姓名、学号、指导教师和完成日期。
正文包括以下7个内容:
①课题说明
以无歧义的陈述说明程序设计的任务。
②程序设计思路
简要说明程序设计的思路。
③程序源代码
给出源代码及注释。
④程序测试
给出程序主要运行界面截图。
⑤设计总结
经验和体会等。
⑥参考文献
列出参考的相关资料和书籍。
五、课程设计考核方法及成绩评定
课程设计结束时,要求学生提交课程设计报告(附源程序)及可运行的软件系统。
课程设计成绩分两部分,设计报告占50%,设计作品占50%。
附件:课程设计报告封面和参考程序。
32
湖南科技学院
课程设计报告
课程名称:
面向对象程序设计课程设计
课程设计题目:
画图板
系:
专
业:
年级、班:
姓
名:
学
号:
指导教师:
职
称:
2012年6月
1.
课题的任务和要求
设计一个画图软件
①用户界面友好;
②能绘制基本形状的图形;
③可设置图形的颜色、线条的粗细和填充等属性;
④可将画好的图保存至文件,并能从文件中读取。
2.
程序设计思路
该课题的任务是设计一个画图软件,要求能绘制基本形状的图形;同时可以设置图形的颜色、线条的粗细和是否填充等属性;并且可以将画好的图形以某种格式,比如说JPG保存至文件,并能从文件中读取某种格式的图像文件并显示出来。
首先,作为画图板,应该能够绘制基本的图形,像“铅笔“,“直线“,“矩形“,“椭圆“,”圆”,同时考虑到实用性,画图板应该能够提供橡皮擦,设置线条粗细,颜色,背景颜色的功能。在鼠标停留在按钮上时,按钮上应该提供显示提示文字,通过设置JButton的setText方法即可达到要求,在使用线条工具来绘制线条时,如果设置图形过于粗大,要求绘制出来图形能够消除锯齿,思路是在设置Graphics2D的大小时,设置Graphics2D,setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);即可达到要求
第二,考虑到平时画图时,总是喜欢按住shift来绘制45°,90°的线条,为方便用户,画图板也必须提供相应的功能,思路是判断线条的角度,如果角度大于0°同时小于45°,则绘制45°的斜线,如果线条的角度大于45°小于90°,则绘制90度的直线。
第三,关于设置背景颜色,考虑到美观,使用了渐变背景色,思路是在设置Graphics2D的背景色时,通过绘制不同透明度的条纹背景,与设置不同级别的透明度来达到绘制渐变背景色的目的。
第四,关于画图板,在提供通用的功能的同时,应该能够提供一些扩展功能,这是课程设计的一项基本要求,对于扩展功能我提供了绘制圆角矩阵,三角形,3D立方体,和绘制f(x)=A*sin(Bx)+C*cos(Cx),绘制重叠椭圆等扩展功能,绘制圆角矩阵是通过Graphics2D的drawRoundRect来实现的,而3D立方体则是通过fill3DRect实现的,而三角形是通过绘制首尾相连的三条直线来实现的。而正余弦曲线则完全是通过计算出曲线的值,然后绘制一小段直线,通过绘制很多这样的小直线相连来达到绘制正余弦曲线的目的。的值,然后绘制一小段直线,通过绘制很多这样的小直线相连来达到绘制正余弦曲线的目的。而重叠椭圆的实现则是通过Graphics2D的draw(new
Ellipse2D.Double(x1,y1,85,90);绘制一个椭圆,然后translate(x1,y1);
将
Graphics2D
上下文的原点平移到当前坐标系中的点(x1,y1),在计算d=m*mathPI/180的值,rotate(d);
将当前的
Graphics2D
Transform
与旋转转换连接,然后,translate(-x1,-y1);
将Graphics2D
上下文的原点平移到当前坐标系中的点(-x1,-y1)。draw(new
Ellipse2D.Double(x1,y1,85,90));再来绘制一个椭圆,通过这样的处理,来绘制一个在一个圆平面且重叠的椭圆图形。
第五,关于设置是否填充的问题,对于直线来说,是否填充是没有实际意义的,所以不予考虑,释放填充应该考虑圆,椭圆,圆角矩阵,三角形,对于圆和椭圆的填充是通过调用
Graphics2D
的drawOval方法实现的,圆角矩阵则是通过调用Graphics2D的drawRoundRect来实现的,而三角行的填充则是通过调用Graphics2D的fillPolygon方法来实现的.而填充与否的判断则是通过isfill的真与假来实现的.
第六,要求能够保存图形与打开已有的图形,这是通过使用BufferedImage来缓存绘制的图形,然后使用ImageIO将绘制的图形在重新绘制一次再保存到指定的位置,从而实现了文件的保存,打开文件时,考虑到实用性与方便,提供了预览图像的功能,通过继承Jpanel,将选得的图片通过setIcon绘制在出来,实现预览的功能。打开是通过ImageIO将图片绘制在面板上。为方便用户,提供了一个File的菜单,菜单中提供了新建,保存,打开,退出的功能。
第七,考虑到美观,使用了观感器的图形界面。主要是通过观感管理器来实现的。UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());对于背景颜色则是通过设置渐变背景颜色来实现的。
第八,在用户退出时,要求能询问用户是否保存作品,考虑到菜单中有保存的选项,所以通过菜单退出时没有提供询问是否保存的功能,而在实际生活中,考虑到有时候会忘记保存,所以通过右上角窗口退出时必须询问是否保存,是否保存则是通过JOptionPane.showConfirmDialog来实现的,当用户选择Yes时,保存文件。其他则直接退出。
根据课题要求,首先对要实现的功能类型抽象出一个公共的基类Drawing,子类Line,Rectange,Oval,Pencil,RoundRect,Circle,Rect3D,Triangle,SinCos,Tuo,Eraser通过继承基类来实现不同的功能,在使用时,通过基类来调用不同的子类,很好地体现了面向对象的Java语言的多态,抽象,继承的思想。用户通过选择不同的按钮来绘制图形,这主要是利用按钮监听将不同的绘图功能绑定到不同的按钮上,通过监听用户的选择来创建不同的子类,通过子类绘制不同的图形。
3.
源代码及注释
package
myclass;
import
java.awt.*;
import
java.awt.event.*;
import
java.awt.geom.Ellipse2D;
import
java.awt.geom.Rectangle2D;
import
java.awt.image.BufferedImage;
import
java.beans.PropertyChangeEvent;
import
java.beans.PropertyChangeListener;
import
java.io.*;
import
java.util.ArrayList;
import
java.util.Random;
import
javax.imageio.ImageIO;
import
javax.swing.*;
import
javax.swing.event.*;
import
javax.swing.filechooser.FileFilter;
import
javax.swing.filechooser.FileNameExtensionFilter;
import
javax.swing.filechooser.FileView;
import
javax.swing.text.StyledEditorKit.ForegroundAction;
import
org.omg.CORBA.FREE_MEM;
import
org.w3c.dom.css.Rect;
public
class
DrawingBoard
{
public
static
void
main(String[]
args)
{
DrawGraphic
newPad
=
new
DrawGraphic();
//创建窗口对象
}
}
class
DrawGraphic
extends
JFrame
{
private
JButton
choices[];
//
按钮数组
private
String
names[]
=
{
“铅笔“,“直线“,“矩形“,“椭圆“,“圆角矩阵“,“圆“,“3D立方体“,“三角形“,“椭圆重叠“,“正余弦曲线“,“橡皮擦“,“背景色“,“颜色“};
//
按钮上的文本
private
String
tipText[]
=
{
“自由绘制“,“绘制直线“,“绘制矩形“,“绘制椭圆“,“绘制圆角矩阵“,“绘制圆“,“绘制3D立方体“,“绘制三角形“,“椭圆重叠“,“正余弦曲线“,“橡皮檫“,“设置透明背景色“,“选择颜色“};
//
按钮的提示字串
JToolBar
buttonBar;
//
工具条
Drawing
[]itemlist=new
Drawing[1000];
JCheckBox
fillCheckBox;//复选框
JSlider
strokeSlider;//滑动条
int
index=0;
private
int
currentType=1;//当前选择
private
Color
color=Color.black;//颜色
private
float
currentstroke=1.0f;//线条粗细
private
boolean
currentfill=false;//是否填充
private
boolean
isShiftDown
=
false;//释放按下shift键
private
JLabel
statusBar;
//
状态栏
private
double
A=0,B1=0,C=0,D=0;//f(x)=A*sin(B*x)+C*cos(D*x);
private
DrawPanel
drawingArea;
//
画图区域
private
JPanel
sliderPanel;//放置滑动条的面板
private
int
width
=
1000,height
=
600;
//
画图区域初始大小
private
JFileChooser
chooser;//颜色选择
private
BufferedImage
bi=null;//
最后的图形要保存下来,使用缓冲图像
private
Graphics
gg;//
图像专用画笔
public
DrawGraphic()
{
//窗口的构造方法
//super(“画板“);
//显式调用父类的带参构造方法,设置窗口标题为“画板“this.setTitle(“画板“);
//窗口的标题也通过窗口的属性来设置
JMenuBar
menuBar
=
new
JMenuBar();
//
创建菜单条
choices
=
new
JButton[names.length];
//
创建按钮数组
buttonBar
=
new
JToolBar(JToolBar.HORIZONTAL);
//
创建工具条对象,水平
drawingArea
=
new
DrawPanel();
//
创建画图区域
for
(int
i
=
0;
i
getWidth())
icon
=
new
ImageIcon(icon.getImage()
.getScaledInstance(getWidth(),-1,Image.SCALE_DEFAULT));//图片太大,设置为缩略图
setIcon(icon);
}
}
});
}
}
void
SaveFile()//保存文件功能
{
int
s
=
chooser.showSaveDialog(null);
Graphics2D
g2d=(Graphics2D)gg;
for(int
i=0;i
0))
{
try{
A=Double.parseDouble(s);//将String类型转换为double类型
}catch(NumberFormatException
e)
{
flag=false;
}
itemlist[index].A=A;
}
else
flag=false;
if(flag)//A正确设置B的值
{
s
=
(String)JOptionPane.showInputDialog(“请输入Sin(BX)中的参数B)“);
}
if((s
!=
null)
//将String类型转换为double类型
}catch(NumberFormatException
e)
{
flag=false;
}
itemlist[index].B1=B1;
}
else
flag=false;
if(flag)
{
s=(String)JOptionPane.showInputDialog(“请输入Sin(AX)*C中的参数
C“);
}
if((s
!=
null)
//将String类型转换为double类型
}catch(NumberFormatException
e)
{
flag=false;
}
itemlist[index].C=C;
}
else
flag=false;
if(flag)
{
s=(String)JOptionPane.showInputDialog(“请输入Cos(BX)*D中的参数
D“);
}
if((s
!=
null)
//将String类型转换为double类型
}catch(NumberFormatException
e)
{
flag=false;
}
itemlist[index].D=D;
}
}
}
class
Drawing
implements
Serializable
{
int
x1,x2,y1,y2;
ArrayList
pointList=new
ArrayList(
);
Color
color;//颜色
float
stroke;//粗细
int
type;//选择
boolean
fill=false;//是否填充
boolean
isShiftDown=false;//释放按下shift键
public
double
A,B1,C,D,sum;//正余弦曲线参数值
void
draw(Graphics2D
g2d){}//画图函数
}
class
Line
extends
Drawing//绘制直线
{
void
draw(Graphics2D
g2d)
{
g2d.setPaint(color);
g2d.setStroke(new
BasicStroke(stroke,BasicStroke.CAP_ROUND,BasicStroke.JOIN_BEVEL));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);//防止锯齿
if(isShiftDown)//按下shift键
{
double
x
=
x2
-
x1;
double
y
=
y2
-
y1;
double
length
=
Math.hypot(x,y);
double
sin
=
Math.abs(y
/
length);
if
(0
0)
y
=
x;
else
y
=
-x;
}
else
{
if
(x
y
>
0)
x
=
y;