LED 字体创建器(带滚动显示)






4.75/5 (19投票s)
带字符编辑器的 LED 显示器。
引言
通过这个控件,我试图解决一个我们非英语母语者都面临的常见问题。我所见过的所有 LED、LCD、七段数码管控件都只支持 7 位 ASCII 字符集。所以,对于所有希望拥有自己特定字符或符号的人来说,我都添加了一个字符编辑器。我受到了 Liu Xia 的另一个 LED 控件 一个漂亮的七段 LED 控件 的启发,从中我还借用了一些东西,例如 ISupportInitialize
。
背景
互联网上有一些相当不错的免费 LED 字体,例如 Andreas Nylin 的 Ozone 和 Ritchie Ned Hansel 的 AI pointe。Al pointe 使用 5x7 矩阵,一种漂亮的浅色字体,而 Ozone 使用更粗的 6x8 矩阵。看看并获得灵感,创建你自己的字体。您可以随意使用 4x4(从未尝试过)到 8x8、5x7、6x10 或任何乘积小于等于 64 的范围。
矩阵存储在一个 ulong
中,最多可容纳 64 位。

Using the Code
此控件只有几个特定的公共属性,两个用于更改字体外观,三个用于滚动。除此之外,你当然可以更改 ForeColor
和 BackColor
,它们也支持透明度。你创建的字体存储在一个 Dictionary key=char, value=bits
中,并使用以下方法保存到你文档目录中的 XML 文件中:
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\LedFont.xml";
这是因为该文件在设计模式和运行时都需要,这在“注意事项”中有所解释。创建的文件包含字符及其二进制矩阵,表示为一个 ulong
,例如字符 char="A" bits="227873781661662"
,这在二进制中转换为 “0000 0000 0000 0000 1100 1111 0011 1111 1111 1111 1100 1111 0011 1111 1101 1110”
。
如果你从右边读,你可以在编辑器中从左上角开始逐位匹配。
通过更改常量 HSEGMENTS
和 VSEGMENTS
,还可以更改矩阵的布局,目前是 6x8。
但请务必备份你之前使用的字体文件,然后再开始使用新的字体,否则如果矩阵与你的字体不匹配,将会出现混乱。
由于字体不是位图,因此它是可自由缩放的,到目前为止,我已测试了 16 像素高到 120 像素高的字体。当然,字体越大,CPU 负载就越高。
我包含了一个 LedFont.xml 文件,其中包含大写字母和数字,如果你想开始使用的话。
只需记住将此文件复制到你的文档文件夹。
公共属性
SegmentSpace
- 段之间的间距,占段大小的百分比CharSpace
- 字符之间的间距,占字符大小的百分比Scroll
-true
或false
,是否滚动ScrollDelay
- 移动之间的延迟(以毫秒为单位)ScrollStep
- 按像素或段滚动
公共方法
-
public bool FindChar(char chr)
检查字典中是否存在字符
-
public void AddChar(char chr, ulong bits)
向字典添加一个字符,如果存在则替换旧的
-
public void RemoveChar(char chr)
如果字符存在于字典中,则移除该字符
-
public ulong GetValue(char chr)
获取字符的值
-
public ArrayList GetKeys()
获取字典中字符的列表
-
public void DrawChar(ulong bits, Graphics g, Rectangle rect)
在指定矩形内将单个
char
绘制到图形对象上 -
public void DrawString(string str, Graphics g, Rectangle rect)
在指定矩形内将
string
绘制到图形对象上
通常你不会直接使用这些方法,因为它们是由 Text
属性调用的,而 Text
属性本身又调用 DrawString
方法。当 Text
属性更改、大小更改、颜色更改和间距更改时,会调用 DrawString
方法。DrawChar
通过一次性屏蔽位来使用 ulong
位,并在不为零时绘制 LED。
public void DrawString(string str, Graphics g, Rectangle rect)
{
ulong bits;
if (str != null && str.Length > 0)
{
int width = Convert.ToInt32(this.Height / VSEGMENTS * HSEGMENTS);
// position for next character
int pos = (int) (width + width * charSpace);
for (int i = 0; i < str.Length; i++)
{
segDict.TryGetValue(str[i], out bits);
rect = new Rectangle(pos * i, 0, width, rect.Height);
DrawChar(bits, g, rect);
}
}
}
public void DrawChar(ulong bits, Graphics g, Rectangle rect)
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
float size = rect.Height / VSEGMENTS; // height and width makes a square
float space = (size * segmentSpace) / 2; // space between segments
using (SolidBrush segmentBrush = new SolidBrush(ForeColor))
{
for (int y = 0; y < VSEGMENTS; y++) // vertical row
{
for (int x = 0; x < HSEGMENTS; x++) // horizontal row
{
if ((bits & 1) != 0)// if bit 1 is set, fill segment
{
RectangleF segmentRect =
new RectangleF(rect.X + x * size,
y * size, size, size);
// do not inflate to zero
if ((space * 2) < size)
segmentRect.Inflate
(-space, -space);
g.FillEllipse(segmentBrush,
segmentRect);
}
// roll bits to the right
bits = bits >> 1;
}
}
}
}
关注点
在使用 XML 文件存储字符定义时,我发现了一件事。为了在设计模式下使用该文件(我必须这样做),我无法使用常见的 Application.StartupPath
,因为当你存储数据时通常会这样做,因为在设计模式下该路径会更改为 Visual Studio 的目录!最简单的解决方案是使用文档文件夹,使其在两种模式下都可用,但你可以随意更改。另一件事是 System.Timer.Timer
和 Windows.Forms.Timer
相当不准确。这使得计时器滴答声会根据计算机正在执行的其他操作而变化。在我的普通计算机上,我也无法获得低于 15 毫秒的滴答率。
历史
- 2008 年 9 月 17 日:初始版本