VC++课程设计.docx
- 文档编号:14956573
- 上传时间:2023-06-28
- 格式:DOCX
- 页数:15
- 大小:24.48KB
VC++课程设计.docx
《VC++课程设计.docx》由会员分享,可在线阅读,更多相关《VC++课程设计.docx(15页珍藏版)》请在冰点文库上搜索。
VC++课程设计
Vc++简单的画图软件的制作
1.工程的新建
打开MicrosoftVisualC++6.0—>点击File—>New在Projects中选择MFCAppWizard(exe);在Projectname中输入工程的名字Graphic,在Location中选择工程存放的路径。
填完后点击OK按钮。
(如图1)填完后点击OK按钮,弹出对话框(如图2)。
在弹出来的对话框中我们可以选择生成三种不同类型的应用程序:
单文档、多文档、对话框。
单文档程序如记事本,在一个应用程序中只能对一个文档进行操作,降低了编程的复杂度并减少了运行程序时所需的资源。
对某些小型应用(比如文本编辑器或小型图像编辑器)可以采用这种类型的窗口应用程序。
多文档程序如PhotoShop,在一个应用程序中可以同时对多个文档进行操作;对话框程序如QQ,应用程序的界面是对话框形式的。
现对话框版本的程序更小一些。
除了节省资源外,对话框版本的应用程序的加载速度也更快些。
基于对话框的应用程序比完成相同功能的基于窗口的应用程序更简单有效。
这里我们选第一个:
单文档。
选择完后点击Next,设置默认,最后点击Finish完成工程的创建。
1.1添加消息响应函数
系统为我们生成了一个程序的框架,但是这个框架完成不了什么具体的功能。
为了使程序程序完成我们想要做的事,我们要向这个框架中加入一些代码。
VC++程序的运行并不像C语言是按照顺序运行下来的。
每当我们完成一个事件,系统就会发出特定的消息,程序就会跳到相应的消息响应函数中执行里面的代码。
单击菜单中的View->ClassWizard(或按快捷键Ctrl+W),将会弹出MFCClassWizard对话框。
在ClassName中选择CView,在Messages中选择WM_LBUTTONDBLCLK,点击右边的AddFunction按键。
这样我们就为程序添加了鼠标左键双击的消息响应函数,函数名为OnLButtonDblClk(UINTnFlags,CPointpoint)。
我们点击EditCode按键就可以进入消息响应函数中。
我们在消息响应函数中添加如下代码:
AfxMessageBox(“HelloWord!
”);运行程序!
当我们在客户区中双击鼠标左键时,我们可以看到效果(如图5)我们在完成双击鼠标左键这个事件后,Windows便。
会发出WM_LBUTTONDBLCLK这条消息。
我们的程序收到这个消息后,就会跳转到鼠标左键双击的消息响应函数内,执行里面的代码。
同样的,我们可以添加其他的消息响应函数,如鼠标左键按下,抬起,鼠标移动等(WM_LBUTTONUP、WM_LBUTTONDOWN、WM_MOUSEMOVE等)。
我们程序就是在这样的消息响应机制下运行的。
1.2资源视图管理器
在ResoureView里,我们可以编辑对话框、菜单、工具条、快捷键等资源。
点开Menu,可以看到一个ID为IDR_MAINFRAME的菜单。
ID是一个标识,实际上是一个无符号整型常量,每一个资源在程序中都有一个唯一的ID号。
双击IDR_MAINFRAME,在右边的视图中双击帮助右边的虚线框,弹出菜单属性,Caption在中输入“画图”,并将其关闭。
双击画图菜单下面出现虚线框,在caption中输入“画线”后将其关闭。
双击画线,在弹出的菜单属性中ID栏的ID_MENUITEM32775改成ID_MENUITEM_LINE。
同样方法在建一个“画圆”菜单项。
注意:
每个资源对应一个ID号,ID号的命名全部用大写字母,且要符合匈牙利命名法。
我们为新的菜单项起名,如果我们选择了Pop-up,生成的菜单就还有下级子菜单;如果没有选择,菜单就没有下级菜单。
我们同样可以在ClassWizard中为我们生成的菜单添加响应。
在ClassWizard中的ObjectIDs中选中菜单的ID号,Messages中选择COMMOND,然后点击AddFunction。
这样,我们就为新建的菜单添加了点击的响应,我们同样可以点击EditCode编辑消息响应函数。
1.3设备环境
CDC是设备环境类的基类直接由CObject派生。
是GDI的关键元素,它代表了物理设备。
每一个C++设备环境对象都有相对应Windows设备环境,并通过一个32位类型的HDC句柄来标识。
CDC类的虚拟性使我们可以很容易的做到编写同时适用于多种设备的代码。
使用CDC类可以使我们的作图不用关心设备的问题。
CClientDC和CWindowDC是显示设备环境类,都是由CDC派生而来,区别在于CClientDC是窗口的客户区不包括边框、标题栏和菜单栏,(0,指客户区域的左上角。
0)CWindowDC的(0,0)指整个屏幕的左上角,这意味着我们可以在显示器的任意地方绘图,包括窗口边框、标题栏和菜单栏等等。
CWindowDC一般应用在框架窗口,而不是视图窗口。
CDC对象被创建后一定要在合适的时候将它删除掉,如果忘记了删除设备环境对象则会造成内存丢失。
在每次绘图前,我们要获取设备环境,我们可以使用CDC*GetDC()函数来获取设备环境。
在绘图完成后,使用voidReleaseDC(CDC*pDC)函数释放设备环境。
2.简易画图板的制作
2.1设计目的
设计一个单文档类型的MFCAppWizard(exe)工程,工程取名为:
Graphic。
此程序将实现简单的绘图功能,包括点、直线、矩形、椭圆、扇形和连续线的绘制。
并且能实现绘图的控制,包括线宽、线型和颜色的设置,图形的保存和打开以及笔刷的使用。
2.2总体设计
首先,新建一个单文档类型的MFCAppWizard(exe)工程,工程取名为:
Graphic。
为此程序添加一个子菜单,菜单名称为“绘图”,并为其添加六个菜单项,分别用来控制不同图形的绘制。
当用户选择其中的一个菜单项后,程序将按照当前的选择进行相应图形的绘制。
添加的六个菜单项的ID及名称如表1所示。
然后分别为这六个菜单项添加命令响应,本程序让视类(CGraphicView)对这些菜单命令进行响应,
在程序运行以后,当用户单击某个菜单项时,应该把用户的选择保存起来,以便随后的绘图操作使用。
因此在CGraphicView类中添加一个私有变量m_nDrawType;用来保存用户的选择,该变量的定义如下所述:
private:
UINTm_nDrawType;接着,在视类的构造函数中将此变量初始化为0,程序代码如下:
CGraphicView:
:
CGraphicView(){//TODO:
addconstructioncodeherem_nDrawType=0;}利用switch/case语句,来分别完成相应图形的绘制。
当用户选择【绘图】菜单下的不同子菜单项时,将变量m_nDrawType设置为不同的值。
程序代码如下:
voidCGraphicView:
:
OnDot(){//TODO:
Addyourcommandhandlercodeherem_nDrawType=1;}voidCGraphicView:
:
OnLine(){//TODO:
Addyourcommandhandlercodeherem_nDrawType=2;}voidCGraphicView:
:
OnRectangle(){//TODO:
Addyourcommandhandlercodeherem_nDrawType=3;
}voidCGraphicView:
:
OnEllipse(){//TODO:
Addyourcommandhandlercodeherem_nDrawType=4;}voidCGraphicView:
:
OnShanxing(){//TODO:
Addyourcommandhandlercodeherem_nDrawType=5;}voidCGraphicView:
:
OnLianxuxian(){//TODO:
Addyourcommandhandlercodeherem_nDrawType=6;}
2.3点、直线、矩形、椭圆的绘制
对于直线、矩形和椭圆,在绘制时都可有两点来确定其图形。
当鼠标左击时得到一个点,当鼠标左键松开时得到另外一个点。
为视类CGraphicView分别捕获鼠标左键按下和弹起这两个消息。
另外当鼠标左键按下时,需要将鼠标当前按下点保存,因此我们为CGraphicView再增加一个CPoint类型的私有成员变量:
m_ptOrigin,在视类的构造函数中将此变量初始化为0。
在鼠标按下消息响应函数中,保存该点,代码如下:
voidCGraphicView:
:
OnLButtonDown(UINTnFlags,CPointpoint){//TODO:
Addyourmessagehandlercodehereand/orcalldefaultm_ptOrigin=point;}在鼠标左键弹起消息响应函数中实现绘图,代码如下:
voidCGraphicView:
:
OnLButtonUp(UINTnFlags,CPointpoint){//保存鼠标按下得到点,也是绘制一个点CView:
:
OnLButtonDown(nFlags,point);
//TODO:
Addyourmessagehandlercodehereand/orcalldefault//创建并获得设备描述CClientDCdc(this);switch(m_nDrawType){case1:
dc.SetPixel(point,RGB(255,0,0));/*绘制点*/break;case2:
dc.MoveTo(m_ptOrigin);/*调用MoveTo函数移动到原点*/dc.LineTo(point);/*调用LineTo函数绘制到终点。
*/break;case3:
break;case4:
break;CView:
:
OnLButtonUp(nFlags,point);}在上述程序中,设置一个点,用到的函数是SetPixel,这也是CDC类的一个成员方法,该函数的生命形式如下:
COLORREFSetPixel(POINTpoint,COLORREF;该函数是在指定的点设置一个像素。
其中第一个参数(point)是指定的crColor)点,第二个参数(crColor)是指定的颜色。
在程序中设定的颜色在系统颜色表中可能不存在,但系统会选择一种和这个颜色最接近的颜色。
RGB是一个宏,它有三个参数,分别代表红、蓝三种颜色的值。
绿、这三个参数BYTE类型,取值范围为0~255。
RGB(0,0,0)是黑色,RGB(255,255,255)是白色,将这三个分量设置成为0~255之间的任意值,从而得到各种不同的颜色。
这里的RGB(255,0,0)是红色。
绘制直线时,首先调用MoveTo函数移动到原点,然后调用LineTo函数绘制到终点。
绘制矩形时使用Rectangle函数,该函数声明形式为:
BOOLRectangle(LPCRECTlpRect);该函数有一个指向Crect对象的参数,后者可以利用两个点来构造。
需要注意的是而上述代码中传递的却是Crect对象,但运该函数需要的是指向Crect对象的指针,
dc.Rectangle(CRect(m_ptOrigin,point));
dc.Ellipse(CRect(m_ptOrigin,point));
行编译时也能成功通过,运行时也不会报错,这是为什么呢?
我们知道C系列的语言都是强类型语言,如果类型不匹配的话,需要进行强制类型转换。
但这里为什么没有进行这样的强制类型转换程序也可以通过呢?
实际上,Crect类提供了这样一个成员函数:
重载LPCRECT操作符,其作用是将Crect转换为LPCRECT类型。
因此,当在程序中给Rectangle函数的参数赋值时,如果它发现该参数是一个Crect对象,它就会隐式地调用LPCRECT操作符,将Crect类型的对象转换为LPRECT类型。
因此,在给函数传递参数时,如果我们看到的传递的数值类型和所需要的类型不匹配,但编译和运行都正确的情况时,就要想想这其中的缘由了。
当然,有的情况下可能是这些类型之间本来就可以互相转换,例如short类型和int类型。
但是参数是对象类的话,就要考虑了,它选择的对象的构造方法进行的隐式转换,还是有其他重载的操作符。
当用户选择椭圆菜单项时,调用Ellipes函数绘制一个椭圆。
2.4连续线和扇形的绘制
Windows系统为我们提供了一个画图程序,在该程序中,利用画笔可以绘制连续的线条,下面我们设计绘制连续线和扇形。
为了绘制连续的线条,首先要得到线条的起点,这在前面已经实现。
然后需要捕获鼠标移动过程中的每一个点,这可以通过捕获鼠标移动消息(WM_MOUSEMOVE)来实现。
在此消息响应函数中,在依次捕获的各个点之间绘制一条条非常短的线段,从而就可以绘制出一条连续的线条。
遵照这一思路,我们开始增加程序的功能。
首先为视类增加鼠标移动消息(WM_MOUSEMOVE)的响应函数(OnMouseMove)。
这样,只要鼠标在应用程序窗口中移动时都会进入到这个消息响应函数中。
但这并不是我们所期望的,我们希望在鼠标左键按下后开始绘图。
因此,我们需要有一个变量来表示鼠标左键是否按下这一状态,然后在鼠标移动消息响应函数中对这一变量进行判断。
当此变量为真,即鼠标左键已经按下去,我们开始绘图。
于是,为视类添加一个BOOL型的私有变量m_bDraw,当鼠标左键按下去时,此变量为真;当鼠标左键弹起时,此变量为假,这时,我们就不再绘制线条了。
该变量在视类头文件中的定义代码如下:
Private:
BOOLm_bDraw;接下来在视类的构造函数中,将此变量初始化为FALSE。
m_bdraw=FALSE;当鼠标左键按下去时,在视类的OnLButtonDown函数中将此变量初始化为
TRUE。
m_bdraw=TRUE;当鼠标左键弹起时,在视类的OnLButton函数中将此变量初始化为假。
m_bdraw=FALSE;然后在OnMouseMove函数中首先对m_bdraw变量进行判断,如果其值为真,说明鼠标左键已经按下去了,这时就可开始进行画线操作。
还有一点需要注意,因为每绘制一条线段后,下次应该从这条线段的终点开始继续绘制。
因此,绘制完当前线段后,应该修改线段的起点,将当前线段的终点作为下一条线段的起点,程序代码如下:
voidCGraphicView:
:
OnMouseMove(UINTnFlags,CPointpoint){//TODO:
Addyourmessagehandlercodehereand/orcalldefault{//创建并获得设备描述CClientDCdc(this);//创建宽度为1的实线红色画笔CPenpen(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);}如果在上面绘制连续线条的程序中,保持每段小直线的起点不变,即以鼠标左键按下时的起点为起点不变,分别绘制到鼠标移动点的直线,这时就会出现扇形的效果。
也就是去掉上述代码OnMouseMove函数中修改线段起点的代码。
程序代码如下:
voidCGraphicView:
:
OnMouseMove(UINTnFlags,CPointpoint){//TODO:
Addyourmessagehandlercodehereand/orcalldefault{//创建并获得设备描述CClientDCdc(this);//创建宽度为1的实线红色画笔CPenpen(PS_SOLID,1,RGB(255,0,0));//把创建的画笔选入设备描述CPen*pOldpen=dc.SelectObject(&pen);if(m_bDraw==true){dc.MoveTo(m_ptOrigin);dc.LineTo(point);}//恢复设备描述dc.SelectObject(pOldpen);CView:
:
OnMouseMove(nFlags,point);}
2.5画刷
再为此程序添加一个子菜单,菜单名称为“画刷”,并为其添加三个菜单项,分别用来控制不同的画刷。
MFC提供了一个CBrush类,可以用来创建画刷对象。
画刷通常用来填充一块区域。
简单画刷、位图画刷、透明画刷,程序代码如下:
voidCDrawView:
:
OnLButtonUp(UINTnFlags,CPointpoint){//创建一个红色画刷CBrushbrush(RGB(255,0,0));//创建并获得设备描述表CClientDCdc(this);//利用红色画刷填充鼠标拖曳过程中形成的矩形区域dc.FillRect(CRect(m_ptOrigin,point),&brush);//创建位图对象CBitmapbitmap;//加载位图资源bitmap.LoadBitmap(IDB_BITMAP1);//创建位图画刷CBrushbrush(&bitmap);//创建并获得设备描述表CClientDCdc(this);//利用红色画刷填充鼠标拖曳过程中形成的矩形区域dc.FillRect(CRect(m_ptOrigin,point),&brush);//创建并获得设备描述表CClientDCdc(this);//创建一个空画刷CBrush//将空画刷选入设备描述表CBrush*pOldBrush=dc.SelectObject(pBrush);//绘制一个矩形dc.Rectangle(CRect(m_ptOrigin,point));//恢复先前的画刷dc.SelectObject(pOldBrush);m_bDraw=FALSE;CView:
:
OnLButtonUp(nFlags,point);}在简单画刷程序中,首先创建一个红色画刷;接着创建设备描述表对象;然后调用设备描述表对象的成员函数FillRect,利用指定的画刷填充一块指定的矩形区域,而鼠标拖动过程中的起点和终点就决定了需要填充的矩形区域,因此,代码中通过CRect类利用鼠标拖动的起点和终点构造了这快矩形区域。
CRect类提供了多个构造函数,这里使用的是下面这种构造函数,即通过指定矩形区域的左上角和右下角这两个点来构造一块矩形区域。
CRect(POINTtopLeft,POINTbottomRight);代码中的CDC类的成员函数FillRect,该函数的功能是用指定的画刷填充一个
*pBrush
CBrush:
:
FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));矩形。
该函数将填充全部的矩形,包括上左边界,但不填充右底边界。
FillRect函数的声明如下:
voidFillRect(LPCRECTlpRect,CBrush*pBrush);该函数有两个参数,lpRect是指向一个RECT结构体或CRect对象的指针,该结构体或对象中包含了要填充的矩形的逻辑坐标。
pBrush是指向用于填充矩形的画刷对象的指针。
在位图画刷程序中,CBrush类有下面这样一种构造函数。
CBrush(CBitmap*pBitmap);该构造函数要求一个CBitmap类型的指针,CBitmap类是位图类,于是我们就会这样想:
利用这个构造函数是否就可以创建一个位图画刷呢?
事实确实如此。
创建CBitmap对象时,仅调用其构造函数并不能得到一个有用的位图对象,还需要调用一个初始化函数来初始化这个位图对象。
CBitmap类提供了多个初始化函数,例如,LoadBitmap、CreateBitmap、BitmapIndirect等。
这里用LoadBitmap函数来加载一副位图,该函数的声明如下:
BOOLLoadBitmap(LPCTSTRlpszResourceName);BOOLLoadBitmap(UINTnIDResource);其中第二种声明需要一个资源ID作为参数。
首先给程序增加一个位图资源。
为一个工程创建资源有多种实现方法,其中一种方法可以利用【Insert】菜单下的【Resource…】命令,在弹出的对话框中选择Bitmap资源类型,单击【New】按钮,即可创建一个默认名称为IDB_BITMAP1的位图资源,并在VC++集成开发环境右边的代码编辑区中打开位图编辑器。
可以利用编辑器右边的调色板和绘图工具来编辑位图资源,还可以通过拉伸位图编辑器中网格周围的蓝色方点来调整位图的大小。
在透明画刷程序中,我们利用GetStockObject这个函数来获取一个黑色或白色的画刷句柄。
这个函数是否能够获得一个透明画刷句柄呢?
从MSND提供的帮助信息中,可以看到该函数的参数取值之一可以是NULL_BRUSH,以获取一个空画刷。
那么,这个空画刷是否就是我们所需要的透明画刷呢?
结论是正确的。
但这时存在一个问题,我们获取的是句柄,而在进行绘制操作时需要的是一个画刷对象。
如何从画刷句柄转换为画刷对象呢?
CBrush类提供了一个FromHandle函数来实现这样的功能。
该函数的声明如下:
StaticCDC*PASCALFromHandle(HDChDC);
5.部分源代码
voidCMyPaintView:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
this->SetCapture();//捕获鼠标
HCURSORcross=LoadCursor(NULL,IDC_CROSS);
SetCursor(cross);
m_bDrawing=true;//开始画图
m_ptPrev=point;
m
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VC 课程设计