现在的位置: 首页 > 综合 > 正文

七段数码显示的数字时钟

2013年12月15日 ⁄ 综合 ⁄ 共 3546字 ⁄ 字号 评论关闭
 

七段数码显示的数字时钟

作者: mt.hu

下载源代码

摘要
绝大多数的电子产品都使用了七段数码显示,如果软件也能模拟出这种效果该有多好?在本文之前,VC知识库在线杂志曾有两篇文章介绍过如何实现这种效果,有一篇的实现方法较为简单,但绘出的数字不够逼真,而另一篇实现的效果虽然逼真,但必须依赖位图资源,并且无法设置前景色和背景色等。笔者经过仔细的研究与试验,终于找到了较好的解决办法。本文将详细讲述七段数码显示的数字时钟的实现。
关键字 七段数码显示 数字时钟
实现原理
我们知道,时钟的显示由时、分、秒及冒号组成,因此我们可以用以下函数来实现:DrawHour,DrawMinute,DrawSecond和Draw2Dot。由于时、分、秒都由两个数字组成(小于10的前面加0),因此可以再把问题分解,用DrawSingleNunber来画单个数字。单个数字又该怎么画呢?下面看七段数码的组成,我们用1到7的标号来表示每一段。

由于每个数字都是由这七段拼凑而成,因此我们可以在DrawSingleNumber函数中用switch语句,根据不同的数字去画不同的段,接下来的工作就是如何去画这七段了,每一段都是一个具有颜色填充的多边形。

void CDigitalClock::DrawSingleNumber(int nNum,int nLeft)
{
	switch (nNum)
	{
	case 0:
		DrawSection1(nLeft);
		DrawSection2(nLeft);
		DrawSection3(nLeft);
		DrawSection4(nLeft);
		DrawSection5(nLeft);
		DrawSection6(nLeft);
		break;
	case 1:		
		DrawSection2(nLeft);
		DrawSection3(nLeft);		
		break;
	case 2:
		DrawSection1(nLeft);
		DrawSection2(nLeft);
		DrawSection4(nLeft);
		DrawSection5(nLeft);
		DrawSection7(nLeft);
		break;
	case 3:
		DrawSection1(nLeft);
		DrawSection2(nLeft);
		DrawSection3(nLeft);
		DrawSection4(nLeft);		
		DrawSection7(nLeft);
		break;
	case 4:		
		DrawSection2(nLeft);
		DrawSection3(nLeft);		
		DrawSection6(nLeft);
		DrawSection7(nLeft);
		break;
	case 5:
		DrawSection1(nLeft);
		DrawSection3(nLeft);
		DrawSection4(nLeft);
		DrawSection6(nLeft);
		DrawSection7(nLeft);
		break;
	case 6:
		DrawSection1(nLeft);
		DrawSection3(nLeft);
		DrawSection4(nLeft);
		DrawSection5(nLeft);
		DrawSection6(nLeft);
		DrawSection7(nLeft);
		break;
	case 7:
		DrawSection1(nLeft);
		DrawSection2(nLeft);
		DrawSection3(nLeft);		
		break;
	case 8:
		DrawSection1(nLeft);
		DrawSection2(nLeft);
		DrawSection3(nLeft);
		DrawSection4(nLeft);
		DrawSection5(nLeft);
		DrawSection6(nLeft);
		DrawSection7(nLeft);
		break;
	case 9:
		DrawSection1(nLeft);
		DrawSection3(nLeft);
		DrawSection4(nLeft);
		DrawSection2(nLeft);
		DrawSection6(nLeft);
		DrawSection7(nLeft);
		break;
	default:
		;
	}
}

要画出逼真的效果来,必须精确或基本精确去计算出多边形的每个顶点的坐标,然后用作图函数MoveTo和LineTo去画线条,画线前,可以构造一个画笔,用指定的颜色去画。把几个边的线条画好后,发现还需要进行填充,因此再去构造一个区域,使用画刷进行填充。这样一来,不仅画出了立体效果,还可以设置不同的背景色和前景色。以下代码展示了第一段的绘制过程

void CDigitalClock::DrawSection1(int nLeft)
{
	if (m_memDC.m_hDC!=NULL)
	{
		CPoint point[4];
		point[0].x=nLeft+(int)(0.1*m_nWidth);
		point[0].y=m_nYmargin;

		point[1].x=nLeft+(int)(0.9*m_nWidth);
		point[1].y=m_nYmargin;

		point[2].x=nLeft+(int)(0.7*m_nWidth);
		point[2].y=(int)(0.2*m_nWidth)+m_nYmargin;

		point[3].x=nLeft+(int)(0.3*m_nWidth);
		point[3].y=(int)(0.2*m_nWidth)+m_nYmargin;

		CBrush br(m_crText);
		CRgn rgn;
		rgn.CreatePolygonRgn(point,4,ALTERNATE);
		m_memDC.FillRgn(&rgn,&br);

		br.DeleteObject();
		rgn.DeleteObject();
		
		m_memDC.MoveTo(point[0]);
		m_memDC.LineTo(point[1]);
		
		m_memDC.MoveTo(point[1]);
		m_memDC.LineTo(point[2]);
		
		m_memDC.MoveTo(point[2]);
		m_memDC.LineTo(point[3]);
		
		m_memDC.MoveTo(point[3]);
		m_memDC.LineTo(point[0]);			
	}	
}

实现了这些基本元素“段”,就可以画单个数字了,进而可以在不同的位置画出时、分、秒。冒号由一个专门的函数Draw2Dot来实现。

void CDigitalClock::Draw2Dot(int nLeft)
{
	if (m_memDC.m_hDC!=NULL)
	{
		CBrush br(m_crText);				

		CRect rect;
		rect.SetRect(nLeft+(int)(0.3*m_nWidth),(int)(0.4*m_nWidth)+m_nYmargin,
			nLeft+(int)(0.6*m_nWidth),(int)(0.7*m_nWidth)+m_nYmargin);
		m_memDC.Ellipse(rect);
		CRgn rgn1;
		rgn1.CreateEllipticRgn(rect.left,rect.top,rect.right,rect.bottom);
		m_memDC.FillRgn(&rgn1,&br);

		rect.OffsetRect(0,(int)(0.8*m_nWidth)+m_nYmargin);
		m_memDC.Ellipse(rect);
		CRgn rgn2;
		rgn2.CreateEllipticRgn(rect.left,rect.top,rect.right,rect.bottom);
		m_memDC.FillRgn(&rgn2,&br);

		br.DeleteObject();
		rgn1.DeleteObject();
		rgn2.DeleteObject();
	}
}

结语
要实现七段数码显示的效果,关键在于计算各个顶点的坐标,经过调试发现,将一个数字的宽度调整为高度的一半时可达到最好的显示效果。最初设计这个类时,我是在OnPaint里面调用自定义绘图函数DrawHour、DrawMinute、DrawSecond以及Draw2Dot,结果发现绘出的时钟有明显闪烁,后来采用双缓冲绘图的办法消除了这一现象。
本文实现的数字时钟从CStatic派生,使用时,只需在界面上放置一个静态文本控件,然后关联一个CDigitalClock的控件变量即可。示例代码在VC6.0+Windows XP下编译通过。运行效果如下图:

最后,衷心感谢《电子八段管的仿真控件》的作者kevin cheng和《电子式时钟》的作者李宏亮以及网友redcheek等人。
QQ: 40475290
Email: hmt-abc@163.com

【上篇】
【下篇】

抱歉!评论已关闭.