以文本方式查看主题

-  计算机科学论坛  (http://bbs.xml.org.cn/index.asp)
--  『 C/C++编程思想 』  (http://bbs.xml.org.cn/list.asp?boardid=61)
----  七段数码显示的数字时钟【附源码】  (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=64647)


--  作者:卷积内核
--  发布时间:7/16/2008 9:06:00 AM

--  七段数码显示的数字时钟【附源码】
摘要
绝大多数的电子产品都使用了七段数码显示,如果软件也能模拟出这种效果该有多好?在本文之前,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下编译通过。


[此贴子已经被作者于2008-7-17 15:53:42编辑过]

W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
46.875ms