设计报告:Graphic简易画图板-----韩伟谢程焜肖越周峰电科二班1设计目的设计一个单文档类型的MFC AppWizard (exe)工程,工程取名为:Graphic。
此程序将实现简单的绘图功能,包括点、直线、矩形、椭圆、扇形和连续线的绘制。
并且能实现绘图的控制,包括线宽、线型和颜色的设置,图形的保存和打开以及笔刷的使用。
2 总体设计设计图如图6图63详细设计首先,新建一个单文档类型的MFC AppWizard (exe)工程,工程取名为:Graphic。
为此程序添加一个子菜单,菜单名称为“绘图”,并为其添加六个菜单项,分别用来控制不同图形的绘制。
当用户选择其中的一个菜单项后,程序将按照当前的选择进行相应图形的绘制。
添加的六个菜单项的ID及名称如表1所示。
然后分别为这六个菜单项添加命令响应,本程序让视类(CGraphicView)对这些菜单命令进行响应,这六个响应函数的名称分别如表1所示。
在程序运行以后,当用户单击某个菜单项时,应该把用户的选择保存起来,以便随后的绘图操作使用。
因此在CGraphicView类中添加一个私有变量m_nDrawType;用来保存用户的选择,该变量的定义如下所述:private: UINT m_nDrawType;接着,在视类的构造函数中将此变量初始化为0,程序代码如下:CGraphicView::CGraphicView(){// TODO: add construction code herem_nDrawType=0;}利用switch/case语句,来分别完成相应图形的绘制。
当用户选择【绘图】菜单下的不同子菜单项时,将变量m_nDrawType设置为不同的值。
程序代码如下:void CGraphicView::OnDot(){// TODO: Add your command handler code herem_nDrawType=1;}void CGraphicView::OnLine(){// TODO: Add your command handler code herem_nDrawType=2;}void CGraphicView::OnRectangle(){// TODO: Add your command handler code herem_nDrawType=3;}void CGraphicView::OnEllipse(){// TODO: Add your command handler code herem_nDrawType=4;}void CGraphicView::OnShanxing(){// TODO: Add your command handler code herem_nDrawType=5;}void CGraphicView::OnLianxuxian(){// TODO: Add your command handler code herem_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 defaultm_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));//把创建的画笔选入设备描述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);}如果在上面绘制连续线条的程序中,保持每段小直线的起点不变,即以鼠标左键按下时的起点为起点不变,分别绘制到鼠标移动点的直线,这时就会出现扇形的效果。