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

news/2025/10/1 14:20:48/文章来源:https://www.cnblogs.com/ljbguanli/p/19122423

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

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

 相关链接:

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

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

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

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

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

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

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

开源 C# 快速开发(八)通讯--Tcp服务器端

开源 C# 快速开发(九)通讯--Tcp客户端

开源 C# 快速开发(十)通讯--http客户端

推荐链接:

开源 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.mzph.cn/news/923927.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025中医师承培训、考试、认证机构权威推荐榜:名师传承与临床实践口碑之选

2025中医师承培训、考试、认证机构权威推荐榜:名师传承与临床实践口碑之选 在中医药事业蓬勃发展的今天,中医师承教育作为传统医学传承的重要方式,正受到越来越多从业者的关注与重视。随着国家对中医药传承创新支持…

建设监督网站阜城网站建设代理

1.筛选需求的报告id 基于REAC14Q4文件,筛选出需求报告的id,该文件格式如下&#xff0c;其中pt字段描述了患者在事件中所有的不良信息&#xff0c;注意此处一个报告id可以对应复数条信息。 primaryid$caseid$pt$drug_rec_act 初步统计约有4500种不良反应&#xff0c;总计60W条数…

什么网站做蔬菜生鲜比较好向客户介绍网站建设

一篇word文档&#xff0c;内容有大的章&#xff0c;小的节。如何把章节抽出来生成目录&#xff1f;WORD →点击需要插入的地方 → 插入菜单 → 索引和目录 → 目录 → 确定目录通常是长文档不可缺少的部分&#xff0c;有了目录&#xff0c;用户就能很容易地知道文档中有什么内容…

【Linux系列】让 Vim “跑”起来:建立一个会动的进度条

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

网上自己建网站网站建设合同建设方注意事项

来源&#xff1a;国防科技要闻据悉&#xff0c;俄罗斯地面部队已完成“木船”&#xff08;Kungas&#xff09;机器人系统样机的国家试验&#xff0c;将于2020年开始部署部队&#xff0c;用于作战试验。发展背景自2010年以来&#xff0c;俄罗斯机器人系统进入快速发展时期。2014…

网站空间商是什么图书馆网络规划与设计

Problem: 354. 俄罗斯套娃信封问题 文章目录 思路解题方法复杂度Code 思路 这个问题可以转换为最长递增子序列&#xff08;Longest Increasing Subsequence&#xff0c;LIS&#xff09;问题。先对信封按宽度升序排序&#xff0c;当宽度相同时&#xff0c;按高度降序排序。然后在…

天津建设工程评标专家网站怎么用ps制作个人网站模板下载

31.《危险化学品安全管理条例》所称重大危险源,是指生产、储存、使用或者搬运危险化学品,且危险化学品的数量等于或者超过&#xff08;&#xff09;的单元(包括场所和设施)。 A.标准 B.一定量 C.临界量 答案&#xff1a;C 32.《危险化学品生产企业安全生产许可证实施办法》…

电子文件分类整理与双向同步 2025年10月1日

电子文件分类整理与双向同步 2025年10月1日一、网上包邮购买 极空间私有云Z4Pro+性能版钛金灰+希捷酷狼Pro16TBx4块二、在极空间Windows电脑客户端设置文件夹实时双向同步任务三、在极空间Windows电脑客户端设置自动挂…

手机wap购物网站模板上海建筑设计院招聘

内网工具对抗 首先&#xff0c;你需要分析&#xff1a; 1、安全工具是否有源代码 2、安全工具源代码逻辑复杂程度 3、当前源代码你是否有能力修改 其次&#xff0c;你需要考虑&#xff1a; 1、无源码或无能力修改 2、各种异常bug打包问题 3、修改打包后效果也不太好 故…

C++版搜索与图论算法 - 详解

C++版搜索与图论算法 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco",…

达成设计卓越:全面解析 IC 设计中的验证之道

在集成电路(IC)设计流程中,验证(Verification) 是确保设计符合规格、功能正确的关键环节。本文以简洁明快的风格,深入探讨验证的重要性、常用方法与实践经验,帮助设计师构建高效可靠的验证流程。 1、验证的重要…

Typora 笔记迁移 Obsidian 图片链接转换

解决了Typora 笔记迁移 Obsidian 图片链接转换问题,实现了自动化`![Pasted image 20221223164738.png](./Database/Pasted image 20221223164738.png)--![[Pasted image 20221223164738.png]]`附件:Typora 笔记迁移 O…

【Java八股文】12-分布式面试篇 - 教程

【Java八股文】12-分布式面试篇 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mon…

Java 运行 Word 文档标签并赋值:从基础到实战

Java 运行 Word 文档标签并赋值:从基础到实战pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &q…

上海配资网站开发广州开发区投资集团有限公司

都是copy的百度SDK文档&#xff0c;简单说说怎么用。1、没安装Python的参见此文&#xff1a;Python学习笔记系列 1 ——安装调试Python开发软件2、winr输入cmd打开命令行&#xff0c;输入&#xff1a;pip install baidu-aip&#xff0c;如下安装百度AI的模块。3、新建文本文档&…

词云组件

效果图: 组件代码:<template><div class="post"><div class="portal-title flex-h justify-between"><div class="flex-h"><img class="icon"…

域名 网站名称网站建设对电子商务的作用

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

网站制作的关键技术新乡手机网站建设电话

文章目录 一、JavaScript 逻辑运算符1、逻辑运算符 概念2、逻辑与运算符 &&3、逻辑或运算符 ||4、逻辑非运算符 !5、完整代码示例 一、JavaScript 逻辑运算符 1、逻辑运算符 概念 JavaScript 中的 逻辑运算符 的作用是 对 布尔值 进行运算 , 运算完成 后 的 返回值 也是…

没有网站也可以做外贸吗wordpress和万网

碰撞 Collision. [kəˈliʒən] 碰撞&#xff1b;冲突&#xff1b;&#xff08;意见&#xff0c;看法&#xff09;的抵触&#xff1b;&#xff08;政党等的&#xff09;倾轧 选择一个需要添加碰撞器的游戏对象后 Component->Physics- Unity一共为对象提供了6 种碰撞器&…

监控设备网站制作工作服厂家联系方式

目录 1. 更换yum源更新系统软件包&#xff1a; 1.1备份yum源 1.1.1创建备份目录&#xff1a; 1.1.2移动现有仓库配置文件到备份目录&#xff1a; 1.1.3验证备份&#xff1a; 1.2更换yum源 1.2.1添加yum源 1.2.2删除和建立yum缓存 1.3更新系统软件包 1.4 yum与dnf介绍…