简单图形绘制系统设计方案Word下载.docx
《简单图形绘制系统设计方案Word下载.docx》由会员分享,可在线阅读,更多相关《简单图形绘制系统设计方案Word下载.docx(51页珍藏版)》请在冰豆网上搜索。
![简单图形绘制系统设计方案Word下载.docx](https://file1.bdocx.com/fileroot1/2023-1/29/573e8f6d-c6aa-407d-b313-63cb531aafe0/573e8f6d-c6aa-407d-b313-63cb531aafe01.gif)
2.2.1题设要求
完成简单图形的绘制系统:
实现直线,矩形,圆的绘制,并能设置线型,线宽和颜色;
实现图形的重绘和保存功能;
实现在状态栏动态显示当前时间功能。
2.2.2题目分析
题目要求设计一个简单的绘图系统,程序功能要求简单,可以用一个简单的窗口菜单程序解决。
对题目要求的绘制图形和线条更改,使用菜单响应会很容易解决,至于图形的重绘和保存,状态栏的时间显示虽然使用的函数较为复杂,看似麻烦,实际上函数框架简化出来后很容易理解,响应功能的代码量也相对较少。
2.3设计原理
我创建的是一个单文档类的MFCAppWizard(exe)工程(图2-1,图2-2),在该工程里,我使用菜单(图2-3,图2-4)和对话框(图2-5)实现了题目要求的简单绘图设计。
图2-1创建MFC应用程序
图2-2创建单文档类MFC工程
图2-3双击IDR_MAINFRAME创建菜单
图2-4建立如图菜单项
图2-5建立如图所示对话框
第三章详细设计
3.1菜单的响应
3.1.1菜单的创建
首先建立一个但文档类型的MFCAppWizard(exe)工程,工程名为:
简单绘图演示(图2-1,图2-2),然后打开资源视图,找到“菜单”-“IDR_MAINFRAME”,双击“IDR_MAINFRAME”创建菜单(见图2-3图2-4)。
建立的菜单如图4所示。
3.1.2菜单的响应
菜单建好后,要为所建立的菜单添加消息响应函数,这样所建立的菜单才能被加载入程序(斜体部分为添加的消息响应函数,图3-1)。
例3-1
voidC简单绘图演示View:
:
OnLine()
{//TODO:
在此添加命令处理程序代码
}
OnCircle()
{
//TODO:
OnRect()
图3-1在类向导中响应创建的菜单项
(响应项ID:
ID_CIRCLE、ID_LINE、ID_RECT;
分别对应圆、直线、矩形)
接着,为C简单绘图演示View添加私有成员变量m_nDrawStyle(图3-2是具体的添加成员变量操作),并将m_nDrawStyle初始化为0(斜体为m_nDrawStyle初始化过程)。
例3-2
C简单绘图演示View:
C简单绘图演示View()
:
m_nDrawStyle(0)
在此处添加构造代码
m_nDrawStyle=0;
图3-2为C简单绘图演示View添加UINT类型的私有成员变量m_nDrawStyle
m_nDrawStyle变量初始化后再为响应函数赋值(斜体为赋值过程)
例3-3
m_nDrawStyle=1;
m_nDrawStyle=2;
赋值完成后,即要开始让程序绘图了,谈到绘图自然就想到了绘图的必要工具——画笔和画刷,当然,当我们调用绘图函数的时候其实系统已经提供了一个默认的画笔很画刷。
如果要自定义更改画笔和画刷的颜色,类型就需要另外调用申明了。
现在先使用默认工具响应图像的绘制,自定义画笔画刷后面会讲到。
对于直线、矩形和圆,在绘图是都可以由2个点来确定其图形。
当鼠标左键按下时得到一个点,当鼠标左键松开时又会得到一个点。
也就是说,在鼠标左键按下时将当前点保存为绘图原点,当鼠标左键松开时,就可以绘图了。
因此就需要为视类(C简单绘图演示View)分别捕获鼠标左键按下和左键松开这两个消息。
另外,当鼠标左键按下时,需要将鼠标当前按下点保存起来,因此为C简单绘图演示View类再增加一个CPoint类型的私有成员变量:
m_ptOrigin。
并在C简单绘图演示View类构造函数中,将该变量的值设置为0,即将原点设置为(0,0)。
然后,在鼠标左键按下消息响应函数中,保存当前点,代码如例3-4(斜体)。
例3-4
OnLButtonDown(UINTnFlags,CPointpoint)
在此添加消息处理程序代码和/或调用默认值
m_ptOrigin=point;
CView:
OnLButtonDown(nFlags,point);
在鼠标左键松开消息响应函数中实现绘图功能,具体代码如例3-5(斜体)。
例3-5
OnLButtonUp(UINTnFlags,CPointpoint)
CClientDCdc(this);
switch(m_nDrawStyle)
{
case1:
dc.Ellipse(CRect(m_ptOrigin,point));
break;
case2:
dc.Rectangle(CRect(m_ptOrigin,point));
case0:
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
}
OnLButtonUp(nFlags,point);
好了,绘图响应函数完成了,试运行看看程序是否能完成绘图操作。
为了进行绘图,首先需要有DC对象,例3-5所示代码中首先定义了一个CClientDC类型的变量:
dc。
然后将已经保存在变量m_nDrawStyle的用户选择调用出来,选择switch/case语句来分别完成绘图,完成用户的不同选择。
程序运行结果(图3-3):
图3-3简单绘图程序运行显示
从运行结果图中可以发现该程序绘制的图形都是黑色的,而且图形中绘制的圆也不是圆,而是一个椭圆,当一个图形在另一个图形上绘制的时候会将之前的图形覆盖掉。
为了有效的解决程序中发现的问题,我们一个一个分析:
1、图形显示为黑色,是因为系统默认的画笔和画刷都是黑色的,要想程序输出不用的颜色,这就需要为程序重新申明一支画笔和画刷;
2、绘制的圆是椭圆的原因是因为我们调用的是椭圆的绘制函数,在几何上,圆是椭圆的特殊形态,当椭圆的长轴和短轴相等时,椭圆就成了一个圆,换句话说就是当椭圆的外接矩形是一个正方形时,这是的椭圆就是圆,而椭圆的绘制函数就是通过外接矩形的左上角坐标和右下角坐标来绘制的,所以在获取椭圆的参数时,只要将左上角和右下角两个坐标的x,y的差取等即可;
3、图形会被覆盖是因为程序默认的画刷类型是一个白画刷,若是想看到图形里面的容,只需要将画刷类型改为透明即可。
程序更改如例3-6(斜体,粗体部分为修改后的容)
例3-6
CPenpen(PS_SOLID,1,RGB(255,0,0));
dc.SelectObject(&
pen);
CBrush*pBrush=CBrush:
FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
dc.SelectObject(pBrush);
dc.Ellipse(m_ptOrigin.x,m_ptOrigin.y,point.x,m_ptOrigin.y+point.x-m_ptOrigin.x);
运行结果(图3-4):
图3-4修改后程序运行结果图
从图中可以看到之前的问题已经被解决了。
3.2设置对话框
基本绘图功能已经实现,现在给“简单绘图演示”程序加上其他功能——线宽、线型和颜色按钮设置。
(对话框建立如第二章图2-5)
对话框建好后,为此对话框建立一个响应的对话框类。
图3-5为对话框建立相应的对话框类
响应对话框,创建一个响应消息(如例3-7斜体部分)。
例3-7
OnSetting()
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;
响应消息是应该注意添加头文件#include“SettingDlg.h”。
其中m_nLineWidth和m_nLineStyle变量的申明见图3-6。
申明后在C简单绘图演示View和SettingDlgView中初始化为0。
图3-6为编辑框和单选框添加变量
得到线宽和线型的变量后,在例3-7中已经保存赋值,接着就要使用了,线宽线型都是对画笔的变量,自然使用在画笔函数中,先前定义的画笔CPenpen(PS_SOLID,1,RGB(255,0,0));
其中三个参数分别对应线型线宽和颜色,将线型和线宽参数用变量m_nLineStyle和m_nLineWidth代替即可实现对画笔线型和线宽的更改,更改如下:
例3-8
CPenpen(m_nLineStyle,m_nLineWidth,RGB(255,0,0));
更改后运行结果如图3-7.
图3-7线型线宽实现后的运行结果
3.3颜色对话框
在先前对话框建立的时候,可以看到一个“颜色选择”按钮,该按钮是对画笔颜色进行自定义的控件。
MFC为我们提供了一个类:
CColorDialog,可以很方便地创建颜色对话框。
在SettingDlgView响应按钮“颜色选择”:
例3-9
voidCSettingDlg:
OnClickedColor()
在此添加控件通知处理程序代码
CColorDialogdlg;
dlg.m_cc.Flags|=CC_RGBINIT|CC_FULLOPEN;
dlg.m_cc.rgbResult=m_clr;
m_clr=dlg.m_cc.rgbResult;
其中m_clr是一个COLORREF类型的变量,该变量在SettingDlg.h中申明,是一个public成员。
然后在C简单绘图演示View响应OnSetting消息中添加如下粗体代码:
例3-10
dlg.m_clr=clr;
clr=dlg.m_clr;
其中clr是在C简单绘图演示View.h中定义的COLORREF类型的private成员变量。
做完这些后,再次更改画笔参数中的颜色参数,更改如下:
CPenpen(m_nLineStyle,m_nLineWidth,clr);
响应后运行结果如图3-8:
图3-8颜色对话框改变画笔颜色
3.4状态栏时间设置
通过第三章的前三节,我们已经创建了一个可以绘制圆、矩形和直线的简单绘图程序,该程序已经能够实现对,下面我们来扩展下程序对系统时间的响应。
首先增加一个名为时钟的字符串资源,创建方式:
双击StringTable文件夹下的StringTable项,打开C简单绘图演示程序的字符串资源,在其中添加一个“ID:
IDS_TIMER;
Caption:
时钟”的字符串资源。
然后在CMainFrame类源文件的前部定义:
例3-11
staticUINTindicators[]=
ID_SEPARATOR,//状态行指示器
IDS_TIMER,
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
为了在状态栏上显示时间的静态文本,在程序的CMainFrame类的OnCreate函数的后部,但要在其return语句前添加例3-12所示代码。
例3-12
CTimet=CTime:
GetCurrentTime();
CStringstr=t.Format("
%H:
%M:
%S"
);
CSizesz=dc.GetTextExtent(str);
intindex=0;
index=m_wndStatusBar.CommandToIndex(IDS_TIMER);
m_wndStatusBar.SetPaneInfo(index,IDS_TIMER,SBPS_NORMAL,sz.cx);
m_wndStatusBar.SetPaneText(index,str);
SetTimer(1,1000,NULL);
其中SetTimer()是一个定时器,起功能是1000毫秒触发一次定时器消息,加粗部分功能是获取输出文本显示是占据的宽度,然后直接用这个宽度去修改窗格的宽度。
此时我们已经获得了当前的系统时间,但是这个时间是静止的,我们要想它实时的显示系统当前的时间,就必须让这个时间“动起来”。
我们已经设置了一个定时器,没一秒发送一次WM_TIMER定时器消息,那么我们就可以在该定时器消息响应函数中再次获得系统当前时间,并设置状态栏窗格的文本。
加入代码如例3-13。
例3-13
voidCMainFrame:
OnTimer(UINT_PTRnIDEvent)
CTimet=CTime:
m_wndStatusBar.SetPaneInfo(1,IDS_TIMER,SBPS_NORMAL,sz.cx);
m_wndStatusBar.SetPaneText(1,str);
CFrameWndEx:
OnTimer(nIDEvent);
此时运行程序可以看到状态栏中的时间已经“动起来”了。
3.5图形的保存和重绘
程序运行后似乎没什么问题了,可是当我们放大或缩小窗口时,我们在窗口中绘制的图形会神奇的消失掉。
这是因为当窗口尺寸发生变化时,引起窗口重绘,会发送WM_PAINT消息,这是首先会擦除窗口的背景,然后再进行重绘操作,这样就把窗口中先前绘制的图形擦除掉了。
如果希望所绘制的图形始终在窗口中呈现出来,就需要将这些图形保存起来,然后当窗口尺寸发生变化引起窗口重绘时,将这些图形再次在窗口中输出。
当窗口重回是总是会调用程序视类的OnDraw函数,因此我们可以在该函数中完成图形的输出。
而保存图形的方式多种多样,对于本程序来说,只需要绘制时的起点、终点和绘制的类型(圆、矩形或直线)就可以了。
此时我们要新建一个类:
CGraph。
新增类类型为:
GenericClass。
为新增类添加成员变量:
例3-14
public:
CGraph(UINTm_nDrawType,CPointm_ptOrigin,CPointm_ptEnd,COLORREFm_clr1,UINTm_LineWidth,intm_LineStyle);
virtual~CGraph();
UINTm_nDrawType;
CPointm_ptOrigin;
CPointm_ptEnd;
COLORREFm_clr1;
intm_LineStyle;
UINTm_LineWidth;
在GraphView中初始化变量:
例3-15
CGraph:
CGraph(UINTm_nDrawType,CPointm_ptOrigin,CPointm_ptEnd,COLORREFm_clr1,UINTm_LineWidth,intm_LineStyle)
this->
m_nDrawType=m_nDrawType;
m_ptOrigin=m_ptOrigin;
m_ptEnd=m_ptEnd;
m_clr1=m_clr1;
m_LineWidth=m_LineWidth;
m_LineStyle=m_LineStyle;
在C简单绘图演示View视类OnDraw中加入如下代码:
例3-16
OnDraw(CDC*/*pDC*/)
C简单绘图演示Doc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!
pDoc)
return;
在此处为本机数据添加绘制代码
for(inti=0;
i<
m_ptrArray.GetSize();
i++)
CPenpen(((CGraph*)m_ptrArray.GetAt(i))->
m_LineStyle,((CGraph*)m_ptrArray.GetAt(i))->
m_LineWidth,
((CGraph*)m_ptrArray.GetAt(i))->
m_clr1);
dc.SelectObject(&
switch(((CGraph*)m_ptrArray.GetAt(i))->
m_nDrawType)
{
case1:
dc.Ellipse(((CGraph*)m_ptrArray.GetAt(i))->
m_ptOrigin.x,((CGraph*)m_ptrArray.GetAt(i))->
m_ptOrigin.y,
((CGraph*)m_ptrArray.GetAt(i))->
m_ptEnd.x,((CGraph*)m_ptrArray.GetAt(i))->
m_ptOrigin.y+((CGraph*)m_ptrArray.GetAt(i))->
m_ptEnd.x-((CGraph*)m_ptrArray.GetAt(i))->
m_ptOrigin.x);
break;
case2:
dc.Rectangle(CRect(((CGraph*)m_ptrArray.GetAt(i))->
m_ptOrigin,
m_ptEnd));
case0:
dc.MoveTo(((CGraph*)m_ptrArray.GetAt(i))->
m_ptOrigin);
dc.LineTo(((CGraph*)m_ptrArray.GetAt(i))->
m_ptEnd);
}
可以看到,代码中调用了一个CGraph*指针,其定义如下:
例3-17