适用于 .NET 的七段数码管控件






4.87/5 (76投票s)
一个自定义的 Windows Forms 控件,外观类似于电子七段数码管显示屏。
代码
源代码可在 GitHub 上获取!
引言
我通常不太喜欢自定义控件,除非在万不得已的情况下。从可用性的角度来看,始终使用操作系统自带的控件是最有意义的。您的用户已经熟悉操作系统的原生控件,因此创建自定义控件只会增加您应用程序的学习难度。但话又说回来。有时,有些控件就是会让人想写,无论它们是否有用。
这就是我决定编写这个七段数码管控件的原因:不是因为它比标准的 Label 控件“有用”,而是因为它看起来棒极了。我还编写了这个控件,以更好地熟悉 C# 和 .NET 的内部工作原理。而且,如果您喜欢这个控件,并且能够使用它,或者从中学习,那就更好了。
背景
即使您以前没有听说过“七段数码管显示屏”这个名字,您一生中也可能见过不少。它们出现在几乎所有需要显示数字的电子设备上,例如微波炉上的定时器、CD 播放器上的显示屏,或者您的数字手表上的时间。
它们被称为七段数码管显示屏,是因为它们实际上由七个“段”组成——七个单独的灯(LED 或其他)以不同的图案点亮,代表十个数字(0-9)。
使用代码
您可以通过简单地将 "SevenSegment.cs" 文件包含在项目中来将此自定义控件构建到您的应用程序中。重新生成项目,您就可以从工具面板中选择 SevenSegment
控件,并将其直接拖放到您的窗体上。
为了复制七段数码管显示屏的外观,我绘制了七个精确匹配真实显示屏物理布局的多边形。为了建模这些多边形,我将它们绘制在方格纸上,并记录了每个多边形中每个点的坐标。为了在控件上绘制这些多边形,我使用了 FillPolygon
函数,并将代表多边形的点数组传递给它。让我们检查一下控件的 Paint
事件,看看具体发生了什么。
private void SevenSegment_Paint(object sender, PaintEventArgs e)
{
//this will be the bit pattern that gets shown on the segments,
//bits 0 through 6 corresponding to each segment.
int useValue = customPattern;
//create brushes that represent the lit
//and unlit states of the segments
Brush brushLight = new SolidBrush(colorLight);
Brush brushDark = new SolidBrush(colorDark);
//Define transformation for our container...
RectangleF srcRect = new RectangleF(0.0F, 0.0F,
gridWidth, gridHeight);
RectangleF destRect = new RectangleF(Padding.Left, Padding.Top,
this.Width - Padding.Left - Padding.Right,
this.Height - Padding.Top - Padding.Bottom);
//Begin graphics container that remaps
//coordinates for our convenience
GraphicsContainer containerState =
e.Graphics.BeginContainer(destRect, srcRect,
GraphicsUnit.Pixel);
//apply a shear transformation based on our "italics" coefficient
Matrix trans = new Matrix();
trans.Shear(italicFactor, 0.0F);
e.Graphics.Transform = trans;
//apply antialiasing
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.PixelOffsetMode = PixelOffsetMode.Default;
// Draw elements based on whether the corresponding bit is high!
// "segPoints" is a 2D array of points that
// contains the segment coordinates to draw
e.Graphics.FillPolygon((useValue & 0x1) == 0x1 ?
brushLight : brushDark, segPoints[0]);
e.Graphics.FillPolygon((useValue & 0x2) == 0x2 ?
brushLight : brushDark, segPoints[1]);
e.Graphics.FillPolygon((useValue & 0x4) == 0x4 ?
brushLight : brushDark, segPoints[2]);
e.Graphics.FillPolygon((useValue & 0x8) == 0x8 ?
brushLight : brushDark, segPoints[3]);
e.Graphics.FillPolygon((useValue & 0x10) == 0x10 ?
brushLight : brushDark, segPoints[4]);
e.Graphics.FillPolygon((useValue & 0x20) == 0x20 ?
brushLight : brushDark, segPoints[5]);
e.Graphics.FillPolygon((useValue & 0x40) == 0x40 ?
brushLight : brushDark, segPoints[6]);
//draw the decimal point, if it's enabled
if (showDot)
e.Graphics.FillEllipse(dotOn ? brushLight : brushDark,
gridWidth - 1, gridHeight - elementWidth + 1,
elementWidth, elementWidth);
//finished with coordinate container
e.Graphics.EndContainer(containerState);
}
您可以通过两个属性设置控件中显示的值:Value
和 CustomPattern
。Value
属性是一个字符串值,可以设置为单个字符,例如“5”或“A”。该字符将自动转换为看起来像指定字符的七段位模式。
如果您想显示一个自定义模式,该模式可能看起来像任何字母或数字,也可能不像,您可以使用 CustomPattern
属性并将其设置为 0 到 127 之间的任何值,这让您可以完全控制每个段,因为位 0 到 6 控制相应段的状态。
代码中的实现方式如下。我有一个枚举,它编码了所有预定义的值,这些值代表可以在七段数码管上显示的数字和字母。
public enum ValuePattern
{
None = 0x0, Zero = 0x77, One = 0x24, Two = 0x5D, Three = 0x6D,
Four = 0x2E, Five = 0x6B, Six = 0x7B, Seven = 0x25,
Eight = 0x7F, Nine = 0x6F, A = 0x3F, B = 0x7A, C = 0x53,
D = 0x7C, E = 0x5B, F = 0x1B, G = 0x73, H = 0x3E,
J = 0x74, L = 0x52, N = 0x38, O = 0x78,
P = 0x1F, Q = 0x2F, R = 0x18,
T = 0x5A, U = 0x76, Y = 0x6E,
Dash = 0x8, Equals = 0x48
}
请注意,每个值都是一个位图,其中每个位对应于七个段中的一个。现在,在 Value
属性的 set
块中,我将给定的字符与我们已知的值进行比较,并使用相应的枚举作为当前显示的位模式。
//is it a digit?
int tempValue = Convert.ToInt32(value);
switch (tempValue)
{
case 0: customPattern = (int)ValuePattern.Zero; break;
case 1: customPattern = (int)ValuePattern.One; break;
...
}
...
//is it a letter?
string tempString = Convert.ToString(value);
switch (tempString.ToLower()[0])
{
case 'a': customPattern = (int)ValuePattern.A; break;
case 'b': customPattern = (int)ValuePattern.B; break;
...
}
无论哪种方式,要显示在控件中的位模式最终会存储在 customPattern
变量中,该变量然后在 Paint
事件中如上所示使用。
您还可以通过操作 ItalicFactor
属性来“斜体化”显示。该值只是一个剪切因子,在绘制控件时应用,如 Paint
事件所示。-0.1 的斜体因子使显示效果稍微倾斜,看起来专业得多。
如果您开始注意到段绘制超出了控件的边界(可能是由于过多的斜体化),您可以使用 Padding
属性并增加左/右/上/下填充,直到所有形状都在控件的客户区矩形内。
该控件还有其他几个方便的属性供您使用,例如背景颜色、段的启用和禁用颜色以及段的粗细。
七段数码管阵列
除了七段数码管控件本身,我还附带了另一个控件,它是一个数组,包含多个七段数码管显示屏。这允许您在 7 段数码管阵列上显示整个字符串。查看演示应用程序,并深入研究源代码,了解如何使用它;它真的很简单。
要使用阵列控件,请将 "SevenSegmentArray.cs" 文件包含在您的项目中并重新生成。然后,您将能够从工具面板中选择 SevenSegmentArray
控件。
此控件有一个 ArrayCount
属性,用于指定阵列中 7 段数码管显示屏的数量,以及一个 Value
属性,该属性接受任何字符串在阵列上显示。很简单,对吧?
关注点
我必须说,我在编写这个控件的过程中感到非常有趣,而 .NET 通过使其绘制自己的形状、转换坐标和引入真正强大的属性变得异常简单,为我带来了很多乐趣。
此外,我有一些电子背景,对我来说,看到这个控件能唤起对简单时光的怀旧之情。希望您喜欢它。
历史
- 更新 GitHub 代码链接(2017 年 8 月)。
- 小更新:2009 年 7 月 2 日。
- 首次修订:2009 年 6 月 30 日。