MFC模拟时钟.doc
MFC模拟时钟模拟时钟以实例为背景学习基于MFC的WINDOWS应用程序设计,编写一个模拟时钟程序,此程序在屏幕上有一个指针式钟面,用菜单选项进行时间控制。时间必与机器系统时间相同,不可任意设置。1 编程要求(1)为该程序设计绘制合适的时钟外形.(2)程序界面设计合理,色彩得体大方,显示正确.(3)时针、分针和秒针形象美观,即使各指针重合也可辨认。(4)各指针运动规律正确,以便于演示。(5)时间显示正确,并且显示当前系统时间。(6)按下设置菜单项可实现时间的调整与重新显示2 问题分析本题主要涉及到的知识点有:时钟指针运动算法、屏幕重绘方法、菜单命令、画笔/画刷等.指针运动算法和屏幕重绘方法是本程序主要难点所在.不论何种指针,每次转动均以/30弧度(一秒的角度)为基本单位,且都以表盘中心为转动圆心。计算指针端点(x, y)的公式如下:x =圆心x坐标 + 指针长度 * cos (指针方向角)y =圆心y坐标 + 指针长度 sin (指针方向角)注意,指针长度是指自圆心至指针一个端点的长度(是整个指针的一部分),由于指针可能跨越圆心,因此一个指针需要计算两个端点。三个指针的运动是相关联的,秒针转一圈引起分针运动一格,分针转一圈引起时针运动一格,因此应该使用一个定时器消息来处理指针的运动。若用三个定时器消息分别处理时针、分针和秒针的运动,就会使问题复杂化且不易实现三个指针联动的正确规律。采用一个定时器消息可以很容易实现指针联动算法。3 实现步骤 (1)用AppWizard生成一个名为“模拟时钟”的单文档(SDI)程序框架。为了简化应用程序,在第四步时去掉Docking toolbar和Initial status bar选择项,其他各选项均可用缺省设置。(2)编辑项目的菜单资源,在主框架窗口的主菜单(IDR_MAINFRAME)中添加一个名为“时钟控制"的下拉菜单。在“时钟控制”菜单中添加二个菜单选项“启动时钟”、“停止时钟”并在菜单属性项中设定“启动时钟”菜单的ID标号为ID_START,“停止时钟”菜单的ID标号为ID_STOP,“为了简化菜单,可删除系统原有的“编辑”、“关于”等菜单项。(3)利用ClassWizard为视图类添加菜单命令处理函数.进入ClassWizard的Message Maps选项卡,选择Class Name项为CMyView类,在Object IDs列表框中分别选择新添加的菜单选项的ID,在Messages列表框中选择COMMAND,按下Add Function按钮添加成员函数。ClassWizard会为“启动时钟”、“停止时钟"菜单选项添加相应的消息响应函数OnStart ( )、OnStop ( )。(4)设计好这个对话框模板后,利用ClassWizard自动建立对话框类。进入ClassWizard后,它会发现已建立的对话框模板资源,并弹出一个对话框询问是否要为该对话框模板建立类。按下“OK”按钮,会弹出New Class对话框,在Name栏填写对话框类的名称CSetTimeDlg后按“OK”按钮,即可为对话框创建一个对应的类。(5)编辑工程的图标资源,在Resource View选项窗口中修改Icon结点所包含的主框架图标(IDR_MAINFRAME),修改标准图标(32像素×32像素)及小图标(16像素×16像素),从而为该程序设计一个美观大方的图标。(6)完成以上工作后,即可修改程序框架,添加必要的代码.4 程序清单按以下步骤向视图类(CClockView)添加下列数据成员及成员函数。(1) 添加时钟的画笔及画刷变量.CPen m_HouPen, m_MinPen, m_SecPen; / 各种针的画笔CBrush m_MarkBrush; / 表盘标记的画刷(2) 添加时钟控制变量。CPoint m_Center; / 表的中心double m_Radius; / 表的半径CPoint m_Hour 2, m_OldHour 2; / 时针当前及前一次位置CPoint m_Minute 2, m_OldMin 2; / 分针当前及前一次位置CPoint m_Second 2, m_OldSec 2; / 秒针当前及前一次位置 (3) 添加两个函数,计算时钟各指针位置。void SetClock (int hour, int minute, int second);CPoint GetPoint (int nLenth, int nValue);(4) 在视图类中加入此函数,来画时钟static CSize operator (const CSize sz,float scalar)CSize new_sz; new_sz。cx=int(sz.cx*scalar); new_sz.cy=int(sz.cyscalar); return new_sz;CSize PositionOnCircle(const CSize radius,double angle)CSize result; result.cx=(int) (sin ( angle * 2 * M_PI ) * radius。cx); result。cy=(int) (-cos (angle * 2 * M_PI ) radius。cy); return result;const static COLORREF pieColorLookup= RGB(248,141,177), RGB(235,252,69), RGB(90,87,213); void CMainFrame::DrawClock(CDC pDC)CRect clientArea; GetClientRect(clientArea); CRect theClockFace(CPoint(5,5),clientArea。Size()CSize(10,10); CPen pen;CBrush brush; int piePart; CPoint center,p1,p2; CSize radius; SYSTEMTIME st; GetLocalTime(&st); radius=theClockFace.Size()0。5; center=theClockFace.CenterPoint(); pDC>SetArcDirection(AD_CLOCKWISE); for(piePart=0;piePart<12;piePart+)COLORREF pieColor; pieColor = pieColorLookuppiePart3; pen.CreatePen(PS_SOLID,1,pieColor); brush。CreateSolidBrush(pieColor); pDC>SelectObject(&pen); pDC->SelectObject(brush); p1=center+PositionOnCircle(radius,piePart/12.0); p2=center+PositionOnCircle(radius,(piePart+1)/12.0); pDC>Pie(theClockFace,p1,p2); pen。DeleteObject(); brush。DeleteObject(); pen.CreatePen(PS_SOLID,4,RGB(180,0,0)); pDC->SelectObject(pen); pDC->MoveTo(center);pDC-LineTo(center+PositionOnCircle(radius,st.wHour/12.0+st.wMinute/720.0)*0.4); pen.DeleteObject(); pen。CreatePen(PS_SOLID,4,RGB(0,180,0)); pDCSelectObject(pen); pDC>MoveTo(center); pDCLineTo(center+PositionOnCircle(radius,st.wMinute/60.0)*0。8); pen。DeleteObject(); pen.CreatePen(PS_SOLID,1,RGB(0,0,0)); pDCSelectObject(pen); pDC>MoveTo(center);pDC->LineTo(center+PositionOnCircle(radius,st.wSecond/60.0)0.95); (5)在其中加入次函数使更新显示,使显示当前系统时间void CMainFrame::OnUpdateAlwaysOnTop(CCmdUI *pCmdUI)pCmdUISetCheck(IsOnTop); (6) 按照下列步骤增加时钟控制代码: 修改Onstart和OnStop函数,使其可以停止时钟和重新显示时间。其代码为:void CMainFrame::OnStart() / TODO: Add your command handler code here SetTimer(100,1000,NULL);void CMainFrame::OnStop() / TODO: Add your command handler code hereKillTimer(100);(7)至此,时钟程序设计完成。程序运行:模拟时钟示意图进行程序检验:运行程序后显示入上图所示:单击“时间控制”菜单项后,会显示2个下拉选项“开启时间"和“停止时间",点击“停止时间”选项时钟将停止,在点击“开启时间”选项,继续下士系统当期时间,正常运行。