开源 C# 快速开发(五)自定义控件--仪表盘

文章的目的为了记录使用C# 开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

相关链接:

开源 C# 快速开发(一)基础知识

开源 C# 快速开发(二)基础控件

开源 C# 快速开发(三)复杂控件

开源 C# 快速开发(四)自定义控件--波形图

开源 C# 快速开发(五)自定义控件--仪表盘

开源 C# 快速开发(六)自定义控件--圆环

开源 C# 快速开发(七)通讯--串口

推荐链接:

开源 C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客

开源 C# .net mvc 开发(三)WEB内外网访问-CSDN博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示-CSDN博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客

开源 C# .net mvc 开发(六)发送邮件、定时以及CMD编程-CSDN博客

开源 C# .net mvc 开发(七)动态图片、动态表格和json数据生成-CSDN博客

开源 C# .net mvc 开发(八)IIS Express轻量化Web服务器的配置和使用-CSDN博客

开源 C# .net mvc 开发(九)websocket--服务器与客户端的实时通信-CSDN博客

本章节主要内容是:编写仪表盘控件从而实现工业仪表的显示。这个仪表盘控件展示了完整的自定义控件开发流程,从图形绘制到用户交互,是一个功能完善的工业级控件实现。

目录:

1.源码分析

2.所有源码

3.效果演示

一、源码分析

分为两个主要部分:DashboardControl 自定义控件和 Form1 测试窗体。

  1. DashboardControl 自定义控件分析

1.1 属性和字段设计

字段定义:

复制代码
private float _minValue = 0;        // 最小值
private float _maxValue = 100;      // 最大值
private float _currentValue = 0;    // 当前值
private float _warningValue = 80;   // 警告阈值
private float _dangerValue = 90;    // 危险阈值

属性封装特点:

所有属性都调用 Invalidate() 方法,实现属性变化时自动重绘

CurrentValue 属性使用 Math.Max 和 Math.Min 进行范围约束

1.2 构造函数关键设置

复制代码
public DashboardControl()
{
    // 双缓冲和控件样式设置
    this.DoubleBuffered = true;
    SetStyle(ControlStyles.AllPaintingInWmPaint |
            ControlStyles.UserPaint |
            ControlStyles.DoubleBuffer |
            ControlStyles.ResizeRedraw |
            ControlStyles.Opaque, true);  // 关键:避免闪烁
}

1.3 核心绘图方法分析

OnPaint 方法 - 主绘制入口

复制代码
protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    Graphics g = e.Graphics;
    g.SmoothingMode = SmoothingMode.AntiAlias;  // 抗锯齿
    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
    
    // 绘制顺序:背景 → 表盘 → 刻度 → 指针 → 文本
}

DrawDial 方法 - 表盘绘制

复制代码
private void DrawDial(Graphics g, RectangleF dialRect)
{
    // 1. 填充表盘底色
    g.FillEllipse(brush, dialRect);
    
    // 2. 创建渐变效果(高光)
    using (PathGradientBrush pgb = new PathGradientBrush(path))
    {
        pgb.CenterColor = Color.FromArgb(100, 255, 255, 255); // 半透明白色
        pgb.SurroundColors = new Color[] { Color.Transparent };
    }
    
    // 3. 绘制彩色区域(正常/警告/危险)
    DrawColorZones(g, dialRect);
    
    // 4. 绘制外边框
    g.DrawEllipse(borderPen, dialRect);
}

DrawColorZones 方法 - 彩色区域绘制

复制代码
private void DrawColorZones(Graphics g, RectangleF dialRect)
{
    float startAngle = 135;    // 起始角度(左下)
    float sweepAngle = 270;    // 扫描角度(270度圆弧)
    
    // 计算各区域角度范围
    float normalSweep = (_warningValue - _minValue) / (_maxValue - _minValue) * sweepAngle;
    float warningSweep = (_dangerValue - _warningValue) / (_maxValue - _minValue) * sweepAngle;
    float dangerSweep = (_maxValue - _dangerValue) / (_maxValue - _minValue) * sweepAngle;
    
    // 分别绘制三个区域
    DrawZone(g, dialRect, startAngle, normalSweep, Color.Green);
    DrawZone(g, dialRect, startAngle + normalSweep, warningSweep, _warningColor);
    DrawZone(g, dialRect, startAngle + normalSweep + warningSweep, dangerSweep, _dangerColor);
}

DrawScales 方法 - 刻度绘制

复制代码
private void DrawScales(Graphics g, RectangleF dialRect)
{
    // 极坐标计算刻度位置
    PointF center = new PointF(dialRect.X + dialRect.Width / 2, dialRect.Y + dialRect.Height / 2);
    float radius = dialRect.Width / 2;
    
    for (int i = 0; i <= majorDivisions; i++)
    {
        // 角度计算(极坐标转直角坐标)
        float angle = startAngle + (sweepAngle / majorDivisions) * i;
        float radian = angle * (float)Math.PI / 180;
        
        // 计算内外端点
        PointF outerPoint = new PointF(
            center.X + radius * (float)Math.Cos(radian),
            center.Y + radius * (float)Math.Sin(radian));
        
        // 绘制主刻度和数值标签
    }
}

DrawPointer 方法 - 指针绘制

  1. Form1 测试窗体分析

2.1 控件初始化

复制代码
private void SetupDashboard()
{
    dashboard = new DashboardControl();
    dashboard.Location = new Point(50, 50);
    dashboard.Size = new Size(400, 400);
    dashboard.Title = "速度表";
    dashboard.Unit = "km/h";
    // ... 属性设置
}

2.2 控制面板构建

窗体右侧创建了完整的控制面板:

控件类型:

NumericUpDown:数值输入控制

TrackBar:滑块控制

ComboBox:颜色选择

Button:操作控制

Label:状态显示

2.3 数据绑定和事件处理

复制代码
// 数值变化同步更新
nudCurrentValue.ValueChanged += delegate {
    dashboard.CurrentValue = (float)nudCurrentValue.Value;
    trbValue.Value = (int)nudCurrentValue.Value;  // 同步滑块
};

// 滑块事件
trbValue.Scroll += delegate {
    dashboard.CurrentValue = trbValue.Value;
    nudCurrentValue.Value = trbValue.Value;  // 同步数值框
};

2.4 定时器模拟功能

复制代码
private void SetupTimer()
{
    updateTimer = new System.Timers.Timer(100);  // 100ms间隔
    updateTimer.Elapsed += OnTimerElapsed;
    updateTimer.SynchronizingObject = this;  // 关键:线程安全
}

private void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
    // 带缓动效果的数值变化
    float targetValue = 50 + (float)(Math.Sin(DateTime.Now.Ticks * 0.0000001) * 70);
    float newValue = currentValue + (targetValue - currentValue) * 0.1f;  // 缓动插值
}
  1. 技术亮点

3.1 图形绘制优化

双缓冲技术:DoubleBuffered = true 避免闪烁

抗锯齿:SmoothingMode.AntiAlias 提升视觉效果

路径渐变:PathGradientBrush 创建立体效果

3.2 数学计算精确

极坐标转换:准确计算刻度和指针位置

角度映射:将数值范围映射到270度圆弧

范围约束:确保数值在有效范围内

3.3 用户体验设计

实时响应:所有属性变化立即重绘

多种控制方式:数值框、滑块、按钮、定时器

状态反馈:实时显示当前状态和数值

二、所有源码

DashboardControl.cs文件源码

复制代码
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace _4_dashboard
{
    public class DashboardControl : Control
    {
        #region 属性和字段

        // 仪表盘设置
        private float _minValue = 0;
        private float _maxValue = 100;
        private float _currentValue = 0;
        private float _warningValue = 80;
        private float _dangerValue = 90;

        // 外观设置 - 修改默认背景色
        private Color _backgroundColor = Color.Black;  // 改为不透明颜色
        private Color _dialColor = Color.FromArgb(30, 30, 30);
        private Color _scaleColor = Color.White;
        private Color _pointerColor = Color.Red;
        private Color _warningColor = Color.Orange;
        private Color _dangerColor = Color.Red;
        private Color _valueColor = Color.White;
        private Color _titleColor = Color.LightGray;

        // 字体
        private Font _valueFont;
        private Font _titleFont;
        private Font _scaleFont;

        // 文本
        private string _title = "仪表盘";
        private string _unit = "单位";

        // 尺寸比例
        private float _dialThickness = 0.1f;
        private float _pointerLength = 0.7f;
        private float _pointerWidth = 0.02f;

        #endregion

        #region 属性公开接口

        public float MinValue
        {
            get { return _minValue; }
            set { _minValue = value; Invalidate(); }
        }

        public float MaxValue
        {
            get { return _maxValue; }
            set { _maxValue = value; Invalidate(); }
        }

        public float CurrentValue
        {
            get { return _currentValue; }
            set
            {
                _currentValue = Math.Max(_minValue, Math.Min(_maxValue, value));
                Invalidate();
            }
        }

        public float WarningValue
        {
            get { return _warningValue; }
            set { _warningValue = value; Invalidate(); }
        }

        public float DangerValue
        {
            get { return _dangerValue; }
            set { _dangerValue = value; Invalidate(); }
        }

        public Color BackgroundColor
        {
            get { return _backgroundColor; }
            set { _backgroundColor = value; Invalidate(); }
        }

        public Color DialColor
        {
            get { return _dialColor; }
            set { _dialColor = value; Invalidate(); }
        }

        public Color PointerColor
        {
            get { return _pointerColor; }
            set { _pointerColor = value; Invalidate(); }
        }

        public Color ScaleColor
        {
            get { return _scaleColor; }
            set { _scaleColor = value; Invalidate(); }
        }

        public string Title
        {
            get { return _title; }
            set { _title = value; Invalidate(); }
        }

        public string Unit
        {
            get { return _unit; }
            set { _unit = value; Invalidate(); }
        }

        public Color WarningColor
        {
            get { return _warningColor; }
            set { _warningColor = value; Invalidate(); }
        }

        public Color DangerColor
        {
            get { return _dangerColor; }
            set { _dangerColor = value; Invalidate(); }
        }

        #endregion

        #region 构造函数

        public DashboardControl()
        {
            // 初始化字体
            _valueFont = new Font("Arial", 16, FontStyle.Bold);
            _titleFont = new Font("Arial", 12);
            _scaleFont = new Font("Arial", 8);

            this.DoubleBuffered = true;
            // 修复:使用不透明的背景色
            this.BackColor = Color.Black;  // 改为不透明颜色
            this.Size = new Size(200, 200);

            // 设置控件样式,确保正确绘制
            SetStyle(ControlStyles.AllPaintingInWmPaint |
                    ControlStyles.UserPaint |
                    ControlStyles.DoubleBuffer |
                    ControlStyles.ResizeRedraw |
                    ControlStyles.Opaque, true);  // 添加 Opaque 样式
        }

        #endregion

        #region 绘图方法

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;

            // 先清除背景
            using (SolidBrush backgroundBrush = new SolidBrush(_backgroundColor))
            {
                g.FillRectangle(backgroundBrush, this.ClientRectangle);
            }

            // 计算仪表盘尺寸和位置
            int size = Math.Min(Width, Height) - 20;
            if (size <= 0) return;  // 添加安全检查

            int x = (Width - size) / 2;
            int y = (Height - size) / 2;
            RectangleF dialRect = new RectangleF(x, y, size, size);

            // 绘制表盘
            DrawDial(g, dialRect);

            // 绘制刻度
            DrawScales(g, dialRect);

            // 绘制指针
            DrawPointer(g, dialRect);

            // 绘制数值和标题
            DrawText(g, dialRect);
        }

        private void DrawDial(Graphics g, RectangleF dialRect)
        {
            // 绘制表盘底色
            using (SolidBrush brush = new SolidBrush(_dialColor))
            {
                g.FillEllipse(brush, dialRect);
            }

            // 绘制渐变效果
            using (GraphicsPath path = new GraphicsPath())
            {
                path.AddEllipse(dialRect);
                using (PathGradientBrush pgb = new PathGradientBrush(path))
                {
                    pgb.CenterPoint = new PointF(
                        dialRect.X + dialRect.Width * 0.3f,
                        dialRect.Y + dialRect.Height * 0.3f);
                    pgb.CenterColor = Color.FromArgb(100, 255, 255, 255);
                    pgb.SurroundColors = new Color[] { Color.Transparent };
                    g.FillEllipse(pgb, dialRect);
                }
            }

            // 绘制刻度区域(彩色圆弧)
            DrawColorZones(g, dialRect);

            // 绘制外边框
            using (Pen borderPen = new Pen(Color.FromArgb(100, 255, 255, 255), 2f))
            {
                g.DrawEllipse(borderPen, dialRect);
            }
        }

        private void DrawColorZones(Graphics g, RectangleF dialRect)
        {
            float startAngle = 135;
            float sweepAngle = 270;

            // 检查除零错误
            if (_maxValue - _minValue <= 0) return;

            // 正常区域(绿色)
            float normalSweep = (_warningValue - _minValue) / (_maxValue - _minValue) * sweepAngle;
            if (normalSweep > 0)
                DrawZone(g, dialRect, startAngle, normalSweep, Color.Green);

            // 警告区域(橙色)
            float warningSweep = (_dangerValue - _warningValue) / (_maxValue - _minValue) * sweepAngle;
            if (warningSweep > 0)
                DrawZone(g, dialRect, startAngle + normalSweep, warningSweep, _warningColor);

            // 危险区域(红色)
            float dangerSweep = (_maxValue - _dangerValue) / (_maxValue - _minValue) * sweepAngle;
            if (dangerSweep > 0)
                DrawZone(g, dialRect, startAngle + normalSweep + warningSweep, dangerSweep, _dangerColor);
        }

        private void DrawZone(Graphics g, RectangleF dialRect, float startAngle, float sweepAngle, Color color)
        {
            if (sweepAngle <= 0) return;

            float penWidth = dialRect.Width * _dialThickness;
            if (penWidth <= 0) return;

            RectangleF zoneRect = new RectangleF(
                dialRect.X + penWidth / 2,
                dialRect.Y + penWidth / 2,
                dialRect.Width - penWidth,
                dialRect.Height - penWidth);

            using (Pen zonePen = new Pen(color, penWidth))
            {
                zonePen.StartCap = LineCap.Round;
                zonePen.EndCap = LineCap.Round;
                g.DrawArc(zonePen, zoneRect, startAngle, sweepAngle);
            }
        }

        private void DrawScales(Graphics g, RectangleF dialRect)
        {
            float startAngle = 135;
            float sweepAngle = 270;
            int majorDivisions = 10;
            int minorDivisions = 5;

            float penWidth = dialRect.Width * 0.01f;
            float majorTickLength = dialRect.Width * 0.05f;
            float minorTickLength = dialRect.Width * 0.025f;

            using (Pen majorPen = new Pen(_scaleColor, penWidth * 2))
            using (Pen minorPen = new Pen(_scaleColor, penWidth))
            using (SolidBrush textBrush = new SolidBrush(_scaleColor))
            {
                PointF center = new PointF(dialRect.X + dialRect.Width / 2, dialRect.Y + dialRect.Height / 2);
                float radius = dialRect.Width / 2;

                for (int i = 0; i <= majorDivisions; i++)
                {
                    float angle = startAngle + (sweepAngle / majorDivisions) * i;
                    float radian = angle * (float)Math.PI / 180;

                    // 主刻度
                    PointF outerPoint = new PointF(
                        center.X + radius * (float)Math.Cos(radian),
                        center.Y + radius * (float)Math.Sin(radian));
                    PointF innerPoint = new PointF(
                        center.X + (radius - majorTickLength) * (float)Math.Cos(radian),
                        center.Y + (radius - majorTickLength) * (float)Math.Sin(radian));

                    g.DrawLine(majorPen, outerPoint, innerPoint);

                    // 主刻度数值
                    float value = _minValue + (_maxValue - _minValue) * i / majorDivisions;
                    string text = value.ToString("F0");
                    SizeF textSize = g.MeasureString(text, _scaleFont);

                    PointF textPoint = new PointF(
                        center.X + (radius - majorTickLength - textSize.Height) * (float)Math.Cos(radian) - textSize.Width / 2,
                        center.Y + (radius - majorTickLength - textSize.Height) * (float)Math.Sin(radian) - textSize.Height / 2);

                    g.DrawString(text, _scaleFont, textBrush, textPoint);

                    // 次刻度
                    if (i < majorDivisions)
                    {
                        for (int j = 1; j < minorDivisions; j++)
                        {
                            float minorAngle = angle + (sweepAngle / majorDivisions / minorDivisions) * j;
                            float minorRadian = minorAngle * (float)Math.PI / 180;

                            PointF minorOuter = new PointF(
                                center.X + radius * (float)Math.Cos(minorRadian),
                                center.Y + radius * (float)Math.Sin(minorRadian));
                            PointF minorInner = new PointF(
                                center.X + (radius - minorTickLength) * (float)Math.Cos(minorRadian),
                                center.Y + (radius - minorTickLength) * (float)Math.Sin(minorRadian));

                            g.DrawLine(minorPen, minorOuter, minorInner);
                        }
                    }
                }
            }
        }

        private void DrawPointer(Graphics g, RectangleF dialRect)
        {
            PointF center = new PointF(dialRect.X + dialRect.Width / 2, dialRect.Y + dialRect.Height / 2);
            float radius = dialRect.Width / 2;

            // 计算指针角度
            float normalizedValue = (_currentValue - _minValue) / (_maxValue - _minValue);
            float angle = 135 + normalizedValue * 270;
            float radian = angle * (float)Math.PI / 180;

            // 指针长度
            float pointerLength = radius * _pointerLength;
            float pointerWidth = radius * _pointerWidth;

            // 指针端点
            PointF tipPoint = new PointF(
                center.X + pointerLength * (float)Math.Cos(radian),
                center.Y + pointerLength * (float)Math.Sin(radian));

            // 指针两侧点
            float perpendicularRadian = radian + (float)Math.PI / 2;
            PointF side1 = new PointF(
                center.X + pointerWidth * (float)Math.Cos(perpendicularRadian),
                center.Y + pointerWidth * (float)Math.Sin(perpendicularRadian));
            PointF side2 = new PointF(
                center.X - pointerWidth * (float)Math.Cos(perpendicularRadian),
                center.Y - pointerWidth * (float)Math.Sin(perpendicularRadian));

            // 绘制指针
            using (GraphicsPath path = new GraphicsPath())
            {
                path.AddLine(side1, tipPoint);
                path.AddLine(tipPoint, side2);
                path.CloseFigure();

                using (SolidBrush brush = new SolidBrush(_pointerColor))
                {
                    g.FillPath(brush, path);
                }

                // 指针边框
                using (Pen borderPen = new Pen(Color.DarkRed, pointerWidth * 0.3f))
                {
                    g.DrawPath(borderPen, path);
                }
            }

            // 绘制中心点
            float centerSize = pointerWidth * 2;
            using (SolidBrush centerBrush = new SolidBrush(Color.Silver))
            {
                g.FillEllipse(centerBrush,
                    center.X - centerSize / 2,
                    center.Y - centerSize / 2,
                    centerSize, centerSize);
            }

            using (Pen centerPen = new Pen(Color.Gray, pointerWidth * 0.2f))
            {
                g.DrawEllipse(centerPen,
                    center.X - centerSize / 2,
                    center.Y - centerSize / 2,
                    centerSize, centerSize);
            }
        }

        private void DrawText(Graphics g, RectangleF dialRect)
        {
            PointF center = new PointF(dialRect.X + dialRect.Width / 2, dialRect.Y + dialRect.Height / 2);

            using (SolidBrush valueBrush = new SolidBrush(_valueColor))
            using (SolidBrush titleBrush = new SolidBrush(_titleColor))
            using (StringFormat format = new StringFormat())
            {
                format.Alignment = StringAlignment.Center;
                format.LineAlignment = StringAlignment.Center;

                // 绘制当前值
                string valueText = string.Format("{0:F1} {1}", _currentValue, _unit);
                RectangleF valueRect = new RectangleF(
                    center.X - dialRect.Width / 2,
                    center.Y + dialRect.Height * 0.1f,
                    dialRect.Width,
                    _valueFont.Height * 1.5f);

                g.DrawString(valueText, _valueFont, valueBrush, valueRect, format);

                // 绘制标题
                RectangleF titleRect = new RectangleF(
                    center.X - dialRect.Width / 2,
                    center.Y + dialRect.Height * 0.3f,
                    dialRect.Width,
                    _titleFont.Height * 1.2f);

                g.DrawString(_title, _titleFont, titleBrush, titleRect, format);
            }
        }

        #endregion

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            Invalidate();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_valueFont != null) _valueFont.Dispose();
                if (_titleFont != null) _titleFont.Dispose();
                if (_scaleFont != null) _scaleFont.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

Form1.cs文件源码

复制代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Timers;

namespace _4_dashboard
{
    public partial class Form1 : Form
    {
        private DashboardControl dashboard;
        private System.Timers.Timer updateTimer;
        private Random random = new Random();

        // 控制控件
        private NumericUpDown nudMinValue, nudMaxValue, nudCurrentValue;
        private NumericUpDown nudWarningValue, nudDangerValue;
        private Button btnStart, btnStop, btnRandom;
        private ComboBox cmbPointerColor, cmbBackgroundColor;
        private TrackBar trbValue;
        private Label lblStatus;

        public Form1()
        {
            InitializeComponent();


            this.Text = "仪表盘控件演示 - .NET 4.0";
            this.Size = new Size(1000, 700);
            this.StartPosition = FormStartPosition.CenterScreen;
            this.BackColor = Color.White;
            SetupDashboard();
            SetupControls();
            SetupTimer();
        }

        private void SetupDashboard()
        {
            dashboard = new DashboardControl();
            dashboard.Location = new Point(50, 50);
            dashboard.Size = new Size(400, 400);
            dashboard.Title = "速度表";
            dashboard.Unit = "km/h";
            dashboard.MinValue = 0;
            dashboard.MaxValue = 200;
            dashboard.WarningValue = 160;
            dashboard.DangerValue = 180;
            dashboard.CurrentValue = 60;
            this.Controls.Add(dashboard);
        }

        private void SetupControls()
        {
            int xPos = 500;
            int yPos = 50;

            // 量程设置
            AddLabel("量程设置:", xPos, yPos);
            nudMinValue = CreateNumericUpDown(xPos + 80, yPos, 0, 1000, 0);
            nudMaxValue = CreateNumericUpDown(xPos + 150, yPos, 1, 1000, 200);
            nudMinValue.ValueChanged += UpdateDashboardRange;
            nudMaxValue.ValueChanged += UpdateDashboardRange;

            yPos += 40;

            // 警戒值设置
            AddLabel("警戒值:", xPos, yPos);
            nudWarningValue = CreateNumericUpDown(xPos + 80, yPos, 0, 1000, 160);
            nudDangerValue = CreateNumericUpDown(xPos + 150, yPos, 0, 1000, 180);
            nudWarningValue.ValueChanged += UpdateThresholds;
            nudDangerValue.ValueChanged += UpdateThresholds;

            yPos += 40;

            // 当前值设置
            AddLabel("当前值:", xPos, yPos);
            nudCurrentValue = CreateNumericUpDown(xPos + 80, yPos, 0, 1000, 60);
            nudCurrentValue.ValueChanged += delegate (object sender, EventArgs e)
            {
                dashboard.CurrentValue = (float)nudCurrentValue.Value;
                trbValue.Value = (int)nudCurrentValue.Value;
            };

            yPos += 40;

            // 滑块控制
            AddLabel("滑块控制:", xPos, yPos);
            trbValue = new TrackBar()
            {
                Location = new Point(xPos + 80, yPos),
                Size = new Size(200, 45),
                Minimum = 0,
                Maximum = 200,
                Value = 60,
                TickFrequency = 20
            };
            trbValue.Scroll += delegate (object sender, EventArgs e)
            {
                dashboard.CurrentValue = trbValue.Value;
                nudCurrentValue.Value = trbValue.Value;
            };
            this.Controls.Add(trbValue);

            yPos += 60;

            // 颜色设置
            AddLabel("指针颜色:", xPos, yPos);
            cmbPointerColor = CreateColorComboBox(xPos + 80, yPos);
            cmbPointerColor.SelectedIndex = 0;
            cmbPointerColor.SelectedIndexChanged += delegate (object sender, EventArgs e)
            {
                dashboard.PointerColor = GetSelectedColor(cmbPointerColor);
            };

            yPos += 40;

            AddLabel("背景颜色:", xPos, yPos);
            cmbBackgroundColor = CreateColorComboBox(xPos + 80, yPos);
            cmbBackgroundColor.SelectedIndex = 0;
            cmbBackgroundColor.SelectedIndexChanged += delegate (object sender, EventArgs e)
            {
                // 移除透明色选项,只提供不透明颜色
                dashboard.BackgroundColor = GetSelectedBackgroundColor(cmbBackgroundColor);
            };

            yPos += 60;

            // 控制按钮
            btnStart = new Button() { Text = "开始模拟", Location = new Point(xPos, yPos), Size = new Size(80, 30) };
            btnStop = new Button() { Text = "停止模拟", Location = new Point(xPos + 90, yPos), Size = new Size(80, 30) };
            btnRandom = new Button() { Text = "随机数值", Location = new Point(xPos + 180, yPos), Size = new Size(80, 30) };

            btnStart.Click += delegate (object sender, EventArgs e)
            {
                updateTimer.Start();
                UpdateStatus("模拟运行中");
            };
            btnStop.Click += delegate (object sender, EventArgs e)
            {
                updateTimer.Stop();
                UpdateStatus("模拟已停止");
            };
            btnRandom.Click += delegate (object sender, EventArgs e)
            {
                SetRandomValue();
            };

            this.Controls.AddRange(new Control[] { btnStart, btnStop, btnRandom });

            yPos += 40;

            // 状态显示
            lblStatus = new Label()
            {
                Text = "状态: 准备就绪",
                Location = new Point(xPos, yPos),
                Size = new Size(300, 20),
                ForeColor = Color.Blue,
                Font = new Font("Arial", 10, FontStyle.Bold)
            };
            this.Controls.Add(lblStatus);
        }

        // 修改颜色选择方法,移除透明色
        private Color GetSelectedBackgroundColor(ComboBox cmb)
        {
            switch (cmb.Text)
            {
                case "黑色": return Color.Black;
                case "深灰色": return Color.DarkGray;
                case "深蓝色": return Color.DarkBlue;
                case "深绿色": return Color.DarkGreen;
                case "深红色": return Color.DarkRed;
                case "深紫色": return Color.Purple;
                default: return Color.Black;
            }
        }

        private void AddLabel(string text, int x, int y)
        {
            var label = new Label()
            {
                Text = text,
                Location = new Point(x, y),
                AutoSize = true,
                Font = new Font("Arial", 9)
            };
            this.Controls.Add(label);
        }

        private NumericUpDown CreateNumericUpDown(int x, int y, decimal min, decimal max, decimal value)
        {
            var nud = new NumericUpDown()
            {
                Location = new Point(x, y),
                Size = new Size(60, 20),
                Minimum = min,
                Maximum = max,
                DecimalPlaces = 1
            };
            // 先设置范围,再设置值
            nud.Minimum = min;
            nud.Maximum = max;
            nud.Value = value;
            this.Controls.Add(nud);
            return nud;
        }

        private ComboBox CreateColorComboBox(int x, int y)
        {
            var cmb = new ComboBox()
            {
                Location = new Point(x, y),
                Size = new Size(120, 20),
                DropDownStyle = ComboBoxStyle.DropDownList
            };

            // 修改选项,移除透明色相关选项
            if (x > 500) // 背景颜色下拉框
            {
                cmb.Items.AddRange(new object[] { "黑色", "深灰色", "深蓝色", "深绿色", "深红色", "深紫色" });
            }
            else // 指针颜色下拉框
            {
                cmb.Items.AddRange(new object[] { "红色", "蓝色", "绿色", "黄色", "紫色", "橙色" });
            }

            this.Controls.Add(cmb);
            return cmb;
        }

        private Color GetSelectedColor(ComboBox cmb)
        {
            switch (cmb.Text)
            {
                case "红色": return Color.Red;
                case "蓝色": return Color.Blue;
                case "绿色": return Color.Green;
                case "黄色": return Color.Yellow;
                case "紫色": return Color.Purple;
                case "橙色": return Color.Orange;
                default: return Color.Red;
            }
        }

        private void UpdateDashboardRange(object sender, EventArgs e)
        {
            dashboard.MinValue = (float)nudMinValue.Value;
            dashboard.MaxValue = (float)nudMaxValue.Value;
            trbValue.Minimum = (int)nudMinValue.Value;
            trbValue.Maximum = (int)nudMaxValue.Value;
        }

        private void UpdateThresholds(object sender, EventArgs e)
        {
            dashboard.WarningValue = (float)nudWarningValue.Value;
            dashboard.DangerValue = (float)nudDangerValue.Value;
        }

        private void UpdateStatus(string status)
        {
            lblStatus.Text = string.Format("状态: {0} - 当前值: {1:F1}", status, dashboard.CurrentValue);
        }

        private void SetupTimer()
        {
            updateTimer = new System.Timers.Timer(100);
            updateTimer.Elapsed += OnTimerElapsed;
            updateTimer.SynchronizingObject = this;
        }

        private void OnTimerElapsed(object sender, ElapsedEventArgs e)
        {
            // 模拟真实数据变化(带缓动效果)
            float targetValue = 50 + (float)(Math.Sin(DateTime.Now.Ticks * 0.0000001) * 70 + random.NextDouble() * 20);
            float currentValue = dashboard.CurrentValue;
            float newValue = currentValue + (targetValue - currentValue) * 0.1f;

            dashboard.CurrentValue = newValue;
            nudCurrentValue.Value = (decimal)newValue;
            trbValue.Value = (int)newValue;

            UpdateStatus("模拟运行中");
        }

        private void SetRandomValue()
        {
            float randomValue = (float)(random.NextDouble() * (dashboard.MaxValue - dashboard.MinValue) + dashboard.MinValue);
            dashboard.CurrentValue = randomValue;
            nudCurrentValue.Value = (decimal)randomValue;
            trbValue.Value = (int)randomValue;
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            if (updateTimer != null)
            {
                updateTimer.Stop();
                updateTimer.Dispose();
            }
            base.OnFormClosing(e);
        }

    }
}

三、效果演示

可以进行量程,警戒值等参数设置。拖动滑块速度显示和指针随之改变。点击模拟,则实时更新仪表盘控件数据。

相关推荐
高峰君主2 小时前
构建智能投资视野:用Python打造个性化股票分析系统
开发语言·python·股票
Cx330❀3 小时前
《C++:STL》详细深入解析string类(一):
开发语言·c++·经验分享
Q_Q19632884753 小时前
python+uniapp基于微信小程序的医院陪诊预约系统
开发语言·spring boot·python·微信小程序·django·flask·uni-app
THOVOH3 小时前
C++——类和对象(下)
开发语言·c++
杨筱毅3 小时前
【计算机通识】主流标准C库演进、差异和设计哲学【三】
c语言·开发语言·计算机通识
Dream achiever3 小时前
3.WPF - 依赖属性
c#·wpf
疯癫的老码农4 小时前
【word解析】Java文件解析问题排查:无法找到OMML2MML.xsl的IO异常解析
java·开发语言·spring boot·spring·maven
mudtools4 小时前
.NET操作Excel:高级格式设置
c#·.net·excel·wps
路弥行至4 小时前
C语言入门教程 | 第一讲:C语言零基础入门教程:第一个程序到变量运算详解
c语言·开发语言·经验分享·笔记·单片机·其他·课程设计