基于MFC的简单画图程序实验doc.docx
《基于MFC的简单画图程序实验doc.docx》由会员分享,可在线阅读,更多相关《基于MFC的简单画图程序实验doc.docx(19页珍藏版)》请在冰豆网上搜索。
基于MFC的简单画图程序实验doc
简单画图程序
【实验目的】
本实验目的是通过构建基于MFC的windows画图程序,使学生:
(1)理解MFC应用程序的运行机制
(2)掌握使用MFC构建Windows应用程序的基本结构及编程的基本方法
(3)理解和掌握MFC应用程序消息处理机制及应用
(4)掌握类向导(ClassWizard)的使用
【实验要求】
(1)必须做好实验原理的预习。
(2)需要对提供的程序代码进行分析,并明确实验时还应在何处添加哪些语句。
【实验环境】
MicrosoftWindowsXP
MicrosoftVisualC++6.0
1基本功能描述
1)在单文档菜单中,在菜单行中可插入一个菜单项,命名为绘图,在下拉菜单中可分别设置绘制的图形形状,如直线、矩形及椭圆,线宽选项,有1-5可供选择,还可以设置线色以及填充色,通过弹出的颜色对话框选择需要的颜色,如果不选择线宽、线色以及填充色,则按默认的画笔,画刷来绘制选择的图形。
2)选择好图形后,通过鼠标可以绘制出相应的直线,矩形或椭圆,鼠标的按下确定图形的起点,鼠标的拖动则确定了图形的终点,即通过鼠标的拖动来决定图形的大小,当鼠标弹起,此图形则绘制完毕。
3)增添工具栏,设置绘制的图形形状,线色以及填充色,可更方便地选择相应的功能。
2设计思路
1)对需要用到的变量进行初始化。
2)选择相应的图形之后就响应相应的消息处理函数,给shape赋对应的值。
选择不同的线宽,线色与填充色,即可改变画笔或画刷的属性。
3)鼠标的按下响应函数OnLButtonDown(),捕捉鼠标当前位置得到起点的坐标,鼠标的拖动响函数OnMouseMove()改变终点的坐标,鼠标的弹起响应OnLButtonUp(),确定终点坐标,刷新,得到绘制图形。
4)选择图形或其它属性,可进行下一次绘制。
图1程序流程图
3软件设计
3.1设计步骤
1)创建单文档
创建一个MFCAppWizard[exe]工程,命名为“yinshuyan”,如图2所示,并创建单文档,如图3所示。
创建成功后,系统自动生成相应的类,如图4所示。
图2创建工程
图3创建单文档
图4生成类
2)编辑菜单
添加需要的菜单项,如图5所示(可以通过拖动调整菜单的顺序);并在菜单的属性中设定好所对应的ID,如图6所示,各项菜单对应的ID如表1所示(其中线宽菜单为弹出菜单,只需在菜单项目属性中的弹出选项前打勾即可,分隔线亦只需在菜单项目属性中选中分隔符(Separator)选项即可)。
图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
建立类向导,在视图类CyinshuyanView(通过菜单View->ClassWizard,或者快捷键Ctrl+w打开)中,对各菜单项添加对应的COMMAND消息处理函数,部分菜单项还添加对应的UPDATE_COMMAND_UI消息函数,如图7所示。
图7建立类向导【注意:
此图有误,Classname的下拉框中,
应选择“CyinshuyanView”而非此图显示的“CMainFrame”】
上述操作完成后,可以发现在ClassCMainFrame中自动增加了类似OnLine()之类的许多函数,并且在源文件MainFrm.cpp中,自动添加了相应的消息映射。
BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_COMMAND(ID_LINE,OnLine)
……
END_MESSAGE_MAP()
3)创建工具栏
在插入处选择资源(菜单Insert->Resource,或者快捷键Ctrl+R),新建工具栏,如图8所示;
图8新建工具栏
在工具栏上添加相应的按钮,在属性处更改其ID,如图9所示。
图9编辑工具栏
4)在相应消息函数处添加代码,实现其功能
建立类向导,在视图类CyinshuyanView中,添加WM_PAINT消息,以及WM_LBUTTONDOWN、WM_LBUTTONUP、WM_MOUSEMOVE消息,并在其中添加相应的代码,如图10所示。
图10添加WM_PAINT消息
3.2界面设计
各控件名称,类型,属性及相关变量如表2所示。
表2界面控件表
控件名称
控件类型
属性
相关变量
绘图
下拉式菜单
无
无
直线
菜单项
工具栏按钮
ID_LINE
intshape
矩形
菜单项
工具栏按钮
ID_RECT
intshape
椭圆
菜单项
工具栏按钮
ID_ELLIPSE
intshape
线宽
弹出式菜单
无
intw
颜色(线色)
菜单项
工具栏按钮
ID_COLOR
COLORREFm_nColor
填充色
菜单项
工具栏按钮
ID_FILLCOLOR
COLORREFm_fColor
3.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)在“YinshuyanView.h”中,在classCYinshuyanView:
publicCView里的public下定义相关变量:
COLORREFm_nColor;
COLORREFm_fColor;
CPointcpoint;
CPointopoint;
BOOLm_Down;
intw;
intshape;
4)在“YinshuyanView.cpp”中,添加如下函数及代码:
CYinshuyanView:
:
CYinshuyanView()
{w=1;//初始线宽默认为1
shape=0;
}
voidCYinshuyanView:
:
OnW1()
{
w=1;//令线宽为1
}
voidCYinshuyanView:
:
OnW2()
{
w=2;//令线宽为2
}
voidCYinshuyan:
:
OnW3()
{
w=3;//令线宽为3
}
voidCYinshuyanView:
:
OnW4()
{
w=4;//令线宽为4
}
voidCYinshuyanView:
:
OnW5()
{
w=5;//令线宽为5
}
voidCYinshuyanView:
:
OnUpdateW1(CCmdUI*pCmdUI)
{
pCmdUI->SetRadio(w==1);//当线宽为1时,此选项前标有圆点
}
voidCYinshuyanView:
:
OnUpdateW2(CCmdUI*pCmdUI)
{
pCmdUI->SetRadio(w==2);//当线宽为2时,此选项前标有圆点
}
voidCYinshuyanView:
:
OnUpdateW3(CCmdUI*pCmdUI)
{
pCmdUI->SetRadio(w==3);//当线宽为3时,此选项前标有圆点
}
voidCYinshuyanView:
:
OnUpdateW4(CCmdUI*pCmdUI)
{
pCmdUI->SetRadio(w==4);
}
voidCYinshuyanView:
:
OnUpdateW5(CCmdUI*pCmdUI)
{
pCmdUI->SetRadio(w==5);
}
voidCYinshuyanView:
:
OnLine()
{
shape=1;//选择直线,则令shape为1
}
voidCYinshuyanView:
:
OnRect()
{
shape=2;//选择矩形,则令shape为2
}
voidCYinshuyanView:
:
OnEllipse()
{
shape=3;//选择椭圆,则令shape为3
}
voidCYinshuyanView:
:
OnUpdateLine(CCmdUI*pCmdUI)
{
pCmdUI->SetCheck(shape==1);//shape为1时,直线选项前打上勾
}
voidCYinshuyanView:
:
OnUpdateRect(CCmdUI*pCmdUI)
{
pCmdUI->SetCheck(shape==2);//shape为2时,矩形选项前打上勾
}
voidCYinshuyanView:
:
OnUpdateEllipse(CCmdUI*pCmdUI)
{
pCmdUI->SetCheck(shape==3);//shape为3时,椭圆选项前打上勾
}
voidCYinshuyanView:
:
OnColor()
{
CColorDialogColor;//创建颜色对话框
if(Color.DoModal()==IDOK)//如果用户点击OK按钮
m_nColor=Color.GetColor();//更改颜色,把颜色赋到m_nColor
}
voidCYinshuyanView:
:
OnFillColor()
{
CColorDialogFillColor;//创建颜色对话框
if(FillColor.DoModal()==IDOK)//如果用户点击OK按钮
m_fColor=FillColor.GetColor();//更改颜色,把颜色赋到m_fColor
}
voidCYinshuyanView:
:
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);//绘制椭圆
}
voidCYinshuyanView:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
m_Down=TRUE;//鼠标按下
SetCapture();//获取坐标
opoint=point;//把鼠标所在坐标赋给起点坐标opoint
ReleaseCapture();//释放坐标
CView:
:
OnLButtonDown(nFlags,point);
}
voidCYinshuyanView:
:
OnMouseMove(UINTnFlags,CPointpoint)
{
if(m_Down)//如果鼠标按下
cpoint=point;//把鼠标所在点坐标赋给终点坐标cpoint
CView:
:
OnMouseMove(nFlags,point);
}
voidCYinshuyanView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
m_Down=FALSE;//鼠标不按下,即弹起
Invalidate(0);//刷新
CView:
:
OnLButtonUp(nFlags,point);
}
3.4关键功能实现
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)绘制图形
鼠标左键按下,则捕获鼠标此时的位置坐标为画图的起点,此时在OnLButtonDown()函数里,将捕获的坐标值赋给定义作为起点的变量opoint;按下鼠标左键拖动鼠标时,捕捉鼠标当前位置坐标值为终点坐标值,此时在OnMouseMove()函数里,把捕获的坐标值赋给定义作为终点的变量cpoint,OnPaint()中绘图的代码中的坐标都得到了,进行绘图;鼠标左键弹起时,此时绘图结束,鼠标弹起时所在位置就是画图的最终终点位置,画图结束后,刷新窗口,以便重新画图,此时执行的是OnLButtonUp()函数。
这次实验中关键就是确定画图起点及终点坐标,因为是用鼠标绘制图形,所以需用函数来捕获鼠标当前所在位置的坐标,因此设置了OnLButtonDown()函数来捕获起点坐标,OnMouseMove()函数来捕获鼠标移动是的当前位置坐标,OnLButtonUp()函数来捕获终点坐标。
而绘制图形使用的函数是OnPaint(),将图形的起点和终点坐标和鼠标的位置坐标相联系后就能用鼠标来绘制图形了,所以在它们之间用opoint和cpoint两变量实现链接。
另外将绘图语句集中在OnPaint()函数中,然后其他函数来调用OnPaint()函数,这样不容易引起混乱,同时程序更简单,更有条理,便于修改。
4.思考题
1)说明直线、椭圆、矩形绘制使用的函数,及其参数含义?
答:
直线、椭圆、矩形绘制使用的函数是OnPaint()。
函数里面定义和创建了绘图的画笔pen和填充图形的画刷brush,3种图形本身对应的消息处理函数里分别赋给shape3个不同的值:
1,2,3,在OnPaint()里有3个if语句,用来这实现这三个图形的绘制:
当选择画直线时,shape=1,则执行绘制直线代码,当选择画矩形时,shape=2,则执行绘制矩形的代码,当性选择画椭圆时,shape=3,则执行绘制椭圆的代码。
2)如何控制菜单项的状态,使用的消息类型?
答:
通过添加UPDATE_COMMAND_UI消息函数,在生成的函数里添加相关代码来控制菜单项的状态及使用的消息类型。
如选择直线时,使shape=1,则OnUpdateLine里添加pCmdUI->SetCheck(shape==1),那么当shape的值为1时,即代表选择了直线项,此时菜单中的直线选项前就打勾了,代表选中。
矩形和椭圆类似。
3)如何设置菜单和工具栏按钮的快捷键操作?
答:
在资源视图下选择Accelerator,双击IDR_MAINFRAME,打开编辑窗口,双击空白处,在ID下拉列表框中选择需要快捷键的菜单项或工具栏按钮的ID,在键一栏中输入快捷键,选择Ctrl复选框和虚拟键单选按钮即可,如图11所示。
图11快捷键的创建
5.附录
5.1易出错的问题
1)一开始没有添加刷新函数Invalidate(),这就使程序运行之后,无论鼠标左键按下时如何移动无法绘图,这是因为当一个窗口内键入内容其实就是将窗口刷新了,相当于更新了窗口,故必须有刷新函数,这和生活中的白纸写字不一样。
2)当添加Invalidate()后,把Invalidate()放在OnMouseMove()里,但是这样只能在窗口内画一个图形,即每画完一个图形就刷新一次。
将Invalidate()改为了Invalidate(0),这时是可绘制多个图形,但鼠标每移动一个位置都进行一次刷新,绘图结束后,绘图过程中的所有痕迹都在,产生了很多拖动的影子。
将Invalidate(0)放在了OnLButtonUp()中,那么每次重绘,上次的图形会作为背景被保留下来,而不会被刷新掉。
5.2测试结果
1)点击链接,编译,运行后的窗口如图12所示。
图12运行结果
2)改变绘制图形形状,颜色,线宽,填充色之后绘制的图形如图13所示。
图13改便各项属性厚后的图形