/****************************************************************************** * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。 * CopyRight (C) 2012-2025 ShenYongHua(沈永华). * QQ群:56829229 QQ:17612584 EMail:SunnyUI@QQ.Com * * Blog: https://www.cnblogs.com/yhuse * Gitee: https://gitee.com/yhuse/SunnyUI * GitHub: https://github.com/yhuse/SunnyUI * * SunnyUI can be used for free under the GPL-3.0 license. * If you use this code, please keep this note. * 如果您使用此代码,请保留此说明。 ****************************************************************************** * 文件名称: UILedBulb.cs * 文件说明: LED灯 * 文件作者: Steve Marsh * 开源协议: CPOL * 引用地址: https://www.codeproject.com/Articles/114122/A-Simple-Vector-Based-LED-User-Control ******************************************************************************/ using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; #pragma warning disable 1591 namespace Sunny.UI { /// /// The LEDBulb is a .Net control for Windows Forms that emulates an /// LED light with two states On and Off. The purpose of the control is to /// provide a sleek looking representation of an LED light that is sizable, /// has a transparent background and can be set to different colors. /// public class UILedBulb : Control, IZoomScale { #region Public and Private Members private Color _color; private bool _on = true; private readonly Color _reflectionColor = Color.FromArgb(180, 255, 255, 255); private readonly Color[] _surroundColor = new Color[] { Color.FromArgb(0, 255, 255, 255) }; private readonly Timer timer; /// /// 禁止控件跟随窗体缩放 /// [DefaultValue(false), Category("SunnyUI"), Description("禁止控件跟随窗体缩放")] public bool ZoomScaleDisabled { get; set; } /// /// 控件缩放前在其容器里的位置 /// [Browsable(false), DefaultValue(typeof(Rectangle), "0, 0, 0, 0")] public Rectangle ZoomScaleRect { get; set; } /// /// 设置控件缩放比例 /// /// 缩放比例 public void SetZoomScale(float scale) { } protected override void Dispose(bool disposing) { base.Dispose(disposing); timer?.Stop(); timer?.Dispose(); } /// /// Gets or Sets the color of the LED light /// [DefaultValue(typeof(Color), "192, 255, 192")] public Color Color { get { return _color; } set { _color = value; DarkColor = ControlPaint.Dark(_color); DarkDarkColor = ControlPaint.DarkDark(_color); Invalidate(); // Redraw the control } } /// /// Dark shade of the LED color used for gradient /// [Browsable(false)] public Color DarkColor { get; protected set; } /// /// Very dark shade of the LED color used for gradient /// [Browsable(false)] public Color DarkDarkColor { get; protected set; } /// /// Gets or Sets whether the light is turned on /// [DefaultValue(true)] public bool On { get { return _on; } set { _on = value; Invalidate(); } } #endregion Public and Private Members #region Constructor public UILedBulb() { SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.UserPaint | ControlStyles.SupportsTransparentBackColor, true); Width = Height = 32; Color = Color.FromArgb(192, 255, 192); timer = new Timer(); timer.Tick += (sender, e) => { On = !On; }; } #endregion Constructor #region Methods /// /// 重载绘图 /// /// 绘图参数 protected override void OnPaint(PaintEventArgs e) { // Create an offscreen graphics object for double buffering using Bitmap offScreenBmp = new Bitmap(ClientRectangle.Width, ClientRectangle.Height); using var g = Graphics.FromImage(offScreenBmp); g.SetHighQuality(); // Draw the control drawControl(g, On); // Draw the image to the screen e.Graphics.DrawImageUnscaled(offScreenBmp, 0, 0); } /// /// Renders the control to an image /// private void drawControl(Graphics g, bool on) { // Is the bulb on or off Color lightColor = (on) ? Color : Color.FromArgb(150, DarkColor); Color darkColor = (on) ? DarkColor : DarkDarkColor; // Calculate the dimensions of the bulb int width = Width - (Padding.Left + Padding.Right); int height = Height - (Padding.Top + Padding.Bottom); // Diameter is the lesser of width and height int diameter = Math.Min(width, height); // Subtract 1 pixel so ellipse doesn't get cut off diameter = Math.Max(diameter - 1, 1); // Draw the background ellipse var rectangle = new Rectangle(Padding.Left, Padding.Top, diameter, diameter); g.FillEllipse(darkColor, rectangle); // Draw the glow gradient using var path = new GraphicsPath(); path.AddEllipse(rectangle); using var pathBrush = new PathGradientBrush(path); pathBrush.CenterColor = lightColor; pathBrush.SurroundColors = new[] { Color.FromArgb(0, lightColor) }; g.SetHighQuality(); g.FillEllipse(pathBrush, rectangle); // Draw the white reflection gradient var offset = Convert.ToInt32(diameter * .15F); var diameter1 = Convert.ToInt32(rectangle.Width * .8F); var whiteRect = new Rectangle(rectangle.X - offset, rectangle.Y - offset, diameter1, diameter1); using var path1 = new GraphicsPath(); path1.AddEllipse(whiteRect); using var pathBrush1 = new PathGradientBrush(path); pathBrush1.CenterColor = _reflectionColor; pathBrush1.SurroundColors = _surroundColor; g.SetHighQuality(); g.FillEllipse(pathBrush1, whiteRect); // Draw the border g.SetClip(ClientRectangle); g.SetHighQuality(); if (On) { using Pen pn = new Pen(Color.FromArgb(85, Color.Black), 1F); g.DrawEllipse(pn, rectangle); } g.SetDefaultQuality(); } private int blinkInterval = 1000; [DefaultValue(1000)] public int BlinkInterval { get => blinkInterval; set { blinkInterval = Math.Max(100, value); bool isBlink = Blink; if (isBlink) timer.Stop(); timer.Interval = blinkInterval; timer.Enabled = isBlink; } } [DefaultValue(false)] public bool Blink { get => timer.Enabled; set { On = true; timer.Stop(); timer.Interval = BlinkInterval; timer.Enabled = value; } } #endregion Methods } }