用VC++制作模拟时钟应用程序.docx

上传人:b****0 文档编号:9662741 上传时间:2023-05-20 格式:DOCX 页数:15 大小:28.91KB
下载 相关 举报
用VC++制作模拟时钟应用程序.docx_第1页
第1页 / 共15页
用VC++制作模拟时钟应用程序.docx_第2页
第2页 / 共15页
用VC++制作模拟时钟应用程序.docx_第3页
第3页 / 共15页
用VC++制作模拟时钟应用程序.docx_第4页
第4页 / 共15页
用VC++制作模拟时钟应用程序.docx_第5页
第5页 / 共15页
用VC++制作模拟时钟应用程序.docx_第6页
第6页 / 共15页
用VC++制作模拟时钟应用程序.docx_第7页
第7页 / 共15页
用VC++制作模拟时钟应用程序.docx_第8页
第8页 / 共15页
用VC++制作模拟时钟应用程序.docx_第9页
第9页 / 共15页
用VC++制作模拟时钟应用程序.docx_第10页
第10页 / 共15页
用VC++制作模拟时钟应用程序.docx_第11页
第11页 / 共15页
用VC++制作模拟时钟应用程序.docx_第12页
第12页 / 共15页
用VC++制作模拟时钟应用程序.docx_第13页
第13页 / 共15页
用VC++制作模拟时钟应用程序.docx_第14页
第14页 / 共15页
用VC++制作模拟时钟应用程序.docx_第15页
第15页 / 共15页
亲,该文档总共15页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

用VC++制作模拟时钟应用程序.docx

《用VC++制作模拟时钟应用程序.docx》由会员分享,可在线阅读,更多相关《用VC++制作模拟时钟应用程序.docx(15页珍藏版)》请在冰点文库上搜索。

用VC++制作模拟时钟应用程序.docx

用VC++制作模拟时钟应用程序

(3)时针、分针和秒针形象美观,即使各指针重合也可辨认。

(4)各指针运动规律正确。

为便于演示,时钟速度应比实际时间快20倍,即1小时相当于3分钟。

(5)数字式时钟的时间显示与指针式时钟显示一致。

(6)按下设置时间按钮或菜单项可弹出一对话框,用于设置当前的时间和日期。

(7)按下秒表控制按钮后,秒表显示窗中显示从0开始的时间,单位为百分之一秒。

再次按下秒表控制按钮后计时停止,该窗口显示累计时间。

2 问题分析

本题主要涉及到的知识点有:

时钟指针运动算法、屏幕重绘方法、定时器消息、鼠标消息、菜单命令、对话框、画笔/画刷、显示文字等。

指针运动算法和屏幕重绘方法是本程序主要难点所在。

不论何种指针,每次转动均以π/30弧度(一秒的角度)为基本单位,且都以表盘中心为转动圆心。

计算指针端点(x,y)的公式如下:

x=圆心x坐标+指针长度*cos(指针方向角)

y=圆心y坐标+指针长度*sin(指针方向角)

注意,指针长度是指自圆心至指针一个端点的长度(是整个指针的一部分),由于指针可能跨越圆心,因此一个指针需要计算两个端点。

三个指针的运动是相关联的,秒针转一圈引起分针运动一格,分针转一圈引起时针运动一格,因此应该使用一个定时器消息来处理指针的运动。

若用三个定时器消息分别处理时针、分针和秒针的运动,就会使问题复杂化且不易实现三个指针联动的正确规律。

采用一个定时器消息可以很容易实现指针联动算法。

由于屏幕的重绘速度很快(50ms一次),如果采用全屏删除式重绘则闪烁十分明显,显示效果不佳。

本程序采用非删除式重绘,假定指针将要移动一格,则先采用背景色(这里是白色)重绘原来指针以删除原来位置的指针,再采用指针的颜色在当前位置绘制指针;如果指针没有动,则直接绘制指针。

另外,秒表需要采用单独的定时器消息控制。

4 程序清单

按以下步骤向视图类(CClockView)添加下列数据成员及成员函数。

(1)添加表示年、月、日、时、分、秒的变量。

intyear;

intmonth;

intday;

inthour;

intminute;

intsecond;

(2)添加秒表的计数变量。

intwatch;

(3)添加时钟的画笔及画刷变量。

CPenm_HouPen,m_MinPen,m_SecPen;//各种针的画笔

CBrushm_MarkBrush;//表盘标记的画刷

(4)添加时钟控制变量。

CPointm_Center;//表的中心

doublem_Radius;//表的半径

CPointm_Hour[2],m_OldHour[2];//时针当前及前一次位置

CPointm_Minute[2],m_OldMin[2];//分针当前及前一次位置

CPointm_Second[2],m_OldSec[2];//秒针当前及前一次位置

(5)添加秒表的两个按钮位置变量。

CRectm_WatchStart;

CRectm_WatchStop;

(6)添加两个函数,计算时钟各指针位置。

voidSetClock(inthour,intminute,intsecond);

CPointGetPoint(intnLenth,intnValue);

(7)在视图类构造函数中增加初始化语句:

CClockView:

:

~CClockView()

{

//设定时间

year=2010;

month=11;

day=22;

hour=0;

minute=0;

second=0; 

//设定画笔画刷

m_HouPen.CreatePen(PS_SOLID,5,RGB(255,0,0));//时针画笔

m_MinPen.CreatePen(PS_SOLID,3,RGB(0,0,250));//分针画笔

m_SecPen.CreatePen(PS_SOLID,1,RGB(0,0,0));//秒针画笔

m_MarkBrush.CreateSolidBrush(RGB(250,250,0));

//设定表芯位置

m_Center.x=222;

m_Center.y=222;

 //设定时钟半径

m_Radius=222;

//计算指针位置

SetClock(hour,minute,second);

//设定秒表计数器及按钮位置

watch=0;

m_WatchStart=CRect(480,310,560,340);//启动按钮

m_WatchStop=CRect(590,310,670,340);//停止按钮

}

 

编写指针位置函数SetClock和GETpOINT。

首先在ClockView.cpp文件头部下添加下面两行代码,以便进行数学计算。

#definePI3.14159265258

#include"math.h"

然后添加下列代码:

 

//计算个指针位置的函数

voidCClockView:

:

SetClock(inthour,intminute,intsecond)

{

hour=hour*5;

hour=hour+minute/12;

//保存时针原位置

m_OldHour[0]=m_Hour[0];

m_OldHour[1]=m_Hour[1];

//计算时针当前位置

m_Hour[0]=GetPoint(int(m_Radius/2),hour);

m_Hour[1]=GetPoint(7,hour+30); 

//保存分针原位置

m_OldMin[0]=m_Minute[0];

m_OldMin[1]=m_Minute[1];

//计算分针当前位置

m_Minute[0]=GetPoint(int(m_Radius*7/10),minute);

m_Minute[1]=GetPoint(10,minute+30);

//保存秒针原位置

m_OldSec[0]=m_Second[0];

m_OldSec[1]=m_Second[1];

 

//计算秒针当前位置

m_Second[0]=GetPoint(int(m_Radius*8/10),second);

m_Second[1]=GetPoint(30,second+30);

}

//计算以表为原点的指针端点位置

CPointCClockView:

:

GetPoint(intnLenth,intnValue)

{

CPointp;

doubleangle=nValue*PI/30-PI/2;

p.x=m_Center.x+(int)(nLenth*cos(angle));

p.y=m_Center.y+(int)(nLenth*sin(angle));

returnp;

}

绘制表盘上的标记、时针、分针和秒针,并显示数字时钟及秒表:

在OnDraw函数中添加下面代码:

voidCClockView:

:

OnDraw(CDC*pDC)

{

CClockDoc*pDoc=GetDocument();

ASSERT_VALID(pDoc);

//绘制表盘标记

pDC->SelectObject(m_MarkBrush);

for(inti=0;i<60;i++)

{

CPointpt=GetPoint(175,i);

if(i%5==0){

pDC->Rectangle(pt.x-5,pt.y-5,pt.x+5,pt.y+5);

}

else

{

pDC->Ellipse(pt.x-2,pt.y-2,pt.x+2,pt.y+2);

}

}

//画时针

pDC->SelectObject(m_HouPen);

if(m_OldHour[0]!

=m_Hour[0])

{

//用白色覆盖原位置时针

pDC->SetROP2(R2_WHITE);

pDC->MoveTo(m_OldHour[0]);

pDC->LineTo(m_OldHour[1]);

pDC->SetROP2(R2_COPYPEN);

//时针绘制

pDC->MoveTo(m_Hour[0]);

pDC->LineTo(m_Hour[1]);

}

else

{

pDC->MoveTo(m_Hour[0]);

pDC->LineTo(m_Hour[1]);

}

//画分针

pDC->SelectObject(m_MinPen);

if(m_OldMin[0]!

=m_Minute[0])

{

//用白色覆盖原位置的分针

pDC->SetROP2(R2_WHITE);

pDC->MoveTo(m_OldMin[0]);

pDC->LineTo(m_OldMin[1]);

pDC->SetROP2(R2_COPYPEN);

//分针绘制

pDC->MoveTo(m_Minute[0]);

pDC->LineTo(m_Minute[1]);

}

else

{

pDC->MoveTo(m_Minute[0]);

pDC->LineTo(m_Minute[1]);

//画秒针

//用白色覆盖原位置的秒针

pCD->SelectObject(m_SecPen)

pDC->SetROP2(R2_WHITE);

pDC->MoveTo(m_OldSec[0]);

pDC->LineTo(m_OldSec[1]);

pDC->SetROP2(R2_COPYPEN);

//秒针绘制

pDC->MoveTo(m_Second[0]);

pDC->LineTo(m_Second[1]);

//数字时钟显示

pDC->SelectStockObject(WHITE_BRUSH);

pDC->Rectangle(450,30,700,180);

pDC->TextOut(535,52,"当前时间");

CStringm_Date,m_Time;

m_Date.Format("%4d年%4月%4日",year,month,day);

pDC->TextOut(510,70,m_Date);

m_Time.Format("%4d点%4分%4秒",hour,minute,second);

pDC->TextOut(510,100,m_Time);

//秒表显示

pDC->Rectangle(450,220,700,370);

pDC->TextOut(545,200,"秒表");

intminSec=watch%100;

intSec=(watch/100)%60;

intMin=(watch/100)/60;

m_Time.Format("%02d:

%02d:

%02d",Min,Sec,minSec);

pDC->TextOut(535,260,m_Time);

pDC->Rectangle(&m_WatchStart);

pDC->Rectangle(&m_WatchStop);

pDC->TextOut(m_WatchStart.left+18,m_WatchStart.top+5,"启动");

pDC->TextOut(m_WatchStop.left+18,m_WatchStop.top+5,"停止");

}

 

请注意将表示时间的整数转换为CString字符串类型的方法以及秒表的显示方法。

另外,watch计数器以1/100秒为计数单位,每达到100则秒数加1。

u按照下列步骤增加时钟控制代码:

①修改Onstart和OnStop函数,设置时钟运动消息。

按比正常时钟快20倍的假定,50ms产生一个消息。

其代码为:

voidCClockView:

:

OnStart()

{

//TODO:

Addyourcommandhandlercodehere

SetTimer(1,50,NULL);

}

voidCClockView:

:

OnStop()

{

//TODO:

Addyourcommandhandlercodehere

KillTimer

(1);

}

②修改OnTimer函数,正确计算并处理年、月、日、时、分、秒等变量的联动变化,其代码为:

voidCClockView:

:

OnTimer(UINTnlDEvent)

{if(nlDEvent==1)

{second++;//秒增加

if(second>59)

{second=0;

minute++;//分增加

}

if(minute>9)

{

minute=0;

hour++;//小时增加

}

if(hour>23)

{hour=0;

day++;//天增加

}

switch(month)

{case1:

//大月

case3:

case5:

case7:

case8:

case10:

case12:

if(day>31)

{day=1;

month++;//月增加

}

break;

case4:

case6:

case9:

case11:

if(day>30)

{day=1;

month++;//月增加

}

break;

case2:

if(year%4==0&&day>29)//闰二月

{day=1;

month++;

}

if(year%4!

=0&&day>28)//二月

{day=1;

month++;

}

break;

}

if(month>12)

{

//年增加

year++;

month=1;

}

SetClock(hour,minute,second);

Invalidate(false);

}

//秒表定时器消息处理

if(nlDEvent==2)

{

watch++;

Invalidate(false);

}

CView:

:

OnTimer(nlDEvent);

}

③添加时间设置对话框代码。

首先在ClockView.cpp文件头部添加下列语句:

#include“SetTimeDlg.H”

在时间设定对话框类的构造函数中,做如下修改,将初始日期设为2010-11-26:

CSetTimeDtg:

:

CSetTimeDtg(CWnd*pParent/*=NULL*/)

:

CDialog(CSetTimeDtg:

:

IDD,pParent)

{

//||AFX_DATA_INIT(CSetTimeDlg)

m_Day=26;

m_Hour=0;

m_Minute=0;

m_Mouth=11;

m_Second=0;

m_Year=2010;

//||AFX_DATA_INIT

}

最后,在OnSettime函数中添加代码如下:

voidCClockView:

:

OnSettime()

{

CSetTimeDtgSetDlg;

if(SetDlg.DoModal()==IDOK)

{

year=SetDlg.m_Year;

month=SetDlg.m_Mouth;

day=SetDlg.m_Day;

hour=SetDlg.m_Hour;

minute=SetDlg.m_Minute;

second=SetDlg.m_Second;

}//计算各指针位置

SetClock(hour,minute,second);

Invalidate(true);

}

至此,除秒表外,时钟部分程序设计完成。

u 按以下步骤设计秒表控制程序:

在OnLButtonDown函数中增加下列内容,以便响应单击秒表启动、停止框所发出的消息:

voidCClockView:

:

OnLButtonDown(UINTnFlags,CPointpoint)

{

if(m_WatchStart.PtInRect(point))

{

watch=0;

SetTimer(2,10,NULL);

}

if(m_WatchStop.PtInRect(point))

{

KillTimer

(2);

}

CView:

:

OnLButtonDown(nFlags,point);

}

程序运行:

下图显示了模拟时钟运行的情况。

“启动”和“停止”框控制秒表,时钟用菜单控制。

本题采用标准的SDI程序结构,完全利用视图类实现了这一程序。

利用定时器消息控制时钟运动是本程序的出发点。

利用一个定时器控制时钟,易于实现指针联动规律。

计算指针位置利用了坐标变换和三角函数的知识。

本程序一个较难处理的地方是屏幕重绘,由于完全在OnDraw函数中实现,因此限制较多。

本程序采取了先覆盖,再重绘的方法。

 

模拟时钟示意图

 本程序由于完全在OnDraw函数中实现,因此屏幕重绘较为麻烦。

如果在OnDarw函数中采用“异或”屏幕重绘方式,在程序窗口最大、最小化及移出屏幕时,会显示异常。

解决这一问题较理想的方式是在定时器处理函数OnTimer中采用“异或”方式直接重绘屏幕,而不采用调用Invalidate()函数的方式;同时在OnDraw函数中显示指针的最后状态,以便处理程序窗口最大、最小化及移出屏幕的情况。

在OnTimer函数中直接重绘屏幕需要使用OClientDC类,具体用法与OnDraw函数中的pDC对象基本一致。

另外,本程序的数字时钟没有显示星期和农历,读者可尝试添加进去。

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 教学研究 > 教学案例设计

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2