自定义七段LED显示控制的探索

在软件开发中,操作系统提供的原生控件通常是最符合用户习惯的选择。它们不仅易于使用,而且用户已经熟悉了这些控件的操作方式,因此,除非在极端情况下,通常不需要创建自定义控件。然而,有时候,某些控件的设计让人忍不住想要尝试编写它们,哪怕它们并非那么“实用”。

这就是决定编写这个七段LED控制的原因:它看起来非常酷,而且通过编写这个控制,能够更熟悉C#.NET的内部机制。如果喜欢这个控制,并且能够使用它,或者从中学到东西,那就更好了。

即使以前没有听说过“七段显示”这个名字,也可能在很多电子设备上看到过它,比如微波炉上的计时器、CD播放器上的显示屏,或者数字手表上的时间显示。它们之所以被称为七段显示,是因为它们由七个“段”组成——七个单独的灯(LED或其他类型)以不同的模式点亮,代表0到9的任何一个数字。

使用代码

要将这个自定义控制集成到应用程序中,只需将"SevenSegment.cs"文件包含到项目中。重新构建项目,将能够在工具面板中选择SevenSegment控制,并将其直接拖放到表单上。

为了模仿七段显示的外观,绘制了七个多边形,精确匹配真实显示的物理布局。为了模拟这些多边形,在坐标纸上绘制了它们,并记录了每个多边形的每个点的坐标。在控制上绘制多边形时,使用了FillPolygon函数,传递给它代表多边形的点数组。让来检查一下控制的Paint事件,看看到底发生了什么:

private void SevenSegment_Paint(object sender, PaintEventArgs e) { // 这将是显示在段上的位模式, // 位0到6对应每个段。 int useValue = customPattern; // 创建代表点亮和未点亮状态的画刷 Brush brushLight = new SolidBrush(colorLight); Brush brushDark = new SolidBrush(colorDark); // 定义容器的变换... 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); // 开始图形容器,重新映射坐标,以方便 GraphicsContainer containerState = e.Graphics.BeginContainer(destRect, srcRect, GraphicsUnit.Pixel); // 根据“斜体”系数应用剪切变换 Matrix trans = new Matrix(); trans.Shear(italicFactor, 0.0F); e.Graphics.Transform = trans; // 应用抗锯齿 e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; e.Graphics.PixelOffsetMode = PixelOffsetMode.Default; // 根据相应位是高还是低来绘制元素! // "segPoints"是一个二维数组的点,包含要绘制的段坐标 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]); // 如果启用了,绘制小数点 if (showDot) e.Graphics.FillEllipse(dotOn ? brushLight : brushDark, gridWidth - 1, gridHeight - elementWidth + 1, elementWidth, elementWidth); // 完成坐标容器 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属性的setter中,将给定的字符与已知值进行比较,并使用相应的枚举作为当前显示的位模式:

// 是数字吗? int tempValue = Convert.ToInt32(value); switch (tempValue) { case 0: customPattern = (int)ValuePattern.Zero; break; case 1: customPattern = (int)ValuePattern.One; break; ... } ... // 是字母吗? 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通过使绘制自己的形状、转换坐标和引入真正强大的属性变得非常容易,增加了很多乐趣。

另外,由于有一点电子背景,对来说,看到这个控制带来了对更简单时代的某种怀旧。希望能喜欢它。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485