2023年7月17日发(作者:)
F
简
单
的
绘
图
程
序
C
——王帅 M
目录
摘要 .............................................................................................................................................................. 2
关键字 ........................................................................................................................................................ 2
1 引言 ........................................................................................................................................................ 2
设计目的 ............................................................................................................... 错误!未定义书签。
2 功能说明 .............................................................................................................................................. 2
2.1菜单栏.......................................................................................................... 错误!未定义书签。
2.1.1图形 ................................................................................................................................... 3
2.1.2画笔 ...................................................................................................................4
2.1.3画硬币 .............................................................................................................................. 4
2.2工具栏......................................................................................................................................... 5
2.3状态栏......................................................................................................................................... 5
3 功能的实现 ........................................................................................................................................ 5
3.1 视图设计 ................................................................................................. 5
3.2 编辑资源 ................................................................................................. 6
3.3 编程思路及各个函数的实现 ...................................................................................... 7
(1)思路 ................................................................................................................................................ 7
(2)代码的实现 ................................................................................................................................ 7
第
1 页 1.为基本形状创建一个基类 ............................................................................................. 8
2.基本形状类的创建 ............................................................................................................. 8
2.1矩形类的创建及定义 ........................................................................................8
2.2圆形类的创建及定义 ........................................................................................10
2.3正五边形类的创建及定义 ................................................................................ 11
2.4正三角形类的创建及定义 ................................................................................14
2.5椭圆类的创建及定义 ........................................................................................16
2.6正四边形类的创建及的定义 ............................................................................17
2.7正六边形类的创建及定义 ................................................................................18
2.8直线类的创建及定义 .................................................................................................... 19
3.各基本形状类在CMyDraw2_0类中的调用和绘图的实现 ................... 20
3.1矩形类的调用与与绘图的实现 ........................................................................20
3.2圆形类的调用 ....................................................................................................24
3.3正三角形类的调用 ............................................................................................25
3.4基本类型调用的剩余代码 ........................................................................................... 26
4.画笔的使用、颜色及大小的调整 ........................................................................... 29
5.画硬币 ..................................................................................................................................... 35
6.工具栏中的自定义控件 ....................................................................................................... 38
7.状态栏中的显示 ................................................................................................................ 39
4程序功能的测试 ...............................................................................................41
5最后总结 ..........................................................................................................42
第
2 页
摘要:
本绘图程序能够进行基本图形的绘画,如直线,圆,矩形,三角形等等,并且在此基础上添加了多边形的绘画,如正五边形等。除此之外,还能够进行随手画,即用鼠标随意画线条。为了更好的绘图,还添加了对画笔粗细的调整,以及对画笔颜色的调整,除了特定的颜色,颜色还可根据输入的RGB值随意更改。还有一些老师的要求,加入了画硬币、显示硬币数目即鼠标坐标等信息。本程序主要采用面向对象写法。
关键字:程序设计,MFC,绘图
1.引言
设计目的
本绘图程序的设计不仅仅局限于老师课堂的要求,通过C++的编写实现绘图要求,我还想要在此基础上,加入自己的一些想法,想要更好地了解MFC,更好地去实现自己的想法。
2.功能说明
2.1菜单栏
2.1.1图形
图形栏中包括直线、矩形、圆形、椭圆、多边形,多边形中包括正三角形、
第
3 页 正四边形、正五边形、正六边形。
①选择直线,可用鼠标拖动画出一条直线
②选择矩形,可用鼠标拖动画出矩形
③选择圆形,可用鼠标拖动画出圆形
④选择椭圆,可用鼠标拖动画出椭圆
⑤选择正三角形,可用鼠标拖动画出正三角形
⑥选择正四边形,可用鼠标拖动画出正方形
⑦选择正五边形,可用鼠标拖动画出正五边形
⑧选择正六边形,可用鼠标拖动画出正六边形
(注:为了验证自己的想法以及想让画出的图形随意地变换方向,特意在正三角形一项中加入了旋转效果,使鼠标在拖动时能旋转三角形)
2.1.2画笔
画笔栏中包括颜色、大小及铅笔
(1)颜色
颜色中包括黑色、红色、绿色、蓝色、橙色、黄色、青色、紫色、粉色、
自定义
①选择黑色,画出的图形将为黑色
②选择红色,画出的图形将为红色
③选择绿色,画出的图形将为绿色
④选择橙色,画出的图形将为橙色
⑤选择黄色,画出的图形将为黄色
⑥选择青色,画出的图形将为青色
⑦选择紫色,画出的图形将为紫色
⑧选择粉色,画出的图形将为粉色
⑨选择自定义,可输入RGB值,画出的图形将显示输入的颜色
(2)大小
大小中包括1、2、3、4、5、6、7
①选择1,画笔大小设为1
②选择2,画笔大小设为2
③选择3,画笔大小设为3
④选择4,画笔大小设为4
⑤选择5,画笔大小设为5
⑥选择6,画笔大小设为6
⑦选择7,画笔大小设为7
(3)铅笔
选中铅笔后,将可以用鼠标进行随意画线
2.1.3画硬币
画硬币中包括画、增加、减少、清除
①选择画,将在客户端窗口中画出初始数量为10的硬币
第
4 页 ②选择增加,窗口中的硬币数目将增加1个
③选择减少,窗口中的硬币数目将减少1个
④选择清除,刷新窗口,将硬币消去
2.2工具栏
工具栏中除了原有的图标外,还加入了自定义的图标
①选择②选择③选择④选择⑤选择⑥选择⑦选择⑧选择同
,可用鼠标拖动画出一条直线
,可用鼠标拖动画出矩形
,可用鼠标拖动画出圆形
,可用鼠标拖动画出正三角形
,可用鼠标进行随手画
,可在窗口画出硬币后,将硬币数量+1
,可在窗口画出硬币后,将硬币数量-1
,可利用鼠标对所绘图形进行擦除,橡皮擦的大小与画笔大小相 2.3状态栏
状态栏中除了原有的显示外,还加入了硬币的数量以及鼠标的x坐标和y坐标
3.功能的实现
3.1视图设计
利用MFC 生成画图应用程序框架具体步骤如下:
(1)执行VC程序,选择File|New命令,弹出New对话框.单击Projects标签,转到Projects选项卡,选择MFC AppWizard(exe)选项,然后在Project name文本框中输入MyDraw2_0(原来也做过一个,不过并没有以面向对象的写法去写,这个就当作是我的第二个版本),文本框是指项目的本地路径。
第
5 页 (2)由于本程序是实现画线,要在视图中完成,所以首先创建一个基于单文档的应用程序
3.2编辑资源
(1)利用ResourceView中的Menu编辑器在菜单栏添加菜单,该流程图如下3.2所示:
图3.2
(2)利用ResourceView中的ToolBar编辑器,在工具栏中添加自定义控件。控件图案如下所示:
第
6 页 3.3编程思路及各个函数的实现
(1)思路:
首先,画定义好的形状。直线、矩形、圆形等等都属于基本的形状,那么我设定一个基类,称它为CShape,给这个基类定义一个画画的虚函数Draw(CDC
*pDC),在这个类里面派生出各个需要的类,如CCircle类,并为这些派生类定义各自的属性及方法,重写基类的Draw函数。当我需要用到这些类的时候,只需要在View类里创建指针,然后调用里面Draw方法。由于是当鼠标拖动的时候画出所需的图形,需要添加鼠标响应函数,onLButtonDown(),onLButtonUp,以及onMouseMove()。画画主要是在onMouseMove()里实现。
接着,是画笔的颜色和大小,本来是想单独创建一个画笔类,定义颜色和大小属性,使CCircle等派生类多继承,在继承一个画笔类,但尝试了几遍,发现在菜单里选择颜色时就会使程序停止运行,于是就放弃了。重新构思之后,由于画图是在CMyDraw2_0里实现的,就直接在CMyDraw2_0中定义了颜色和大小的变量,这样也方便。
然后是画硬币。并没有为这个创建单独的类,直接在CMyDraw2_0中的OnDraw()中画硬币,并且在CMyDraw2_0中添加了增加和减少硬币的方法。
工具栏中只要和为各个图标添加函数,作用和菜单栏中的图形一栏中对应即可。
最后还有硬币的数量和鼠标坐标放在状态栏中显示,下面开始进行函数代码的实现。
(2)代码的实现:
1.为基本形状创建一个基类,命名为CShape。
在ClassViewz中右键点击MyDraw2_0 classes->new class,在弹出窗口的顶部下拉框中选择Generic Class,如图所示
第
7 页
在头文件中添加虚函数Draw(CDC *pDC)
public:
CShape();
virtual Draw(CDC* pDc)=0;//添加的虚函数
virtual ~CShape();
2.基本形状类的创建(注:以矩形、圆形、正五边形、正三边形为重点介绍)
2.1矩形类的创建及定义
创建一个矩形类,继承CShape类,如图
在该类中重新定义画画函数Draw(),并添加带参数的构造函数,矩形的左上角,以及矩形的宽度和高度,代码如下:
Public:
CRectangle();
Draw(CDC* pDC); //重新定义Draw函数
CPoint point_LeftUp; //矩形的左上角坐标
CRectangle(int x,int y,int w=0,int h=0);
//带参数的构造函数,x表示左上角的横坐标,y表示左上角的纵坐标
int width; //矩形的宽度
int height; //矩形的高度
virtual ~CRectangle();
第
8 页
在无参数构造函数中初始化point_LeftUp的坐标和宽度以及高度的值,代码如下:
CRectangle::CRectangle()
{
point_LeftUp.x=0; //左上角坐标x值设置为0
point_LeftUp.y=0; //左上角坐标x值设置为0
width=0; //矩形的宽度初始为0
height=0; //矩形的高度初始为0
}
在带参数的构造函数中将值赋给point_LeftUp和宽度以及高度,代码如下:
point_LeftUp.x=x; //将传入的x值赋给左上角坐标的x值
point_LeftUp.y=y; //将传入的y值赋给左上角坐标的y值
width=w; //将传入的w值赋给width
height=h; //将传入的h值赋给height
重写Draw(CDC* pDC)函数,代码如下:
CRectangle::Draw(CDC* pDC)
{
pDC->Rectangle(point_LeftUp.x,point_LeftUp.y,point_LeftUp.x+width,
point_LeftUp.y+height);
//利用Rectangle()函数画出矩形,其中的值分别为矩形的左上角横坐标, 左上角纵坐标,右下角横坐标,右下角纵坐标
}
在CMyDraw2_0View中引入矩形类的头文件:双击CMyDraw2_0View,在
代码
// MyDraw2_0View.h : interface of the CMyDraw2_0View class
//
/////////////////////////////////////////////////////////////////////////////
第
9 页 #if !defined(AFX_MYDRAW2_0VIEW_H__3809529C_6744_4AD2_80A4 _D44683D0A5AF__INCLUDED_)
#define
AFX_MYDRAW2_0VIEW_H__3809529C_6744_4AD2_80A4_D44683D0 A5AF__INCLUDED_
下添加如下代码:
#include "Rectangle.h"
并在View类中添加私有成员变量,创建矩形类的指针:
右键点击CMyDraw2_0View,选择Add Member Variable,
在弹出的对话框中如下输入:
将在CMyDraw2_0View头文件中出现如下代码
Private:
CRectangle *rectangle;//定义指向矩形类的指针,
为私有变量
2.2圆形类的创建及定义
创建一个圆形类,命名为CCircle,继承CShape类,在该类中添加公有成员变量,代码如下:
public:
CCircle();
CCircle(int x,int y,int radius=0);
//带参数的构造函数,其中,x表示圆心的x值,y表示圆心的y值,radius表示圆的半径
Draw(CDC* pDC); //重新定义Draw函数
virtual ~CCircle();
int Radius; //定义圆的半径
第
10 页 CPoint center_point; //定义圆的中心点
在无参数的构造函数中初始化变量值,代码如下:
CCircle::CCircle()
{
center_point.x=0; //圆心的横坐标初始为0
center_point.y=0; //圆心的纵坐标初始为0
Radius=0; //圆的半径初始为0
}
在带参数的构造函数中将传入的值赋给各变量,代码如下:
CCircle::CCircle(int x,int y,int radius)
{
center_point.x=x; //将传入的x值赋给圆心的横坐标
center_point.y=y; //将传入的y值赋给圆心的纵坐标
Radius=radius; //将传入的radius值赋给圆的半径
}
重写定义的Draw函数,代码如下:
CCircle::Draw(CDC* pDC)
{
pDC->Ellipse(center_point.x-Radius,center_point.y-Radius,center_p oint.x+Radius,center_point.y+Radius);
//利用Ellipse()函数进行圆的绘制,其中的值分别为圆的外接正方形的左上角横坐标、纵坐标,右下角横坐标、纵坐标
}
在CMyDraw2_0View中引入圆形类的头文件:
#include "Circle.h"
添加私有成员变量,创建圆形类的指针变量:
CCircle *circle; //创建圆形类的指针,可以直接写在矩形类只针对下方
2.3正五边形类的创建及定义
创建一个正五边形类,命名为CPentangle,继承CShape类,
在该类中添加公有成员变量,代码如下:
public:
CPentangle();
CPentangle(int x,int y,int radius=0);//带参数的构造函数,x为外接圆圆心的横坐标,y为外接圆圆心的纵坐标,radius为外接圆的半径
第
11 页
int Radius; //定义外接圆半径
CPoint cP; //定义外接圆圆心
Draw(CDC* pDC); //重新定义Draw函数
virtual ~CPentangle();
在无参数的构造函数中初始化各变量,代码如下:
CPentangle::CPentangle()
{
cP.x=0; //圆心横坐标初始为0
cP.y=0; //圆心纵坐标初始为0
Radius=0; //外接圆半径初始为0
}
在带参数的构造函数中将传入的值赋给各变量,代码如下:
CPentangle::CPentangle(int x,int y,int radius)
{
cP.x=x; //将传入的x值赋给圆心的横坐标
cP.y=y; //将传入的y值赋给圆心的纵坐标
Radius=radius; //将传入的radius值赋给外接圆半径
}
下面重写的Draw函数与前两个不同,需要用到数学函数cos()以及sin(),由于两个函数用的是弧度制,还需引入数学变量PI,为了能够顺利的写入这些函数,需要在CPentangle类的客户端中引入数学类的头文件:
双击ClassView中的CPentangle(),在出现的构造函数上方,在如下代码
// : implementation of the CPentangle class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MyDraw2_0.h"
#include "Pentangle.h"
下添加数学类头文件:
#include “math.h”
再定义一个宏变量PI,添加如下代码:
#define PI 3.1415926
第
12 页
开始重写Draw(CDC* pDC)函数,代码如下:
CPentangle::Draw(CDC* pDC)
{
double rc=Radius*cos(36*PI/180); //将半径和36度的余弦值相乘并且赋给新的变量rc
double rs=Radius*sin(36*PI/180); //将半径和36度的正弦值相乘并且赋给新的变量rs
double Rc=Radius*cos(18*PI/180); //将半径和18度的余弦值相乘并且赋给新的变量Rc
double Rs=Radius*sin(18*PI/180); //将半径和18度的正弦值相乘并且赋给新的变量Rs
POINT pts[]={{cP.x+rs,cP.y+rc},{cP.x-rs,cP.y+rc},{cP.x-Rc,cP.y-R
s},{cP.x,cP.y-Radius},{cP.x+Rc,cP.y-Rs}};
//利用点类的数组将五个点储存在点数组pts中
pDC->Polygon(pts,5); //利用函数Polygon()进行多边形的绘画,其中pts为储存的点,5为点的个数
}
下面对Draw函数中各数据进行深层次的分析,表明它们的来历:
如图所示:
72。
以外接圆圆心为坐标轴中心,设该点的坐标为(cP.x,cP.y);
则右下角的坐标为
cP.x+R*sin(36*PI/180),cP.y+R*cos(36*PI/180)
按顺时针方向看,接下去的几个点的坐标分别为
cP.x-R*sin(36*PI/180),cP.y+R*cos(36*PI/180)
cP.x-R*cos(18*PI/180),cP.y-R*sin(18*PI/180)
cP.x,cP.y-R
cP.x+R*cos(18*PI/180),cP.y-R*sin(18*PI/180)
以上为正五边形5个点的来历,接下来在CMyDraw2_0View中引入正五边形类的头文件:
第
13 页 #include “Pentangle.h”
添加一个私有变量,创建指向正五边形的指针变量:
CPentangle *pentangle;
2.4正三角形类的创建及定义(这个类中添加了旋转)
创建一个正三角形类,命名为CDelta,继承CShape类,在该类中添加公有成员变量,代码如下:
public:
CDelta();
CDelta(int x,int y,int radius=0); //带参数的构造函数,其中x为外接圆圆心的横坐标,y为外接圆圆心的纵坐标,radius为外接圆半径
int Radius; //外接圆半径
CPoint cp; //外接圆圆心
double theta; //在正三角形原图上旋转过的角度
double st; //该变量储存的是sin(theta)
double ct; //该变量储存的事cos(theta)
Draw(CDC* pDC); 重新定义Draw函数
virtual ~CDelta();
在无参数构造函数中初始化变量,代码如下:
CDelta::CDelta()
{
cp.x=0; //圆心的横坐标初始为0
cp.y=0; //圆心的纵坐标初始为0
Radius=0; //外接圆半径初始为0
}
在带参数构造函数中将传入的值赋给各变量,代码如下:
CDelta::CDelta(int x,int y,int radius)
{
cp.x=x; //将传入的x值赋给圆心的横坐标
cp.y=y; //将传入的y值赋给圆心的纵坐标
Radius=radius; //将传入的radius值赋给外接圆半径
ct=1; //调用该函数时将cos(theta)设置为1
st=0; //调用该函数时将sin(theta)设置为0
}
与正五边形相同,要引入数学类的头文件以及定义宏变量PI,
#include “math”
#define PI 3.1415926
开始重写定义的Draw(CDC* pDC)函数,代码如下:
第
14 页
CDelta::Draw(CDC* pDC)
{
double rc=Radius*cos(60*PI/180); //外接圆半径与60度余弦值相乘后赋给rc
double rs=Radius*sin(60*PI/180); //外接圆半径与60度正弦值相乘后赋给rs
ct=cos(theta); //将theta的余弦值赋给ct
st=sin(theta); //将theta的正弦值赋给st
POINT dx1,dx11; //定义两个点(接下来会详细说明)
POINT dx2,dx22; //同上
POINT dx3,dx33; //同上
dx1.x=cp.x-cp.x;
dx1.y=cp.y-Radius-cp.y;
dx11.x=dx1.x*ct-dx1.y*st+cp.x;
dx11.y=dx1.y*ct+dx1.x*st+cp.y;
dx2.x=cp.x-rs-cp.x;
dx2.y=cp.y+rc-cp.y;
dx22.x=dx2.x*ct-dx2.y*st+cp.x;
dx22.y=dx2.y*ct+dx2.x*st+cp.y;
dx3.x=cp.x+rs-cp.x;
dx3.y=cp.y+rc-cp.y;
dx33.x=dx3.x*ct-dx3.y*st+cp.x;
dx33.y=dx3.y*ct+dx3.x*st+cp.y;
POINT pts[]={{dx11.x,dx11.y},{dx22.x,dx22.y},{dx33.x,dx33.y}};//定义点数组,存储正三角形的三个点
pDC->Polygon(pts,3);//利用画多边形的函数Polygon()画正三角形,pts为储存的三个点,3为点的个数
}
接下来对Draw函数里的变量以及运算进行解释:
如图所示,正三角形的中心到各顶点的距离为半径,
设中心点的坐标为(cp.x,cp.y),
则可得到右下角的坐标为
cp.x+R*sin(60*PI/180),cp.y+R*cos(60*PI/180)
按顺时针方向,接下来两个点的坐标分别为
cp.x-R*sin(60*PI/180),cp.y-R*cos(60*PI/180)
cp.x,cp.x-R
此时,我们得到了三个顶点的坐标,如果按这三个点的
第
15 页
R
60。 坐标画图,就会得到如图所示的三角形,在此基础上,
不妨设此图形逆时针转过的角度为,有以下原理作为基础:
设一个点的坐标为(x1,y1),它绕另一个点(x2,y2)旋转角,得到新的点的坐标为:
x=(x1-x2)*cos-(y1-y2)*sin+x2;
y=(y1-y2)*cos+(x1-x2)*sin+y2;
显然,只需得到三个点绕中心旋转后各自的新坐标,我们就可以根据旋转的角得到新的正三角形
在Draw(CDC * pDC)函数中,用theta来代替,以右下角顶点为例,原坐标为cp.x+rs,cp.y+rc
按如下代码将cos(theta)和sin(theta)替换:
ct=cos(theta);
st=sin(theta);
用dx3.x储存该点与中心点横坐标的差
dx3.y储存该点与中心点纵坐标的差,如下:
dx3.x=cp.x+rs-cp.x;
dx3.y=cp.y+rc-cp.y;
用dx33储存该点旋转后得到的新的坐标:
dx33.x=dx3.x*ct-dx3.y*st+cp.x;
dx33.y=dx3.y*ct+dx3.x*st+cp.y;
这样就得到了该点旋转后的坐标,其它两点按同样方法即可得到新坐标,dx22为左下角的新坐标,dx11为正上方的新坐标
接下来,在CMyDraw2_0View的头文件中引入正三角形类,
#include “Delta.h”
添加私有变量,创建正三角形类的指针变量:
CDelta* delta;
接下来我直接给出剩下基本形状类的代码(只在当中作注释,不再详细解释)
2.5椭圆类的创建和定义
创建名为CEllipse的类,继承CShape,在该头文件中添加如下代码:
class CEllipse : public CShape
{
public:
CEllipse();
CEllipse(int x,int y,int w=0,int h=0); //带参数的构造函数,值分别为外接矩形左上角的横坐标、纵坐标、宽度、高度
int width; //外接矩形的宽度
int height; //外接矩形的高度
第
16 页 CPoint center_point; //椭圆中心点
Draw(CDC* pDC); //重新定义Draw函数
virtual ~CEllipse();
};
在该类app中添加如下代码:
CEllipse::CEllipse()
{
center_point.x=0; //将中心点横坐标初始为0
center_point.y=0; //将中心点纵坐标初始为0
width=0; //将外接矩形宽度初始为0
height=0; //将外接矩形高度初始为0
}
CEllipse::CEllipse(int x,int y,int w,int h)
{
center_point.x=x; //将传入的x值赋给中心点的横坐标
center_point.y=y; //将传入的y值赋给中心点的纵坐标
width=w; //将传入的w值赋给宽度
height=h; //将传入的h值赋给高度
}
CEllipse::Draw(CDC* pDC)
{
pDC->Ellipse(center_point.x-width,center_point.y-height,center_point.x+width,center_point.y+height);//利用Ellipse()函数画椭圆
}
在CMyDraw2_0View的头文件中引入椭圆类,
#include “Ellipse.h”
添加私有变量,创建椭圆类的指针变量:
CEllipse *ellipse;
2.6正四边形类的创建及定义
命名为CQuadrangle,头文件中添加如下代码:
public:
CQuadrangle();
CQuadrangle(int x,int y,int radius=0); //带参数的构造函数,参数分别为中心点的横坐标、纵坐标、外接圆半径
int Radius; //外接圆半径
CPoint cPoint; //中心点
第
17 页
Draw(CDC* pDC); //重新定义Draw函数
virtual ~CQuadrangle();
在该类app中添加如下代码:
CQuadrangle::CQuadrangle()
{
cPoint.x=0; //将中心点的横坐标初始为0
cPoint.y=0; //将中心点的纵坐标初始为0
Radius=0; //将外接圆的半径初始为0
}
CQuadrangle::CQuadrangle(int x,int y,int radius)
{
cPoint.x=x; //将传入的x值赋给中心点的横坐标
cPoint.y=y; //将传入的y值赋给中心点的纵坐标
Radius=radius; //将传入的radius赋给外接圆半径
}
CQuadrangle::Draw(CDC* pDC)
{
double Rc=Radius*cos(45*PI/180); //将半径与45度余弦值的乘积赋给Rc
POINT
pts[]={{cPoint.x+Rc,cPoint.y+Rc},{cPoint.x+Rc,cPoint.y-Rc},{cPoint.x-Rc,cPoint.y-Rc},{cPoint.x-Rc,cPoint.y+Rc}}; //定义点数组,储存四个顶点
pDC->Polygon(pts,4);//利用多边形绘画函数画正四边形
}
在CMyDraw2_0View的头文件中引入正四边形类,
#include “Quadrangle.h”
添加私有变量,创建正四边形类的指针变量:
CQuadrangle *quadrangle;
2.7正六边形的创建及定义
命名为CRegularHexagon,头文件中添加如下代码:
public:
CQuadrangle();
CQuadrangle(int x,int y,int radius=0);//带参数的构造函数,参数分别为中心点的横坐标、纵坐标、外接圆半径
int Radius;//外接圆半径
CPoint cPoint;//中心点
Draw(CDC* pDC);//重新定义Draw函数
virtual ~CQuadrangle();
在该类app中添加如下代码:
CRegularHexagon::CRegularHexagon()
第
18 页 {
cp.x=0;//将中心点的横坐标初始为0
cp.y=0;//将中心点的纵坐标初始为0
Radius=0;//将外接圆的半径初始为0
}
CRegularHexagon::CRegularHexagon(int x,int y,int radius)
{
cp.x=x;//将传入的x值赋给中心点的横坐标
cp.y=y;//将传入的y值赋给中心点的纵坐标
Radius=radius;//将传入的radius值赋给外接圆半径
}
CRegularHexagon::Draw(CDC* pDC)
{
double rs=Radius*sin(30*PI/180);//将半径与30度正弦值的乘积赋给rs
double rc=Radius*cos(30*PI/180);//将半径与30度余弦值的乘积赋给rc
double Rs=Radius*sin(60*PI/180);//将半径与60度正弦值的乘积赋给Rs
double Rc=Radius*cos(60*PI/180);//将半径与60度余弦值的乘积赋给Rc
POINT
pts[]={{cp.x+rs,cp.y+rc},{cp.x-rs,cp.y+rc},{cp.x-Radius,cp.y},{cp.x-Rc,cp.y-Rs},{cp.x+Rc,cp.y-Rs},{cp.x+Radius,cp.y}};
//定义点数组pts,储存正六边形的六个顶点
pDC->Polygon(pts,6);//利用多边形绘画函数画出正六边形
}
在CMyDraw2_0View的头文件中引入正六边形类,
#include “RegularHexagon.h”
添加私有变量,创建正六边形类的指针变量:
CRegularHexagon* regularhexagon;
2.8直线类的创建及定义
命名为CLine,在头文件中添加如下代码:
public:
CLine();
CLine(int sx,int sy,int ex=0,int ey=0);//带参数的构造函数,分别为直线起点的横坐标、纵坐标,终点的横坐标、纵坐标
Draw(CDC* pDC);//重新定义Draw函数
第
19 页 CPoint p_start; //定义直线起点
CPoint p_end;//定义直线终点
virtual ~CLine();
在该类app中添加如下代码:
CLine::CLine()
{
p_start.x=0;//将起点横坐标初始为0
p_start.y=0;//将起点纵坐标初始为0
p_end.x=0;//将终点横坐标初始为0
p_end.y=0;//将终点纵坐标初始为0
}
CLine::CLine(int sx,int sy,int ex,int ey)
{
p_start.x=sx;//将sx的值赋给起点的横坐标
p_start.y=sy;//将sy的值赋给起点的纵坐标
p_end.x=ex;//将ex的值赋给终点的横坐标
p_end.y=ey;//将ey的值赋给终点的纵坐标
}
CLine::Draw(CDC* pDC)
{
pDC->MoveTo(p_start);//利用MoveTo()函数画出直线起点
pDC->LineTo(p_end);//利用LineTo()函数从起点画直线到终点
}
在CMyDraw2_0View的头文件中引入直线类,
#include “Line.h”
添加私有变量,创建直线类的指针变量:
CLine* line;
3.各基本形状类在CMyDraw2_0View类中的调用与绘图的实现
(注:以矩形、圆形、正三角形为重点介绍)
3.1矩形类的调用与与绘图的实现
绘图的过程是:鼠标左键按下->鼠标移动->鼠标左键弹起
在此,引入鼠标的三个响应函数,分别对应该三个过程:
第
20 页 按下ctrl+w,弹出如图所示对话框,并按如图操作,
选择右侧的Add Function(本应是黑色,由于已添加,变为灰色),将三个响应函数添加到CMyDraw2_0View类app中。
现在,需要告诉鼠标,当鼠标左键按下时开始进行绘画,那么,需要添加一个变量,告诉鼠标是否进行绘画:
为View类添加私有成员变量:
bool mDown;
在View类的构造函数中对该值进行初始化,代码如下:
CMyDraw2_0View::CMyDraw2_0View()
{
// TODO: add construction code here
mDown=false;//将mDown初始为false,表示默认为不进行绘画
}
在鼠标左键按下的响应函数中添加如下代码:
Void CMyDraw2_0View::OnLButtonDown(UINT nFlags, CPoint point)
{
mDown=true;//将mDown标记为true,表示此时即将开始绘画
}
第
21 页
在鼠标左键弹起的响应函数中添加如下代码:
void CMyDraw2_0View::OnLButtonUp(UINT nFlags, CPoint point)
{
mDown=false;//将mDown重新标记为false,表明此时应停止绘画
}
在鼠标移动时判断鼠标是否按下,如果按下则开始进行绘画:
void CMyDraw2_0View::OnMouseMove(UINT nFlags, CPoint point)
{
if(mDown)
{
//此处添加绘画代码(下面会说到)
}
}
到此,对鼠标是否进行绘画的判断已完成,接下来,需要告诉鼠标画出的图形应该是矩形,不妨设一个变量用来储存类型:
在View类中添加私有成员变量:
int ShapeType;//该变量用来储存图形类型
在View类构造函数中进行该变量的初始化:
ShapeType=-1;//默认为-1,表示为标的随手画(下面会提到)
为View类添加菜单中矩形的响应函数:
同样按下Ctrl+W,在弹出的对话框中如下选择:
第
22 页 图中,蓝色条中的字符为在资源编辑时定义的矩形的ID,同样选择Add
Functioin,在View类中出现如下代码:
void CMyDraw2_0View::OnMenuGraphRectangle()
{
// TODO: Add your command handler code here
}
在该函数中添加如下代码:
ShapeType=2;//用2来代表矩形
这样,就能用数字来表示各个基本形状了
有了这个变量后,在鼠标左键按下时,首先判断该变量是否为-1(因为初始为-1,对应的是随手画),假如不是,则对ShapeType的值进行判断,用switch函数进行相应的操作:
在鼠标左键按下的相应函数中添加如下代码:
if(ShapeType!=-1)//判断当前的ShapeType值是否为-1
{
switch(ShapeType)//对当前传入的ShapeType值进行选择,分别进行队形的操作
{
}
}
当然,画矩形需要给矩形类传入矩形的左上角坐标和右下角坐标,在绘图时对应的就是鼠标按下时的坐标(我们把它叫做起始点)、鼠标移动时的坐标(我们把它叫做终点),这样,需要用两个变量来存储这两个点:
在View类中添加私有成员变量:
CPoint ponit_start;//用来存储起点
CPoint point_end;//用来存储终点
在鼠标左键按下的响应函数中添加以下代码:
point_start=point;//将鼠标按下时的点存储在point_start中
point_end.x=0;//将鼠标移动时的点横坐标赋值为0
point_end.y=0;//将鼠标移动时的点纵坐标赋值为0
最后,一切准备就绪,该进行矩形的绘画了:
矩形对应的数字为2,在鼠标按下的相应函数中,在switch()函数中添加以下代码:
case 2:rectangle=new CRectangle(point_start.x,point_start.y);break;
//new一个矩形对象,将该地址存储在rectangle中,并将鼠标按下时的点(起点)传入,作为矩形的左上角的点
此时,当鼠标按下时,鼠标就能知道即将要进行的是矩形的绘画。
在鼠标移动的响应函数中也要对ShapeType值作出判断,告诉鼠标该进行矩形的绘画,方法与前面类似:
第
23 页 在该函数的开头添加如下代码:
CDC* pDC=GetDC();//打开图形设备接口,简单来说,就是用pDC来进行绘画
在if(mDown){}中添加如下代码:
switch(ShapeType)
{
case 2:pDC->SetROP2(R2_NOTXORPEN);//将颜色设置为反色
if(point_end.x!=0)//判断鼠标是否移动了
{
rectangle->Draw(pDC);//调用矩形类中的Draw函数
}
point_end=point;//将终点设置为鼠标当前所在的点
rectangle->width=point_end.x-point_start.x;//将终点与起点的横坐标之差赋给矩形类中的宽度width
rectangle->height=point_end.y-point_start.y;//将终点与起点的纵坐标之差赋给矩形类中的高度height
rectangle->Draw(pDC);调用矩形类中的Draw函数
break;
}
下面对以上代码进行解释:
当鼠标按下时,终点point_end的值为0,判断为false,将鼠标此时的点赋给point_end,储存起来,画出矩形,当鼠标移动后,判断为true,此时画出的矩形左上角坐标为鼠标按下时的点,高度和宽度为之前的高度和宽度,由于前面已将颜色设置为反色,所以将鼠标移动之前画的矩形覆盖掉,不会再看见,所以看到的矩形为当前的矩形,之前的矩形已无法看见,否则将会看到一连串的矩形。
3.2圆形类的调用
在3.1中已经为绘图做好了准备工作,下面只需要用一个数字表示圆形类看,并在鼠标左键按下和鼠标移动的响应函数中的switch语句中添加相应代码即可:
void CMyDraw2_0View::OnMenuGraphCircle()
{
// TODO: Add your command handler code here
ShapeType=3;//用3来表示圆形
第
24 页 }
在OnLButtonDown()中的switch语句中添加如下代码:
Case 3:circle=new CCircle(point_start.x,point_start.y);break;
//new 一个圆形类对象,将地址储存在circle中,并将起点传入,作为圆形的中心点
在OnMouseMove()中的switch语句中添加如下代码:
case 3:pDC->SetROP2(R2_NOTXORPEN);//将颜色设为反色
if(point_end.x!=0)//判断鼠标是否移动
{
circle->Draw(pDC);//调用圆形类中的Draw()函数
}
point_end=point;//将鼠标当前所在的点保存在ponit_end中
xx=point_end.x-point_start.x;//将终点与起点的横坐标之差赋给xx(由于很多地方都会用到该变量,我将它作为View类的私有成员变量)
yy=point_end.y-point_start.y;//将终点与起点的纵坐标之差赋给yy(同上)
circle->Radius=(int)sqrt(xx*xx+yy*yy);//将两点间的距离作为圆的半径
circle->Draw(pDC);//调用圆形类中的Draw函数
break;
接下来,相同作用的代码不再做注释
3.3正三角形类的调用
void CMyDraw2_0View::OnMenuGraphPolygonDelta()
{
// TODO: Add your command handler code here
ShapeType=5;//用5来表示正三角形
}
在OnLButtonDown()中的switch语句中添加如下代码:
case 5:delta=new CDelta(point_start.x,point_start.y);break;
//new 一个正三角形类对象,将地址保存在delta中,并将起点传入,作为正三角形的中心点
在OnMouseMove()中的switch语句中添加如下代码:
第
25 页 case 5:pDC->SetROP2(R2_NOTXORPEN);
if(point_end.x!=0)
{
delta->Draw(pDC);
}
point_end=point;
xx=point_end.x-point_start.x;
yy=point_end.y-point_start.y;
delta->Radius=(int)sqrt(xx*xx+yy*yy);
delta->theta=(double)(point.x-point_start.x)/delta->Radius*PI*2;
//由于theta的取值范围是0~360度,类型为double,假如直接用数学函数asin(),只能取到-90度到90度,所以,当鼠标绕着中心转动的时候,会有余弦的函数cos(),该值为point.x-point_start.x,取值范围是-1~1,只要让该值与2*PI相乘,就能得到-2*PI~2*PI的值,就能符合theta的取值
(注:代码中的强制转型(double)为关键,否则所得到的值会被近似为0)
delta->Draw(pDC);
break;
接下来,将基本类型调用的剩余代码给出:
3.4基本类型调用的剩余代码
用数字表示各基本形状:
void CMyDraw2_0View::OnMenuGraphLine()
{
// TODO: Add your command handler code here
ShapeType=1;
}
void CMyDraw2_0View::OnMenuGraphEllipse()
{
// TODO: Add your command handler code here
ShapeType=4;
}
void CMyDraw2_0View::OnMenuGraphPolygonQuadrangle()
{
// TODO: Add your command handler code here
ShapeType=6;
}
第
26 页 void CMyDraw2_0View::OnMenuGraphPolygonPentangle()
{
// TODO: Add your command handler code here
ShapeType=7;
}
void CMyDraw2_0View::OnMenuGraphPolygonRegularHexagon()
{
// TODO: Add your command handler code here
ShapeType=8;
}
在OnLButtonDown中:
case 1:line=new CLine(point_start.x,point_start.y);break;
case 4:ellipse=new CEllipse(point_start.x,point_start.y);break;
case 6:quadrangle=new CQuadrangle(point_start.x,point_start.y);break;
case 7:pentangle=new CPentangle(point_start.x,point_start.y);break;
case 8:regularhexagon=new CRegularHexagon(point_start.x,point_start.y);break
在OnMouseMove中:
case 1:
pDC->SetROP2(R2_NOTXORPEN);
if(point_end.x!=0)
{
line->Draw(pDC);
}
point_end=point;
line->p_end=point;
line->Draw(pDC);
break;
case 6:pDC->SetROP2(R2_NOTXORPEN);
if(point_end.x!=0)
{
quadrangle->Draw(pDC);
}
第
27 页 point_end=point;
xx=point_end.x-point_start.x;
yy=point_end.y-point_start.y;
quadrangle->Radius=(int)sqrt(xx*xx+yy*yy);
quadrangle->Draw(pDC);
break;
case 7:pDC->SetROP2(R2_NOTXORPEN);
if(point_end.x!=0)
{
pentangle->Draw(pDC);
}
point_end=point;
xx=point_end.x-point_start.x;
yy=point_end.y-point_start.y;
pentangle->Radius=(int)sqrt(xx*xx+yy*yy);
pentangle->Draw(pDC);
break;
case 8:pDC->SetROP2(R2_NOTXORPEN);
if(point_end.x!=0)
{
regularhexagon->Draw(pDC);
}
point_end=point;
xx=point_end.x-point_start.x;
yy=point_end.y-point_start.y;
regularhexagon->Radius=(int)sqrt(xx*xx+yy*yy);
regularhexagon->Draw(pDC);
}
最后,还有一种画法,就是”随手画”
我们已经判断过ShapeType!=-1时执行以上代码,而ShapeType默认为-1,所以如果要随手画,就要将ShapeType值重新变为-1,为画笔菜单中的铅笔添加响应函数,并将ShapeType值变为-1:
void CMyDraw2_0View::OnPencil()
{
// TODO: Add your command handler code here
ShapeType=-1;
第
28 页 }
并在OnMouseMove中,再增加以下代码:
if(-1==ShapeType)
{
pDC->MoveTo(point_start);//将画出起点
pDC->LineTo(point);//画出起点到终点的线条
point_start=point;//将终点设置为上一个点
}
以上即为绘图(不包括改变画笔及画硬币、工具栏)的所有代码,接下来,开始讲解画笔颜色及大小的调整
4.画笔的使用、颜色及大小的调整
在MFC里有一个CPen类,用来设定画笔的属性,使用方法为:
CPen 自定义名称(线条类型,大小,颜色)
所以,我们可以在鼠标移动的时候设定画笔属性:
在打开图形设备接口(即CDC* pDC)后,开始设定,添加如下代码:
CPen pen(PS_SOLID,1,RGB(0,0,0));//其中,画笔类型为实现,大小为1,颜色为黑色
pDC->SelectObject(&pen);//将pen传给pDC,使其能够使用定义的画笔
既然可以调用,那么如果想要由自己去改变画笔属性,可以定义两个变量,用来保存画笔大小和颜色:
为View类添加私有成员变量:
int pen_width;//用来保存画笔大小
COLORREF pen_color;//该变量类型为COLORREF,可以用来保存颜色的RGB值
在View类构造函数中初始两个变量:
pen_color=RGB(0,0,0);//颜色默认为黑色
pen_width=1;//画笔大小默认为1
所以,在设定画笔属性时,可以这样设定:
CPen pen(PS_SOLID,pen_width,pen_color);
//pen_width和pen_color可以随意改变
与基本形状类的情况相同,可以在用户选择颜色和大小后,将pen_color和pen_width设置为对应的RGB值和数字
以红色和大小2为例:
为画笔菜单里的红色选项创建响应函数,并将pen_color设置为对应RGB值:
void CMyDraw2_0View::OnMenuCpenColorRed()
{
// TODO: Add your command handler code here
第
29 页 pen_color=RGB(255,0,0);
}
为画笔菜单里的2选项创建响应函数,并将pen_width设置为对应数字:
void CMyDraw2_0View::OnMenuCepnWidthTwo()
{
// TODO: Add your command handler code here
pen_width=2;
}
接下来,直接给出颜色及大小调整的剩余代码:
颜色的设定:
void CMyDraw2_0View::OnMenuCpenColorBlack()
{
// TODO: Add your command handler code here
pen_color=RGB(0,0,0);//将颜色设置为黑色
}
void CMyDraw2_0View::OnMenuCpenColorGreen()
{
// TODO: Add your command handler code here
pen_color=RGB(0,255,0);//将颜色设置为绿色
}
void CMyDraw2_0View::OnMenuCpenColorBlue()
{
// TODO: Add your command handler code here
pen_color=RGB(0,0,255);//将颜色设置为蓝色
}
void CMyDraw2_0View::OnMenuCpenColorOrange()
{
// TODO: Add your command handler code here
pen_color=RGB(255,97,0);//将颜色设置为橙色
}
void CMyDraw2_0View::OnMenuCpenColorYellow()
{
// TODO: Add your command handler code here
pen_color=RGB(255,255,0);//将颜色设置为黄色
}
第
30 页 大小的设定:
void CMyDraw2_0View::OnMenuCpenColorCyan()
{
// TODO: Add your command handler code here
pen_color=RGB(0,255,255);//将颜色设置为青色
}
void CMyDraw2_0View::OnMenuCpenColorPurple()
{
// TODO: Add your command handler code here
pen_color=RGB(153,51,102);//将颜色设置为紫色
}
void CMyDraw2_0View::OnMenuCpenColorPink()
{
// TODO: Add your command handler code here
pen_color=RGB(255,0,156);//将颜色设置为粉色
}
void CMyDraw2_0View::OnMenuCepnWidthOne()
{
// TODO: Add your command handler code here
pen_width=1;//大小设置为1
}
void CMyDraw2_0View::OnMenuCepnWidthThree()
{
// TODO: Add your command handler code here
pen_width=3;//大小设置为3
}
void CMyDraw2_0View::OnMenuCepnWidthFour()
{
// TODO: Add your command handler code here
pen_width=4;//大小设置为4
}
void CMyDraw2_0View::OnMenuCepnWidthFive()
{
// TODO: Add your command handler code here
pen_width=5;//大小设置为5
}
void CMyDraw2_0View::OnMenuCepnWidthSix()
第
31 页
{
// TODO: Add your command handler code here
pen_width=6;//大小设置为6
}
void CMyDraw2_0View::OnMenuCepnWidthSeven()
{
// TODO: Add your command handler code here
pen_width=7;//大小设置为7
}
到此,就能够画出定义的各种形状,还能选择定义的颜色,当然,毕竟颜色有限,为了能够随意改变颜色,还添加了一个颜色选项,名为”自定义”,用来自定义颜色,下面进行详细讲解:
由于需要用户自己输入RGB值,所以需要一个对话框来完成信息的交互:
在ResourceView中右键Dialog,选择”插入Dialog”,对出现的原始对话框如图进行编辑:
将ID设置为IDD_DIALOG_COLOR,双击对话框,将会弹出信息框,询问是否为该对话框创建新的类,如图选择,
第
32 页 会弹出如下对话框,如图所示进行选择和命名,
在ClassView中会出现CDialogColor的类,在该类中添加共有成员变量:
public :
int R;
int G;
int B;
回到ResourceView中的对话框编辑界面,双击对话框中的”编辑”按钮,分别创建响应函数,在响应函数中如下去写:
void CDialogColor::OnChangeColorR()
{
// TODO: If this is a RICHEDIT control, the control will not
// send this notification unless you override the
CDialog::OnInitDialog()
// function and call CRichEditCtrl().SetEventMask()
// with the ENM_CHANGE flag ORed into the mask.
// TODO: Add your control notification handler code here
CString strR;//定义String类型变量strR,用来保存编辑框中传入的值
第
33 页 GetDlgItemText(IDC_COLOR_R,strR);//通过GetDlgItemText函数获得编辑框中传入的值并赋给strR,其中的参数分别为编辑框的ID、变量strR
R=atof(strR);//将strR转化为浮点数,并赋值给R
}
void CDialogColor::OnChangeColorG()
{
// TODO: If this is a RICHEDIT control, the control will not
// send this notification unless you override the
CDialog::OnInitDialog()
// function and call CRichEditCtrl().SetEventMask()
// with the ENM_CHANGE flag ORed into the mask.
// TODO: Add your control notification handler code here
CString strG;
GetDlgItemText(IDC_COLOR_G,strG);
G=atof(strG);
}
void CDialogColor::OnChangeColorB()
{
// TODO: If this is a RICHEDIT control, the control will not
// send this notification unless you override the
CDialog::OnInitDialog()
// function and call CRichEditCtrl().SetEventMask()
// with the ENM_CHANGE flag ORed into the mask.
// TODO: Add your control notification handler code here
CString strB;
GetDlgItemText(IDC_COLOR_B,strB);
B=atof(strB);
}
通过以上代码,就可以获取对话框中输入的值了,就可以在View类中使用它们:
为View类添加私有成员变量:
int R;
int G;
int B;
第
34 页 在自定义的响应函数中添加如下代码:
void CMyDraw2_0View::OnMenuPenColorCustom()
{
// TODO: Add your command handler code here
CDialogColor DlgColor;创建CDialogColor的引用
l();调用DoModal()函数弹出对话框
R=DlgColor.R;//将CDialogColor中的R赋给View类的R
G=DlgColor.G;//将CDialogColor中的G赋给View类的G
B=DlgColor.B;//将CDialogColor中的B赋给View类的B
pen_color=RGB(R,G,B);//将传入的值作为RGB值
}
5.画硬币
画硬币菜单下有四个选项:画、增加、减少、清除
显然,是在点击”画”之后才开始在窗口上显示画出的硬币,由于画硬币的代码直接写在View类的OnDraw中,所以需要一个标记,判断是否需要画:
为View类添加私有成员变量:
bool draw;
在View类构造函数中初始化该变量:
draw=false;
在”画”的响应函数中将其标记为true:
draw=true;
这样,在OnDraw函数中就会根据draw的值判断是否开始画硬币。
画硬币还需要知道硬币的数量,而且,在画的时候,使用椭圆代替硬币,变化的只是椭圆的两个纵坐标,所以,还需要为View类添加三个私有成员变量:
int CoinsNumber;//硬币的数量
int coin_ly;//椭圆左上角的纵坐标
int coin_ry;//椭圆右上角的纵坐标
在构造函数中初始硬币数量:
CoinsNumber=10;
在OnDraw函数中,先定义第一个硬币的左、右纵坐标:
coin_ly=300;
coin_ry=330;
第
35 页
然后判断是否开始画硬币,当条件为真时开始画硬币,代码如下:
if(draw)
{
for(int i=0;i { pDC->Ellipse(100,coin_ly,300,coin_ry);//画出椭圆 coin_ly-=10;//循环一次就将左上角的纵坐标-10,表示下一个椭圆的位置上移10 coin_ry-=10;//循环一次就将右下角的纵坐标-10,表示下一个椭圆的位置上移10 } } 此时,如果在菜单里选择”画”选项,就需要调用OnDraw()函数,在响应函数中添加如下代码: CDC *pDC=GetDC(); OnDraw(pDC); 在此基础上,增加对硬币数量的增减操作: 很明显,增减硬币操作是在画硬币之后才会执行,所以需要一个标记来判断是否已经画出硬币: 为View类添加一个私有成员变量: bool menu_draw_coin;//用来标记菜单里”画”选项是否执行 在View类构造函数里初始化该变量: menu_draw_coin=false; 当选择”画”时,将该变量标记为true: menu_draw_coin=true; 已经有了标记后,只需判断是否已经执行”画”命令,再对硬币的数量进行增减,代码如下: void CMyDraw2_0View::OnMenuDrawcoinAdd() { if(menu_draw_coin)//判断是否已经执行过”画”命令 { draw=true;//将draw标记为true,以便OnDraw函数中的画硬币顺利执行 CDC *pDC=GetDC();//打开图形设备接口 // TODO: Add your command handler code here 第 36 页 if(CoinsNumber<=30)//为硬币数量设置最大值 CoinsNumber++;//将硬币数量+1 GetDocument()->UpdateAllViews(NULL);//刷新视图 ReleaseDC(pDC);//释放 } } void CMyDraw2_0View::OnMenuDrawcoinReduce() { if(menu_draw_coin)//判断是否已经执行过”画”命令 { draw=true;;//将draw标记为true,以便OnDraw函数中的画硬币顺利执行 CDC *pDC=GetDC();//打开图形设备接口 // TODO: Add your command handler code here if(CoinsNumber>0)//硬币数量应在大于0时才能减少 CoinsNumber--;//将硬币数量-1 GetDocument()->UpdateAllViews(NULL);//刷新视图 ReleaseDC(pDC);//释放 } } 最后的问题就是,画出的硬币会一直存在视图内,在”清除”选项的响应函数中添加如下代码: draw=false;//将draw重新标记为false,表示停止画硬币 menu_draw_coin=false;//将改变量重新标记为false,表示增减操作停止 GetDocument()->UpdateAllViews(NULL);//刷新视图 以上就完成了画硬币的相应操作。 第 37 页 6.工具栏中的自定义控件 如果在工具栏中有控件,可以直接点击后执行相应的操作无疑会更方便,以直线控件为例: 双击ResourceView的Toolbar,出现如下界面: 点击上方工具栏图标所在的最右侧空图标,在该空白图标中画出直线,作为直线的图标,双击该图标弹出对话框,按下图填写: 按Ctrl+W打开类向导,为该ID添加响应函数,在该函数中添加代码: void CMyDraw2_0View::OnDrawLine() { // TODO: Add your command handler code here ShapeType=1;//与原先调用直线类画直线同理 } 接下来给出已添加的控件对应的代码: void CMyDraw2_0View::OnDrawRectangle() { // TODO: Add your command handler code here ShapeType=2;////与原先调用矩形类画矩形同理 第 38 页 } void CMyDraw2_0View::OnDrawCircle() { // TODO: Add your command handler code here ShapeType=3;//与原先调用圆形类画圆形同理 } void CMyDraw2_0View::OnDrawDelta() { // TODO: Add your command handler code here ShapeType=5;//与原先调用正三角形类画正三角形同理 } void CMyDraw2_0View::OnAddCoin() { // TODO: Add your command handler code here OnMenuDrawcoinAdd();//直接调用硬币增加的函数 } void CMyDraw2_0View::OnReduceCoin() { // TODO: Add your command handler code here OnMenuDrawcoinReduce();//直接调用硬币减少的函数 } void CMyDraw2_0View::OnEraser() //橡皮擦 { // TODO: Add your command handler code here pen_color=RGB(255,255,255);//将颜色设置为白色 ShapeType=-1;//使用随手画 } 注:做橡皮擦比较偷懒,所以需要用户自己重新选择画笔颜色 7.状态栏中的显示 以鼠标坐标的显示为例: 双击ResourceView中的String Table,出现如下界面: 第 39 页 双击最下方的空白处,弹出对话框,按下图操作: 其中ID为ID_IDICATOR_MOUSE_XPOSITION,将该ID写入到CMainFrame的app中: static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, ID_INDICATOR_MOUSE_XPOSITION,//该ID为新添加的ID }; 由于鼠标坐标随着鼠标移动而变动,所以在OnMouseMove()中添加如下代码: CString strXPosition;//定义String变量strPosition CStatusBar* pStatus=(CStatusBar* )AfxGetApp()->m_pMainWnd->GetDescendantWindow(ID_VIEW_STATUS_BAR);//先获得主窗口指针,再获得状态栏指针 (" x:%d",point.x);//设置要显示的信息 pStatus->SetPaneText(4,strXPosition);//显示鼠标横坐标,4:鼠标ID在代码中的位置为第5,按数组下标来算,应为4 第 40 页 下面给出硬币、鼠标横纵坐标显示的全部代码(与例子里的位置稍有不同) 添加的ID: ID_INDICATOR_COIN,//硬币的ID ID_INDICATOR_MOUSE_XPOSITION,//鼠标横坐标 ID_INDICATOR_MOUSE_YPOSITION,//鼠标纵坐标 显示代码: OnMouseMove()中: CString strXPosition,strYPosition;//鼠标的横纵坐标 CStatusBar* pStatus=(CStatusBar* )AfxGetApp()->m_pMainWnd->GetDescendantWindow(ID_VIEW_STATUS_BAR); (" x:%d",point.x); (" y:%d",point.y); pStatus->SetPaneText(5,strXPosition);//显示鼠标横坐标 pStatus->SetPaneText(6,strYPosition);//显示鼠标纵坐标 OnDraw()中: CString strCoins;//硬币数量 CStatusBar* pStatus=(CStatusBar*)AfxGetApp()->m_pMainWnd->GetDescendantWindow(ID_VIEW_STATUS_BAR); if(pStatus) { ("硬币:%d",CoinsNumber); pStatus->SetPaneText(4,strCoins);//显示硬币数量 } 至此,已完成所有设计的功能 4.程序功能的测试 程序的测试效果如下图所示: 第 41 页 该图为自定义输入RGB值, 该图为绘画效果图 5.最后总结 为了完成这个程序,我也花了挺长时间,能够亲自将它做出来,这无疑让我感到高兴。我在这个过程当中遇到了许多困难,比如突然冒出想法要做旋转效果,为了这个效果自己去计算,试了好多遍都没成功,也是突然想到只需要关注点的旋转就可以。也由于这个程序,我对面向对象的理解与应用更为深刻了。总的来说,时间花下去了,也收获了很多。 第 42 页
发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1689605314a269952.html
评论列表(0条)