c++简单画图程序 whut.docx
《c++简单画图程序 whut.docx》由会员分享,可在线阅读,更多相关《c++简单画图程序 whut.docx(21页珍藏版)》请在冰豆网上搜索。
c++简单画图程序whut
简单画图程序
1.根本功能描述
简单画图程序实现了常见图形的绘制、图形属性的设置和图形数据的暂存等功能。
该程序的具体功能模块包括以下几项:
1)图形绘制模块。
该模块实现直线段、椭圆、矩形等图形的绘制功能。
在鼠标移动的过程中能实时显示当前绘制的图形。
2)图形属性设置模块。
该模块实现绘图线条的线宽,线色,图形填充色等属性设置功能。
3)图形数据暂存模块。
该模块实现直线段、椭圆、矩形等图形数据暂存功能,涉与图形的坐标、线宽、线色、填充色等数据。
2.设计思路
1)对需要用到的变量进展初始化。
2)选择相应的图形之后就响应相应的消息处理函数,给shape赋对应的值。
选择不同的线宽,线色与填充色,即可改变画笔或画刷的属性。
3)鼠标的按下响应函数OnLButtonDown(),捕捉鼠标当前位置得到起点的坐标,鼠标的拖动响函数OnMouseMove()改变终点的坐标,鼠标的弹起响应OnLButtonUp(),确定终点坐标,刷新,得到绘制图形。
4)选择图形或其它属性,可进展下一次绘制。
5)程序的流程图如下:
图1程序流程图
3.软件设计
3.1设计步骤
1)创建单文档
创建一个MFCAppWizard[exe]工程,命名为“LiYuJing〞,如图1所示,并创建单文档,如图2所示。
创建成功后,系统自动生成相应的类,如图3所示。
图2创建工程
图3创建单文档
图4生成类
2)编辑菜单
添加需要的菜单项,如图4所示;并在菜单的属性中设定好所对应的ID,如图5所示,各项菜单对应的ID如表1所示〔其中线宽菜单为弹出菜单,只需在菜单项目属性中的弹出选项前打勾即可,分隔线亦只需在菜单项目属性中选中分隔符选项即可〕。
图5添加菜单项
图6设置菜单ID
表1对应菜单ID
菜单名
ID
菜单名
ID
直线
ID_LINE
线宽1
ID_W1
矩形
ID_RECT
线宽2
ID_W2
椭圆
ID_ELLIPSE
线宽3
ID_W3
颜色
ID_COLOR
线宽4
ID_W4
填充色
ID_FILLCOLOR
线宽5
ID_W5
建立类向导,在视图类CLiYuJingView中,对各菜单项添加对应的MAND消息处理函数,局部菜单项还添加对应的UPDATE_MAND_UI消息函数,如图7所示。
图7建立类向导
3)创建工具栏
在插入处选择资源,新建工具栏,如图8所示;
图8新建工具栏
在工具栏上添加相应的按钮,在属性处更改其ID,如图9所示。
图9编辑工具栏
4)添加鼠标消息处理函数
添加鼠标消息处理函数OnLButtonDown()、OnMouseMove()、OnLButtonUp(),利用橡皮筋技术实时显示绘制图形,并绘制最终图形,具体源代码参看附录。
添加过程为:
选择View菜单下的ClassWizard菜单项打开类向导,在类列表中选择CLiYuJingView类,在消息列表框中选择WM_LBUTTONDOWN消息并用鼠标左键双击,此时类向导自动在成员函数列表框中添加该消息的处理函数。
然后再用同样方法添加WM_MOUSEMOVE消息和WM_LBUTTONUP消息的处理函数,如图10所示。
图10添加相应代码
3.2界面设计
各控件名称,类型,属性以与相关变量如表2所示。
表2界面控件表
控件名称
控件类型
属性
相关变量
绘图
下拉式菜单
无
无
直线
菜单项工具栏按钮
ID_LINE
intshape
矩形
菜单项工具栏按钮
ID_RECT
intshape
椭圆
菜单项工具栏按钮
ID_ELLIPSE
intshape
线宽
弹出式菜单
无
intw
颜色〔线色〕
菜单项工具栏按钮
ID_COLOR
COLORREFm_nColor
填充色
菜单项工具栏按钮
ID_FILLCOLOR
COLORREFm_fColor
整体界面如图11所示。
图11整体界面显示
3.3关键功能的实现
1)选择要绘制的图形
在直线、矩形以与椭圆的消息处理函数里为shape分别赋值为1,2,3,在OnPaint()函数里添加3个if语句的代码来这实现这三个图形的绘制:
当选择画直线时,shape=1,如此执行绘制直线代码,当选择画矩形时,shape=2,如此执行绘制矩形的代码,当性选择画椭圆时,shape=3,如此执行绘制椭圆的代码。
2)改变线宽
在OnPaint()创建的画笔中,pen.CreatePen(PS_SOLID,w,m_nColor),线宽处用w表示,如此改变w的值即改变了画笔的粗细。
选择菜单绘图→线宽选择划线宽度值,此时所选的线宽值就赋给线宽变量w。
假如不选择线宽值,如此w=1(即默认线宽值为1)。
3)改变线色
在OnPaint()创建的画笔中,pen.CreatePen(PS_SOLID,w,m_nColor),线的颜色处用m_nColor表示,如此改变m_nColor即改变了画笔的颜色。
选择菜单绘图→颜色,会弹出通过WM_COLORREF从系统中引入的颜色选择对话框,选择颜色后,点击确定如此相应颜色值就赋给变量m_nColor,此时画笔的颜色就会发上变化。
假如不选择颜色,如此默认〔线〕颜色为黑色。
4)改变填充色
在OnPaint()创建的画刷中,brush.CreateSolidBrush(m_fColor),颜色就是用m_fColor表示的,改变m_fColor即改变了画刷的颜色。
选择菜单绘图→填充色,会弹出通过WM_COLORREF从系统中引入的颜色选择对话框,选择颜色后,点击确定如此相应颜色值就赋给变量m_fColor,此时画刷的颜色就会发上变化。
假如不选择颜色,如此默认填充色为白色。
5)橡皮筋技术实现鼠标实时绘图
利用橡皮筋技术可以实现在鼠标拖拽作图时,实时显示当前绘图的情况。
这样,我们就要在鼠标移动的消息处理函数中添加相应的代码。
在鼠标左键按下的时候,记录如下图元起始点;在鼠标移动的时候,获取鼠标当前位置,绘制出新的图形,同时,将上一次绘制的图形擦除,这就是橡皮筋技术。
在OnMouseMove()函数中调用SetROP2()函数将绘图模式设置为NOTXORPEN〔同或〕模式,使用同或模式绘图就可以画上真实的图形,并擦除上次绘制的图形。
在OnLButtonDown()函数中调用SetCapture()函数捕捉鼠标,OnLButtonUp()函数中调用ReleaseCapture()函数释放鼠标。
整个绘图过程就是在鼠标左键按下时确定绘图起点,移动鼠标实时显示绘制的图形,鼠标左键弹起即完成图形的绘制的过程。
4.结论与心得体会
这次课设我成功地完成了设计要求,能用鼠标拖动绘制直线段、椭圆、矩形等根本图形;能控制所绘制图形的线宽、线色、填充色等。
经过程序调试,该简单画图程序能够绘制指定线宽、线色、填充色的图形,在鼠标移动的过程中能实时显示当前绘制的图形。
在拿到任务书后,我通过查阅资料,不断编程调试,以与请教同学,最终实现绘图程序的要求。
我学会了鼠标消息的分类,鼠标消息处理函数的常见编程方法,以与捕捉鼠标SetCapture()函数,释放鼠标ReleaseCapture()函数。
同时,利用橡皮筋技术实现鼠标绘图的实时显示是我最大的收获。
我在调试程序时,发现绘制直线时鼠标左键弹起直线并没有绘制完毕,而再次单击鼠标左键,又以上次绘制的直线段终点作为起点绘制直线,即绘制出的直线段是一段连着一段的。
在自己检查数遍并未发现错误之处后,我求助了同学,在OnLButtonDown()函数中添加了一句cpoint=opoint=point0之后问题得以解决。
通过这次课程设计,我学到了很多与计算机绘图相关的根底知识,并进一步体会到面向对象的程序设计的强大,以与Windows应用程序用户界面统一、友好,独立于设备的图形操作特点。
这次的课程设计虽只是做了一个简单的绘图工具,但是也让我从设计者的角度了解了设计一个程序的过程,看似一个很简单的工具,其制作的背后工作是繁琐的。
哪怕是平时我们使用的很顺手的一个小工具,其开发的一切步骤都不可小觑,所以,关于编程还有太多的东西等着我们去了解,学习。
5.思考题
1)说明直线、椭圆、矩形绘制使用的函数,与其参数含义?
答:
直线、椭圆、矩形绘制使用的函数是OnPaint()。
函数里面定义和创建了绘图的画笔pen和填充图形的画刷brush,3种图形本身对应的消息处理函数里分别赋给shape3个不同的值:
1,2,3,在OnPaint()里有3个if语句,用来这实现这三个图形的绘制:
当选择画直线时,shape=1,如此执行绘制直线代码,当选择画矩形时,shape=2,如此执行绘制矩形的代码,当性选择画椭圆时,shape=3,如此执行绘制椭圆的代码。
2)如何控制菜单项的状态,使用的消息类型?
答:
通过添加UPDATE_MAND_UI消息函数,在生成的函数里添加相关代码来控制菜单项的状态与使用的消息类型。
如选择直线时,使shape=1,如此OnUpdateLine里添加pCmdUI->SetCheck(shape==1),那么当shape的值为1时,即代表选择了直线项,此时菜单中的直线选项前就打勾了,代表选中。
矩形和椭圆类似。
3)如何设置菜单和工具栏按钮的快捷键操作?
答:
切换到资源视图,选择Accelerator资源类型,双击IDR_MAINFRAME加速键资源,打开加速键编辑窗口。
在ID下拉列表框中选择相应菜单项的ID,在Key一栏中输入相应键值〔比如L〕,选择Ctrl复选框和VirtKey单项选择按钮,关闭加速键编辑窗口,即可完成加速键设置,如图12所示。
图12快捷键设置
6.附录
6.1调试报告
1)一开始我并没有添加刷新函数Invalidate(),这就使程序运行之后,无论鼠标左键按下时如何移动无法绘图,这是因为当一个窗口键入容其实就是将窗口刷新了,相当于更新了窗口,故必须有刷新函数。
2)在调试程序时,发现绘制直线时鼠标左键弹起直线并没有绘制完毕,而再次单击鼠标左键,又以上次绘制的直线段终点作为起点绘制直线,即绘制出的直线段是一段连着一段的。
在OnLButtonDown()函数中添加了一句cpoint=opoint=point0之后问题得以解决。
这是因为要给初始坐标和终止坐标赋个0值,不然系统无法判断坐标位置。
6.2测试结果
编译、连接、运行程序后,在窗口中绘制不同线宽,不同线色,不同填充色的图形后窗口如图13所示。
图13绘制各个图形
6.3关键源代码
1)在“MainFrm.h〞中,在classCMainFrame:
publicCFrameWnd里的protected下定义:
CToolBarm_drawToolBar;//工具栏
2)在“MainFrm.cpp〞中,在CMainFrame:
:
OnCreate(LPCREATESTRUCTlpCreateStruct)里添加以下代码:
if(!
m_drawToolBar.Create(this)||
!
m_drawToolBar.LoadToolBar(IDR_DRAW))
{TRACE0("Failedtocreatestatusbar\n");
return-1;
}
3)在“LiYuJingView.h〞中,在classCLiYuJingiew:
publicCView里的public下定义相关变量:
CLiYuJingDoc*GetDocument();
COLORREFm_nColor;
COLORREFm_fColor;
CPointcpoint;
CPointopoint;
BOOLm_Down;
intw;
intshape;
HCURSORm_Cursor;//光标资源句柄
4)在“LiYuJingViewView.cpp〞中,添加如下函数与代码:
CLiYuJingView:
:
CLiYuJingView()
{
//TODO:
addconstructioncodehere
w=1;//初始线宽默认为1
shape=0;
m_fColor=RGB(255,255,255);//初始填充色为白色
m_Cursor=AfxGetApp()->LoadStandardCursor(IDC_CROSS);
}
voidCLiYuJingView:
:
OnW5()
{
w=5;//令线宽为5
}voidCLiYuJingView:
:
OnW1()
{
w=1;//令线宽为1
}
voidCLiYuJingView:
:
OnW2()
{
w=2;//令线宽为2
}
voidCLiYuJingView:
:
OnW3()
{
w=3;//令线宽为3
}
voidCLiYuJingView:
:
OnW4()
{
w=4;//令线宽为4
}
voidCLiYuJingView:
:
OnUpdateW1(CCmdUI*pCmdUI)
{
pCmdUI->SetRadio(w==1);//当线宽为1时,此选项前标有圆点
}
voidCLiYuJingView:
:
OnUpdateW2(CCmdUI*pCmdUI)
{
pCmdUI->SetRadio(w==2);//当线宽为2时,此选项前标有圆点
}
voidCLiYuJingView:
:
OnUpdateW3(CCmdUI*pCmdUI)
{
pCmdUI->SetRadio(w==3);//当线宽为3时,此选项前标有圆点
}
voidCLiYuJingView:
:
OnUpdateW4(CCmdUI*pCmdUI)
{
pCmdUI->SetRadio(w==4);
}
voidCLiYuJingView:
:
OnUpdateW5(CCmdUI*pCmdUI)
{
pCmdUI->SetRadio(w==5);
}
voidCLiYuJingView:
:
OnLine()
{
shape=1;//选择直线,如此令shape为1
m_Cursor=AfxGetApp()->LoadStandardCursor(IDC_CROSS);
}
voidCLiYuJingView:
:
OnRect()
{
shape=2;//选择矩形,如此令shape为2
m_Cursor=AfxGetApp()->LoadStandardCursor(IDC_CROSS);
}
voidCLiYuJingView:
:
OnEllipse()
{
shape=3;//选择椭圆,如此令shape为3
m_Cursor=AfxGetApp()->LoadStandardCursor(IDC_CROSS);
}
voidCLiYuJingView:
:
OnUpdateLine(CCmdUI*pCmdUI)
{
pCmdUI->SetCheck(shape==1);//shape为1时,直线选项前打上勾
}
voidCLiYuJingView:
:
OnUpdateRect(CCmdUI*pCmdUI)
{
pCmdUI->SetCheck(shape==2);//shape为2时,矩形选项前打上勾
}
voidCLiYuJingView:
:
OnUpdateEllipse(CCmdUI*pCmdUI)
{
pCmdUI->SetCheck(shape==3);//shape为3时,椭圆选项前打上勾
}
voidCLiYuJingView:
:
OnColor()
{
CColorDialogColor;//创建颜色对话框
if(Color.DoModal()==IDOK)//如果用户点击OK按钮
m_nColor=Color.GetColor();//更改颜色,把颜色赋到m_nColor
}
voidCLiYuJingView:
:
OnFillcolor()
{
CColorDialogFullColor;//创建颜色对话框
if(FullColor.DoModal()==IDOK)//如果用户点击OK按钮
m_fColor=FullColor.GetColor();//更改颜色,把颜色赋到m_fColor
}
voidCLiYuJingView:
:
OnPaint()
{
CPaintDCdc(this);//devicecontextforpainting
CPenpen;//定义画笔
CBrushbrush;//定义画刷
pen.CreatePen(PS_SOLID,w,m_nColor);//创建画笔
brush.CreateSolidBrush(m_fColor);//创建画刷
dc.SelectObject(&pen);//获取画笔
dc.SelectObject(&brush);//获取画刷
if(shape==1)
{dc.MoveTo(opoint.x,opoint.y);
dc.LineTo(cpoint.x,cpoint.y);}//绘制直线,从opoint到cpoint连线
if(shape==2)
dc.Rectangle(opoint.x,opoint.y,cpoint.x,cpoint.y);//绘制矩形
if(shape==3)
dc.Ellipse(opoint.x,opoint.y,cpoint.x,cpoint.y);//绘制椭圆
}
voidCLiYuJingView:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
m_Down=TRUE;//鼠标按下
SetCapture();//获取坐标
cpoint=opoint=point;//把鼠标所在坐标赋给起点坐标opoint
ReleaseCapture();//释放坐标
CView:
:
OnLButtonDown(nFlags,point);
}
voidCLiYuJingView:
:
OnMouseMove(UINTnFlags,CPointpoint)
{
if(m_Down)//如果鼠标按下
SetCursor(m_Cursor);//设置使用光标资源
CClientDCdc(this);//构造设备环境对象
CPennewpen;//新画笔
CPen*oldpen;//老画笔
CBrushnewbrush;//新画刷
CBrush*oldbrush;//老画刷
//创建指定宽度和线色的画笔
newpen.CreatePen(PS_SOLID,w,m_nColor);
newbrush.CreateSolidBrush(m_fColor);//创建指定颜色的画刷
oldpen=dc.SelectObject(&newpen);//将创建的画笔选入设备环境
oldbrush=dc.SelectObject(&newbrush);//将创建的画刷选入设备环境
dc.SetROP2(R2_NOTXORPEN);//设置同或绘图模式
//判断鼠标移动的同时鼠标左键按下,并且要绘制的是直线段
if(m_Down&&shape==1)
{
//重新绘制前一个鼠标移动消息处理函数绘制的直线段
//因为绘图模式的原因,结果是擦除了该线段
dc.MoveTo(opoint);
dc.LineTo(cpoint);
//绘制新的直线段
cpoint=point;//保存新的终止点
dc.MoveTo(opoint);
dc.LineTo(point);
}
//判断鼠标移动的同时鼠标左键按下,并且要绘制的是椭圆
if(m_Down&&shape==2)
{dc.Rectangle(opoint.x,opoint.y,cpoint.x,cpoint.y);
//绘制新的矩形
dc.Rectangle(opoint.x,opoint.y,point.x,point.y);
cpoint=point;//保存新的终止点
}
//判断鼠标移动的同时鼠标左键按下,并且要绘制的是矩形
if(m_Down&&shape==3)
{
dc.Ellipse(opoint.x,opoint.y,cpoint.x,cpoint.y);
dc.Ellipse(opoint.x,opoint.y,point.x,point.y);
cpoint=point;//保存新的终止点
}
newbrush.DeleteObject();//删除新画笔
dc.SelectObject(oldpen);//恢复原有画笔
newbrush.DeleteObject();//删除新画刷
dc.SelectObject(oldbrush);//恢复原有画刷
CView:
:
OnMouseMove(nFlags,point);
}
voidCLiYuJingView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
m_Down=FALSE;//鼠标不按下,即弹起
Invalidate(0);//刷新
CView:
:
OnLButtonUp(nFlags,point);
}