版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
试验三
面向对象程序设计实验——一个简单的可复用时钟控件1精选课件本实验的开发环境使用C++语言实现使用VC++6.0集成开发环境开发使用MFC应用程序开发框架2精选课件MFC版本简介MFC全称MicrosoftFoundationClasses.1989年微软公司成立ApplicationFramework技术团队,开发C++面向对象工具给Windows应用程序开发人员使用。这个小组即AFX小组,就是他们,开始了MFC的开发历程。微软公司于1992年4月推出C/C++7.0产品时,初次向世人介绍了MFC1.0,其32位版本也在1992年7月随着Win32SDK推出。VisualC++1.0(也就是C/C++8.0)搭配MFC2.0于1993年3月推出。同年8月推出在WindowsNT上的VisualC++1.1forWindowsNT,搭配的是MFC2.1。3精选课件微软在1993年12月又推出了16为的VisualC++1.5,搭配的是MFC2.5。1994年9月,微软推出VisualC++2.0,搭配MFC3.0。1995年1月,微软推在增加了MAPI和WinSock支持的基础上,推出MFC3.1。1995年7月,MFC有了3.2版,这是一个小的改版。然后就是1995年9月的32位版MFC4.0。这个版本有了相当大的改进。1996年上半年又有了MFC4.1……时至今日MFC在VisualC++7.0中已经到了7.0版本。我们常用的VisualC++6.0使用的是MFC4.2版本。微软正不断地为“为什么要使用MFC”加上各式各样地强烈你有,并强烈导引它成为Windows程序设计的C++标准界面。正如我们所看到的,越来越多的MFC程序出现了并继续在产生。4精选课件试验设计目标完成一个可重用的C++类,可以通过该类实现一个简单的模拟时钟编写一个简单的MFC程序测试验证这个时钟控件类关于这个时钟控件,如果按照课件继续完善下去,请将他做得更好更强大。比如说:可以考虑为时钟控件的各项设置(如颜色)提供外部接口,供CClockEx的使用者调用,可以考虑丰富背景绘制,加入背景图片设置,在刻度上标上数字,为指针加上阴影效果,在时钟上显示日期等。有兴趣的同学有空不妨试试。5精选课件应用程序框架设计过程(仅供参考)打开VC++6.0,新建一个MFC工程,输入工程名,选择“MFCAppWizard”如图所示,然后点击OK。6精选课件为简单起见,这里选择“Dialogbased”程序,然后可以直接选择finish了。7精选课件在类视图的工程名上右键单击,选择NewClass(如下图所示)来建立一个新类。8精选课件我们可以从CStatic类(静态控件类)派生出类CClockEx来实现时钟控件类,这样,就可以继承MFC静态控件的很多已经具备的功能和特点。在建立新类的对话框中,按下图输入。9精选课件按Ctrl+W调出ClassWizard,在classname中选择刚才建立的新类CClockEx,然后重载虚函数PreSubClassWindow,对时钟控件的基本初始化工作将在该函数中进行。添加消息响应WM_PAINT,我们必须用自己完成时钟的绘制工作。添加消息响应WM_SIZE,重载该消息响应以便我们的时钟控件能够自动适应其大小的变化。为了时钟能够走动,我们得定时刷新时钟控件让它走动,还得添加WM_TIMER的消息响应。最终效果如下图所示。10精选课件到目前为止,时钟控件的轮廓和已经有了,下面考虑时钟绘制的具体实现。一个时钟大致可由时钟背景、时针、分针、秒针四个部分构成。以上的时钟四个部分可是看作四个不同的对象,可以考虑建立类CClockBackground(背景)CClockHourHand(时针)、CClockMinHand(分针)、CClockSecHand(秒针)来分别实现。(此处为了意义明确,类名都比较长)这四个类有它们的共同点,譬如都有自己的绘图函数,如果要具体能够设置颜色,它们都应该有自己的绘图颜色,同样应该有颜色设置函数,此外都有绘图区域和区域设置函数等等。因此,可以为它们的共性建立一个基类,此处命名为CClockElement(时钟元素)。11精选课件下面逐步实现各个类,首先实现各个组成类的基类——CClockElement。同样,在ClassView的工程名上面点右键,选择NewClass,在ClassType里面选择GenenricClass,类CClockElement不需要从其它类派生,所以BaseClass可以不填,效果如下图所示。12精选课件下面对类CClockElement的源代码进行编写。因为在后面的绘图中需要用到sin和cos这两个数学计算公式,因此需包含头文件<MATH.H>以便使用数学函数库。为后面计算使用,还需定义数学常量PI(3.1415926535)。时钟的每个组成部分都有绘图区域区域,因此,可在基类中定义绘图区域变量。同理,可以定义颜色变量,为了是颜色不显得单调,这里为每个控件设置两种颜色(如果想使程序更加绚丽,可以设置更多颜色)。对应的,这些变量需增加接口函数来进行访问。对于每个组成部分都应该有的Draw函数,当然也需在基类中定义,但是,该函数对于基类来说是无需函数实现的,因此可定义为纯虚函数。13精选课件综合刚才这几点,CClockElement的实现的头文件代码如下:#include<MATH.H>#definePI3.1415926535classCClockElement{public: voidSetColor(COLORREFcrMain,COLORREFcrOther); //设置颜色 voidSetTime(constCTime&tmCur); //设置当前时间 voidSetRegion(LPRECTlprcRect); //设置绘图区域 virtualvoidDraw(CDC*pDC)=0; //绘图函数 CClockElement(); virtual~CClockElement();protected: COLORREF m_crMain; //主要颜色 COLORREF m_crOther; //辅助的其他颜色 CTime m_tmCur; //当前时刻 CRect m_rcRegion; //绘图区域 int m_nRadius; //时钟半径14精选课件CClockElement的实现的源文件关键代码如下:CClockElement::CClockElement(){ m_nRadius=0; m_crMain=RGB(255,255,255); m_crOther=RGB(128,128,128);}CClockElement::~CClockElement(){}voidCClockElement::SetRegion(LPRECTlprcRect){ m_rcRegion=lprcRect; m_nRadius=m_rcRegion.Width()/2; if(m_rcRegion.Width()>m_rcRegion.Height()) { m_nRadius=m_rcRegion.Height()/2; }}15精选课件续上页:voidCClockElement::SetTime(constCTime&tmCur){ m_tmCur=tmCur;}voidCClockElement::SetColor(COLORREFcrMain,COLORREFcrOther){ m_crMain=crMain; m_crOther=crOther;}16精选课件下面实现时钟背景类——CClockBackground。同样,在ClassView的工程名上面点右键,选择NewClass,在ClassType里面选择GenenricClass,类CClockBackground需要从类CClockElement派生,所以BaseClass需选择类CClockElement,效果如下图所示。17精选课件CClockBackground只需实现基类的虚函数Draw即可,因此这里重载基类的虚函数Draw,其头文件实现代码如下:#include"ClockElement.h"classCClockBackground:publicCClockElement{public: CClockBackground(); virtual~CClockBackground();};18精选课件CClockBackground源文件代码如下:CClockBackground::CClockBackground(){ //为时钟背景定义默认的颜色设置 m_crMain=RGB(0,255,0); m_crOther=RGB(0,128,0);}CClockBackground::~CClockBackground(){}voidCClockBackground::Draw(CDC*pDC){ //准备设备环境 CPenpenMain(PS_SOLID,1,m_crMain),penOther(PS_SOLID,1,m_crOther); CBrushbrMain(m_crMain),brOther(m_crOther); CPen*pOldPen=pDC->SelectObject(&penOther); CBrush*pOldBrush=pDC->SelectObject(&brMain);19精选课件CClockBackground源文件代码如下(续上页)://绘制60个小圆点,表示分针和秒针的刻度
CPointptCenter=m_rcRegion.CenterPoint(); intnRadius=m_nRadius-8; for(inti=0;i<60;i++) { CPointptEnd=ptCenter; ptEnd.Offset((int)(nRadius*sin(2*PI*(i%60)/60)), (int)(-nRadius*cos(2*PI*(i%60)/60))); CRectrcDot(-2,-2,2,2); rcDot.OffsetRect(ptEnd); pDC->Ellipse(rcDot); } //绘制12个小方框,表示12个正点 pDC->SelectObject(&penMain); pOldBrush=pDC->SelectObject(&brOther); for(i=0;i<12;i++) { CPointptEnd=ptCenter; doublefRadian=2*PI*(i%12)/12; ptEnd.Offset((int)(nRadius*sin(fRadian)), (int)(-nRadius*cos(fRadian))); CRectrcDot(-3,-3,3,3); rcDot.OffsetRect(ptEnd); pDC->Rectangle(rcDot); } //还原设备环境 pDC->SelectObject(pOldPen); pDC->SelectObject(pOldBrush);}20精选课件下面实现时针类CClockHourHand,该类新建的过程与CClockBackground一样,CClockHourHand同样只需实现基类的虚函数Draw即可,其头文件实现代码如下:#include"ClockElement.h"classCClockHourHand:publicCClockElement{public: CClockHourHand(); virtual~CClockHourHand(); virtualvoidDraw(CDC*pDC);};21精选课件CClockHourHand源文件代码如下:CClockHourHand::CClockHourHand(){ //定义默认颜色 m_crMain=RGB(0,255,100); m_crOther=RGB(128,128,0);}CClockHourHand::~CClockHourHand(){}voidCClockHourHand::Draw(CDC*pDC){ //初始化设备环境 CPenpenMain(PS_SOLID,1,m_crMain),penOther(PS_SOLID,1,m_crOther); CBrushbrMain(m_crMain),brOther(m_crOther); CPen*pOldPen=pDC->SelectObject(&penOther); CBrush*pOldBrush=pDC->SelectObject(&brMain); //确定当前指针的弧度 intnTime=(m_tmCur.GetHour()%12)*3600; nTime+=m_tmCur.GetMinute()*60; nTime+=m_tmCur.GetSecond(); doublefRadian=2*PI*nTime/3600/12;22精选课件CClockHourHand源文件代码如下(续上页):
//确定绘制菱形指针所需的四个角的坐标 CPointptDiamond[4]; for(inti=0;i<4;i++) { ptDiamond[i]=m_rcRegion.CenterPoint(); } intnRadus=m_nRadius/2; ptDiamond[0].Offset((int)(nRadus*sin(fRadian)),(int)(-nRadus*cos(fRadian))); fRadian+=0.5*PI; nRadus=m_nRadius/20; ptDiamond[1].Offset((int)(nRadus*sin(fRadian)),(int)(-nRadus*cos(fRadian))); fRadian+=0.5*PI; nRadus=m_nRadius/10; ptDiamond[2].Offset((int)(nRadus*sin(fRadian)),(int)(-nRadus*cos(fRadian))); fRadian+=0.5*PI; nRadus=m_nRadius/20; ptDiamond[3].Offset((int)(nRadus*sin(fRadian)),(int)(-nRadus*cos(fRadian)));23精选课件CClockHourHand源文件代码如下(续上页):
//绘制菱形时针 pDC->Polygon(ptDiamond,4); //恢复设备环境 pDC->SelectObject(pOldPen); pDC->SelectObject(pOldBrush);24精选课件下面实现分针类CClockMinHand,该类新建的过程与CClockHourHand一样,类的实现也基本相似,其头文件实现代码如下:#include"ClockElement.h"classCClockMinHand:publicCClockElement{public: CClockMinHand(); virtual~CClockMinHand(); virtualvoidDraw(CDC*pDC);};25精选课件CClockMinHand源文件代码如下:CClockMinHand::CClockMinHand(){ //定义默认颜色 m_crMain=RGB(0,255,100); m_crOther=RGB(128,128,0);}CClockMinHand::~CClockMinHand(){}voidCClockMinHand::Draw(CDC*pDC){ //初始化设备环境 CPenpenMain(PS_SOLID,1,m_crMain),penOther(PS_SOLID,1,m_crOther); CBrushbrMain(m_crMain),brOther(m_crOther); CPen*pOldPen=pDC->SelectObject(&penOther); CBrush*pOldBrush=pDC->SelectObject(&brMain); //确定分针所在位置的弧度 intnTime=m_tmCur.GetMinute()*60; nTime+=m_tmCur.GetSecond(); doublefRadian=2*PI*nTime/3600;26精选课件CClockMinHand源文件代码如下(续上页): //确定绘制菱形指针所需的四个角的坐标 CPointptDiamond[4]; for(inti=0;i<4;i++) { ptDiamond[i]=m_rcRegion.CenterPoint(); } intnRadus=m_nRadius/2; ptDiamond[0].Offset((int)(nRadus*sin(fRadian)),(int)(-nRadus*cos(fRadian))); fRadian+=0.5*PI; nRadus=m_nRadius/20; ptDiamond[1].Offset((int)(nRadus*sin(fRadian)),(int)(-nRadus*cos(fRadian))); fRadian+=0.5*PI; nRadus=m_nRadius/10; ptDiamond[2].Offset((int)(nRadus*sin(fRadian)),(int)(-nRadus*cos(fRadian))); fRadian+=0.5*PI; nRadus=m_nRadius/20; ptDiamond[3].Offset((int)(nRadus*sin(fRadian)),(int)(-nRadus*cos(fRadian)));27精选课件CClockMinHand源文件代码如下(续上页):
//绘制菱形分针 pDC->Polygon(ptDiamond,4); //恢复设备环境 pDC->SelectObject(pOldPen); pDC->SelectObject(pOldBrush);28精选课件下面实现秒针类CClockSecHand,该类新建的过程与CClockHourHand一样,类的实现也基本相似,其头文件实现代码如下:#include"ClockElement.h"classCClockSecHand:publicCClockElement{public: CClockSecHand(); virtual~CClockSecHand(); virtualvoidDraw(CDC*pDC);};29精选课件CClockSecHand源文件代码如下:CClockSecHand::CClockSecHand(){ //设定秒针的默认颜色 m_crMain=RGB(0,200,200); m_crOther=RGB(0,200,200);}CClockSecHand::~CClockSecHand(){}voidCClockSecHand::Draw(CDC*pDC){ intnTime=m_tmCur.GetSecond(); CPointptStart=m_rcRegion.CenterPoint(); CPointptEnd=ptStart; intnRadius=m_nRadius-10; ptEnd.Offset((int)(nRadius*sin(2*PI*nTime/60)), (int)(-nRadius*cos(2*PI*nTime/60))); CPenpenMain(PS_SOLID,1,m_crMain); CPen*pOldPen=pDC->SelectObject(&penMain); pDC->MoveTo(ptStart); pDC->LineTo(ptEnd); pDC->SelectObject(pOldPen);}30精选课件到目前为止,时钟的各个部件都已经设计完毕,现在该把它们组装起来了。刚才建立的四个类CClockBackground、CClockHourHand、CClockMinHand、CClockSecHand要为CClockEx服务,正如CClockElement为它们服务一样,不过服务的方式发生了变化,刚才是以继承的方式使用,现在需要将上面四个类实例化供CClockEx使用。因此,首先应该在类CClockEx为上四个类分别建立对象。在CClockEx的头文件中恰当位置加入以下代码:#include"ClockBackground.h"#include"ClockHourHand.h"#include"ClockMinHand.h"#include"ClockSecHand.h"classCClockEx:publicCStatic{private: CClockBackground m_clockBK; //时钟背景 CClockHourHand m_clockHour; //时指针 CClockMinHand m_clockMin; //分指针 CClockSecHand m_clockSec; //秒指针31精选课件为了存储绘图区域的大小,需要在CClockEx中加入一个变量m_rcClient:CRect m_rcClient; //客户区域在PreSubclassWindow函数中进行时钟的初始化工作。首先得为各个部件设定区域大小,然后启动定时刷新的定时器(100毫秒的定时器已经足够)。由于每个部件都有自己的默认颜色配置,因此这里暂且先使用默认配置,当然也可以自定义颜色: GetClientRect(m_rcClient);//获取当前客户区域 m_clockBK.SetRegion(m_rcClient); m_clockHour.SetRegion(m_rcClient); m_clockMin.SetRegion(m_rcClient); m_clockSec.SetRegion(m_rcClient); SetTimer(1,100,NULL); //每100毫秒刷新一次32精选课件当控件大小发生变化时,控件状态要能够自动更新:voidCClockEx::OnSize(UINTnType,intcx,intcy){ CStatic::OnSize(nType,cx,cy);
GetClientRect(m_rcClient); m_clockBK.SetRegion(m_rcClient); m_clockHour.SetRegion(m_rcClient); m_clockMin.SetRegion(m_rcClient); m_clockSec.SetRegion(m_rcClient);}每个定时器时间触发时,需要刷新控件以保证时钟的走动:voidCClockEx::OnTimer(UINTnIDEvent){ Invalidate(FALSE);
CStatic::OnTimer(nIDEvent);}33精选课件下面实现时钟的绘制,由于控件在不断刷新,按一般方式绘图,屏幕会不断闪烁,因此此处使用双缓冲绘图——就是在内存中绘图,绘制完毕时在Copy到屏幕上,这样可以有效的防止屏幕闪烁:voidCClockEx::OnPaint(){ CPaintDCdc(this);//devicecontextforpainting //实现双缓冲绘图——防止屏幕闪烁 CDC dcMem; dcMem.CreateCompatibleDC(&dc); CBitmap bmp; bmp.CreateCompatibleBitmap(&dc,m_rcClient.Width(),m_rcClient.Height()); dcMem.SelectObject(&bmp); DrawClock(&dcMem); //绘制时钟 dc.BitBlt(0,0,m_rcClient.Width(),m_rcClient.Height(),&dcMem,0,0,SRCCOPY);}34精选课件为了程序结构更清晰,我们将绘图函数放在一个单独的函数DrawClock中,下面室DrawClock的函数实现:voidCClockEx::DrawClock(CDC*pDC){ CTimetmCur=CTime::GetCurrentTime(); m_clockBK.SetTime(tmCur); m_clockHour.SetTime(tmCur); m_clockMin.SetTime(tmCur); m_clockSec.SetTime(tmCur); m_clockBK.Draw(pDC); m_clockMin.Draw(pDC); m_clockHour.Draw(pDC); m_clockSec.Draw(pDC);}35精选课件下面是完整的CClockEx源码:#if!defined(AFX_CLOCKEX_H__EB35C434_A727_43BE_B10E_121F6307EA73__INCLUDED_)#defineAFX_CLOCKEX_H__EB35C434_A727_43BE_B10E_121F6307EA73__INCLUDED_#if_MSC_VER>1000#pragmaonce#endif//_MSC_VER>1000//ClockEx.h:headerfile/////////////////////////////////////////////////////////////////////////////////CClockExwindow#include"ClockBackground.h"#include"ClockHourHand.h"#include"ClockMinHand.h"#include"ClockSecHand.h"classCClockEx:publicCStatic{private: CRect m_rcClient; //客户区域 CClockBackground m_clockBK; //时钟背景 CClockHourHand m_clockHour; //时指针 CClockMinHand m_clockMin; //分指针 CClockSecHand m_clockSec; //秒指针 voidDrawClock(CDC*pDC);//Constructionpublic: CClockEx();36精选课件下面是完整的CClockEx源码(续上页)://Attributespublic://Operationspublic://Overrides //ClassWizardgeneratedvirtualfunctionoverrides //{{AFX_VIRTUAL(CClockEx) protected: virtualvoidPreSubclassWindow(); //}}AFX_VIRTUAL//Implementationpublic: virtual~CClockEx(); //Generatedmessagemapfunctionsprotected: //{{AFX_MSG(CClockEx) afx_msgvoidOnPaint(); afx_msgvoidOnSize(UINTnType,intcx,intcy); afx_msgvoidOnTimer(UINTnIDEvent); //}}AFX_MSG DECLARE_MESSAGE_MAP()};///////////////////////////////////////////////////////////////////////////////{{AFX_INSERT_LOCATION}}//MicrosoftVisualC++willinsertadditionaldeclarationsimmediatelybeforethepreviousline.#endif//!defined(AFX_CLOCKEX_H__EB35C434_A727_43BE_B10E_121F6307EA73__INCLUDED_)37精选课件下面是完整的CClockEx源码(续上页)://ClockEx.cpp:implementationfile#include"stdafx.h"#include"ClockProject.h"#include"ClockEx.h"#ifdef_DEBUG#definenewDEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE[]=__FILE__;#endif////////////////////////////////////////////////////////////////////////CClockExCClockEx::CClockEx(){}CClockEx::~CClockEx(){}BEGIN_MESSAGE_MAP(CClockEx,CStatic) //{{AFX_MSG_MAP(CClockEx) ON_WM_SIZE() ON_WM_PAINT() ON_WM_TIMER() //}}AFX_MSG_MAPEND_MESSAGE_MAP()38精选课件下面是完整的CClockEx源码(续上页)://////////////////////////////////////////////////////////////////////////CClockExmessagehandlersvoidCClockEx::PreSubclassWindow(){ //获取当前客户区域 GetClientRect(m_rcClient); m_clockBK.SetRegion(m_rcClient); m_clockHour.SetRegion(m_rcClient); m_clockMin.SetRegion(m_rcClient); m_clockSec.SetRegion(
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论