当前位置: 首页 > news >正文

开源 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 方法 - 指针绘制


2. 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;  // 缓动插值
}


3. 技术亮点
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);}}#endregionprotected 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);}}
}

三、效果演示

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

http://www.dtcms.com/a/409901.html

相关文章:

  • 华为FreeClip 2耳夹耳机:让「戴着不摘」成为新的使用习惯
  • 算法继续刷起-2025年09月26日
  • AI笔记在学习与工作中的高效运用
  • QML学习笔记(十四)QML的自定义模块
  • ubuntu一键安装vscode: 使用官方 APT 仓库
  • python做网站的 框架企业邮箱什么样子
  • 学习游戏制作记录(爆炸敌人的制作)
  • 第三方软件登记测试机构:【软件登记测试机构HTML5测试技术】
  • 元宇宙的宠物经济:虚拟宠物的饲养与交易
  • 如何在 CentOS 7 上安装 bzip2-libs-1.0.6-13.el7.x86_64.rpm 文件
  • 做网站的盈利模式北京软件开发公司找和丰软件专业
  • 长视频分析模型 LongVU 论文内容总结与技术架构解析
  • Datawhale25年9月组队学习:llm-preview+Task4:微调大模型
  • Unity-动画目标匹配
  • 国标GB28181平台EasyGBS视频调阅功能在跨域安防监控中的核心应用
  • dlib库关键点定位和疲劳检测
  • 甘肃省建设工程网上投标网站学院门户网站建设
  • JavaWeb--day11--登录认证
  • [VCS]Verdi/VCS 波形调试最佳实践清单
  • 网站怎么做播放窗口网站数据模版
  • 深入理解Kafka的复制协议与可靠性保证
  • 自动化接口框架搭建分享-pytest第三部分
  • WPF 控件悬停弹窗高级指南:用 Behavior 实现带动画的智能 HoverPopup
  • 佳维视工业显示器在喷码机中的应用
  • 自存19-48
  • ARM CoreSight:多核SoC调试追踪架构解析
  • Windows 显示器EDID笔记
  • 有哪些做任务的网站海淀区seo搜索引擎优化企业
  • 【C++实战㊻】解锁C++观察者模式:从理论到实战
  • 类和对象(二)