LED VU 表用户控件






4.40/5 (13投票s)
2005 年 1 月 18 日
4分钟阅读

164108

8607
一个用 C# 编写的 LED 音量计 Windows 用户控件。
引言
在研究一个用于开发圆形 3D 按钮的小项目时,我偶然发现了非常出色的 Bob Powell 网站。在那里,我学到了关于 PathGradientBrush
的所有知识。经过大量的思考,我设法掌握了 Matrix
和 Transform
的基本原理。虽然我曾考虑过编写自己的 TrackBar
控件,但发现别人已经做过了,于是我决定利用我新获得的知识,尝试创建一个 LED 音量计,就像 PC 和 Mac 音乐录音系统中的那样。正如通常情况一样,它比我最初想的要容易。它完全不进行数字信号处理,所以对于任何希望它能做到这一点的朋友,我深表歉意,但我认为它看起来非常漂亮,因此成为了我提交给 CodeProject 的第一个主题。
代码
该控件继承自 System.Windows.Forms.UserControl
,并重写了 OnPaint
方法。简而言之,我们调整每个 LED 的大小,使其十五个 LED 能很好地适应控件的大小,为它们构建一个 3D 边框,并根据 Volume
属性使用 PathGradientBrush
点亮它们。
有十五个 LED,每个 LED 使用三种颜色。颜色 1 是“未点亮”状态的周围颜色,颜色 2 是“未点亮”状态的中心颜色 *并且* 是“已点亮”状态的周围颜色,颜色 3 是“已点亮”状态的中心颜色。我在 ledColours
数组中设置了这些颜色。
// Array of LED colours Unlit surround Lit surround Lit centre
// Unlit centre
Color[] ledColours =
new Color[] {Color.DarkRed, Color.Red, Color.White,
Color.DarkRed, Color.Red, Color.White,
Color.DarkRed, Color.Red, Color.White,
Color.DarkGoldenrod, Color.Orange, Color.White,
Color.DarkGoldenrod, Color.Orange, Color.White,
Color.DarkGoldenrod, Color.Orange, Color.White,
Color.DarkGoldenrod, Color.Orange, Color.White,
Color.DarkGreen, Color.Green, Color.White,
Color.DarkGreen, Color.Green, Color.White,
Color.DarkGreen, Color.Green, Color.White,
Color.DarkGreen, Color.Green, Color.White,
Color.DarkGreen, Color.Green, Color.White,
Color.DarkGreen, Color.Green, Color.White,
Color.DarkGreen, Color.Green, Color.White,
Color.DarkGreen, Color.Green, Color.White};
这可能不是最优雅的实现方式,但它有效,并且可以轻松更改颜色,尽管有点繁琐。更细心的读者无疑会注意到“点亮的中心”总是白色的,我本可以缩小数组大小并在代码中直接引用 Color.White
,但这样一来,如果白色不适合用户选择的周围颜色,就可以方便地更改“点亮的中心”颜色。
DrawLeds
方法首先根据控件的大小计算每个 LED 的大小。高度的计算方式是让十五个 LED 能够容纳,每个 LED 之间有两像素的间隙。
// Rectangle values for each individual LED - fit them nicely inside the border
int ledLeft = this.ClientRectangle.Left + 3;
int ledTop = this.ClientRectangle.Top + 3;
int ledWidth = this.ClientRectangle.Width - 6;
int ledHeight = this.ClientRectangle.Height / ledCount -2 ;
// Create the LED rectangle
Rectangle ledRect = new Rectangle(ledLeft, ledTop, ledWidth, ledHeight);
接下来,我们创建 GraphicsPath
,将我们的 ledRect
矩形添加到其中,并创建一个 PathGradientBrush
来与之一起使用。
GraphicsPath gp = new GraphicsPath(); // Create Graphics Path
gp.AddRectangle(ledRect); // Add the rectangle
PathGradientBrush pgb = new PathGradientBrush(gp); // Nice brush for shiny LEDs
然后我们循环遍历每个 LED。正如代码注释中所解释的那样,循环包含升序和降序索引。对于每个 LED,我们通过比较 j
的值与 ledVal
(由“Volume
”属性设置)的值来确定它是否被点亮。如果我们的 LED 小于或等于音量,我们就点亮它。(如果它等于 peakVal
变量,我们也会点亮它,稍后会详细介绍。)一旦我们知道是否点亮这个 LED,我们就从 ledColours
数组中选择“未点亮的周围”和“未点亮的中心”,或者“点亮的周围”和“点亮的中心”颜色。这是通过基于 i
值的简单计算实现的。
// Light the LED if it's under current value, or if it's the peak value.
if ((j <= ledVal) | (j == peakVal))
{
pgb.CenterColor=ledColours[i*3+2];
pgb.SurroundColors=new Color[]{ledColours[i*3+1]};
}
// Otherwise, do not light it
else
{
pgb.CenterColor=ledColours[i*3+1];
pgb.SurroundColors=new Color[]{ledColours[i*3]};
}
// Light LED fom the centre.
pgb.CenterPoint=new PointF(ledRect.X + ledRect.Width/2,
ledRect.Y + ledRect.Height/2);
现在是酷炫的部分。我们创建一个 Matrix
并使用它的 Translate
方法根据 i
的值有效地改变 ledRect.X
的值。然后,我们将我们 Graphics
实例的 Transform
属性设置为我们的 Matrix
,即 mx
,将当前 LED 向下移动。我在 Mahesh Shand 这里的帮助下弄清楚了如何做到这一点。然后,我们用我们信赖的 PathGradientBrush
填充 LED。
// Use a matrix to move the LED graphics down according to the value of i
Matrix mx = new Matrix();
mx.Translate(0, i * (ledHeight + 2));
g.Transform=mx;
g.FillRectangle(pgb, ledRect);
一旦我们绘制了所有的 LED,我们就必须将 Graphics
实例重置到其原始偏移量,以便在正确的位置绘制边框。
// Translate back to original position to draw the border
Matrix mx1 = new Matrix();
mx1.Translate(0, 0);
g.Transform = mx1;
我认为最好的部分是实现了峰值指示器。这意味着达到最高级别的 LED 会保持点亮一段时间。这是通过以下方式实现的。
首先,Volume
属性中的这段代码会确定最新值是否高于先前保存的峰值。如果是,它会将其保存在 peakVal
中。同时,计时器会启动。
// New peak value
if (ledVal > peakVal)
{
peakVal = ledVal;
timer1.Enabled = true; // Tell the peak indicator to stay
}
峰值将保持不变,直到它被超过,或者直到计时器间隔过去,此时它将重置为零,LED 将熄灭。
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Enabled = false; // Tell the peak indicator to go
peakVal = 0; //
this.Invalidate();
}
使用代码
使用它非常简单——示例应用程序展示了如何使用。如果将 vuMeterLED.dll 包含在您的项目中,您应该能够将该控件拖到您的窗体上。如果您下载了源代码,请注意,我只包含了 vuMeterLED.cs、Form1.cs 和 AssemblyInfo.cs 文件。这是因为我使用 SharpDevelop 开发了代码,而且我不知道项目文件是否能被 VS 读取。
就这样了!感谢您阅读到这里,希望它对某人有所帮助或有所启发。
接下来呢?
嗯,这个控件需要一个刻度,这不应该太难绘制。更具挑战性的是开发一个带有指针的模拟风格仪表。我正在考虑……