65.9K
CodeProject 正在变化。 阅读更多。
Home

LED VU 表用户控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.40/5 (13投票s)

2005 年 1 月 18 日

4分钟阅读

viewsIcon

164108

downloadIcon

8607

一个用 C# 编写的 LED 音量计 Windows 用户控件。

Four vuMeters in freeze-frame action...

引言

在研究一个用于开发圆形 3D 按钮的小项目时,我偶然发现了非常出色的 Bob Powell 网站。在那里,我学到了关于 PathGradientBrush 的所有知识。经过大量的思考,我设法掌握了 MatrixTransform 的基本原理。虽然我曾考虑过编写自己的 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.csForm1.csAssemblyInfo.cs 文件。这是因为我使用 SharpDevelop 开发了代码,而且我不知道项目文件是否能被 VS 读取。

就这样了!感谢您阅读到这里,希望它对某人有所帮助或有所启发。

接下来呢?

嗯,这个控件需要一个刻度,这不应该太难绘制。更具挑战性的是开发一个带有指针的模拟风格仪表。我正在考虑……

© . All rights reserved.