C#编写多导联扫描式的波形图Demo

本代码调用ZedGraph绘图框架,自己先安装好ZedGraph环境,然后拖一个zedGraphControl控件就行了,直接黏贴下面代码

基本代码显示

using System;
using System.Windows.Forms;
using ZedGraph;
using System.Timers;namespace ECGPlot
{public partial class Form1 : Form{// 定义导联数量和每个导联的电压偏移量private const int ChannelCount = 8;private const int VoltageOffset = 150; // 每个导联的偏移量// 用于存储每个导联的数据点列表和曲线对象private PointPairList[] _dataLists;private LineItem[] _curves;// 定时器用于模拟ECG信号数据更新private System.Timers.Timer _timer;private int _currentIndex = 0;private int _maxPoints = 500;private double[][] _yValues;private double _timeIncrement = 0.1;private double _currentTime = 0;private Random _random = new Random();public Form1(){InitializeComponent();InitializeGraph(); // 初始化图表StartTimer(); // 启动定时器}private void InitializeGraph(){// 获取图表区域对象GraphPane myPane = zedGraphControl1.GraphPane;// 设置图表标题和轴标题myPane.Title.Text = "ECG Data";myPane.XAxis.Title.Text = "Time";myPane.YAxis.Title.Text = "Voltage";// 初始化数据点列表和曲线数组_dataLists = new PointPairList[ChannelCount];_curves = new LineItem[ChannelCount];_yValues = new double[ChannelCount][];for (int i = 0; i < ChannelCount; i++){// 为每个导联创建数据点列表和曲线对象,并添加到图表中_dataLists[i] = new PointPairList();_curves[i] = myPane.AddCurve($"ECG Channel {i + 1}", _dataLists[i], GetColor(i), SymbolType.None);_yValues[i] = new double[_maxPoints];}// 设置X轴和Y轴的范围myPane.XAxis.Scale.Min = 0;myPane.XAxis.Scale.Max = _maxPoints * _timeIncrement;myPane.YAxis.Scale.Min = -600;myPane.YAxis.Scale.Max = 600 + VoltageOffset * (ChannelCount - 1);// 显示网格线myPane.XAxis.MajorGrid.IsVisible = true;myPane.YAxis.MajorGrid.IsVisible = true;// 应用更改并刷新图表zedGraphControl1.AxisChange();}private System.Drawing.Color GetColor(int index){// 定义一组颜色用于不同导联的曲线System.Drawing.Color[] colors = {System.Drawing.Color.Black,System.Drawing.Color.Red,System.Drawing.Color.Blue,System.Drawing.Color.Green,System.Drawing.Color.Purple,System.Drawing.Color.Orange,System.Drawing.Color.Brown,System.Drawing.Color.Magenta};// 根据索引返回颜色return colors[index % colors.Length];}private void StartTimer(){// 创建并配置定时器_timer = new System.Timers.Timer(100); // 100毫秒的更新频率_timer.Elapsed += OnTimedEvent; // 绑定定时器事件_timer.AutoReset = true; // 自动重置_timer.Enabled = true; // 启用定时器}private void OnTimedEvent(Object source, ElapsedEventArgs e){// 为每个导联生成模拟ECG信号数据并更新曲线for (int i = 0; i < ChannelCount; i++){double voltage = _random.Next(-400, 400) + i * VoltageOffset; // 生成带偏移量的电压数据_yValues[i][_currentIndex] = voltage;if (_dataLists[i].Count < _maxPoints){// 添加新的数据点_dataLists[i].Add(_currentTime, voltage);}else{// 更新现有数据点_dataLists[i][_currentIndex].Y = voltage;}}// 更新时间和当前索引_currentTime += _timeIncrement;_currentIndex = (_currentIndex + 1) % _maxPoints;// 使图表无效以触发重绘zedGraphControl1.Invalidate();}private void Form1_Load(object sender, EventArgs e){// 窗体加载事件处理方法(目前为空)}}
}

注释解释:

  1. 全局变量定义:定义导联数量、每个导联的电压偏移量,以及存储数据和曲线的变量。
  2. 构造函数:调用 InitializeGraphStartTimer 方法初始化图表和启动定时器。
  3. InitializeGraph 方法:初始化图表区域,设置标题和轴标题,创建每个导联的曲线对象,并设置轴的范围和网格。
  4. GetColor 方法:定义一组颜色,根据索引返回颜色用于不同导联的曲线。
  5. StartTimer 方法:创建并配置定时器,设置定时器事件处理方法。
  6. OnTimedEvent 方法:在定时器触发时生成模拟ECG信号数据,为每个导联添加或更新数据点,并刷新图表。
  7. Form1_Load 方法:窗体加载事件处理方法(目前为空)。

在这里插入图片描述

添加了y轴方向的导联标签

using System;
using System.Windows.Forms;
using ZedGraph;
using System.Timers;namespace ECGPlot
{public partial class Form1 : Form{// 定义导联数量和每个导联的电压偏移量private const int ChannelCount = 8;private const int VoltageOffset = 500; // 每个导联的偏移量// 用于存储每个导联的数据点列表和曲线对象private PointPairList[] _dataLists;private LineItem[] _curves;// 定时器用于模拟ECG信号数据更新private System.Timers.Timer _timer;private int _currentIndex = 0;private int _maxPoints = 500;private double[][] _yValues;private double _timeIncrement = 0.1;private double _currentTime = 0;private Random _random = new Random();public Form1(){InitializeComponent();InitializeGraph(); // 初始化图表StartTimer(); // 启动定时器}private void InitializeGraph(){// 获取图表区域对象GraphPane myPane = zedGraphControl1.GraphPane;// 设置图表标题和轴标题myPane.Title.Text = "ECG Data";myPane.XAxis.Title.Text = "Time (s)";myPane.YAxis.Title.Text = "Voltage";// 初始化数据点列表和曲线数组_dataLists = new PointPairList[ChannelCount];_curves = new LineItem[ChannelCount];_yValues = new double[ChannelCount][];for (int i = 0; i < ChannelCount; i++){// 为每个导联创建数据点列表和曲线对象,并添加到图表中_dataLists[i] = new PointPairList();_curves[i] = myPane.AddCurve("", _dataLists[i], GetColor(i), SymbolType.None);_yValues[i] = new double[_maxPoints];}// 移除图例myPane.Legend.IsVisible = false;// 设置X轴和Y轴的范围myPane.XAxis.Scale.Min = 0;myPane.XAxis.Scale.Max = _maxPoints * _timeIncrement;myPane.YAxis.Scale.Min = -800;myPane.YAxis.Scale.Max = 800 + VoltageOffset * (ChannelCount - 1);// 显示网格线myPane.XAxis.MajorGrid.IsVisible = true;myPane.YAxis.MajorGrid.IsVisible = true;// 隐藏Y=0的实线myPane.YAxis.MajorGrid.IsZeroLine = false;// 自定义Y轴刻度标注Scale yScale = myPane.YAxis.Scale;yScale.MajorStep = VoltageOffset;yScale.MinorStep = VoltageOffset;yScale.MajorStepAuto = false;yScale.MinorStepAuto = false;myPane.YAxis.ScaleFormatEvent += new Axis.ScaleFormatHandler(FormatYScale);// 应用更改并刷新图表zedGraphControl1.AxisChange();}private string FormatYScale(GraphPane pane, Axis axis, double val, int index){// 自定义Y轴刻度标注int leadIndex = (int)Math.Round(val / VoltageOffset);if (leadIndex >= 0 && leadIndex < ChannelCount){return $"Lead {leadIndex + 1}";}return "";}private System.Drawing.Color GetColor(int index){// 定义一组颜色用于不同导联的曲线System.Drawing.Color[] colors = {System.Drawing.Color.Black,System.Drawing.Color.Red,System.Drawing.Color.Blue,System.Drawing.Color.Green,System.Drawing.Color.Purple,System.Drawing.Color.Orange,System.Drawing.Color.Brown,System.Drawing.Color.Magenta};// 根据索引返回颜色return colors[index % colors.Length];}private void StartTimer(){// 创建并配置定时器_timer = new System.Timers.Timer(10); // 100毫秒的更新频率_timer.Elapsed += OnTimedEvent; // 绑定定时器事件_timer.AutoReset = true; // 自动重置_timer.Enabled = true; // 启用定时器}private void OnTimedEvent(Object source, ElapsedEventArgs e){// 为每个导联生成模拟ECG信号数据并更新曲线for (int i = 0; i < ChannelCount; i++){double voltage = _random.Next(-200, 200) + i * VoltageOffset; // 生成带偏移量的电压数据_yValues[i][_currentIndex] = voltage;if (_dataLists[i].Count < _maxPoints){// 添加新的数据点_dataLists[i].Add(_currentTime, voltage);}else{// 更新现有数据点_dataLists[i][_currentIndex].Y = voltage;}}// 更新时间和当前索引_currentTime += _timeIncrement;_currentIndex = (_currentIndex + 1) % _maxPoints;// 更新X轴刻度显示zedGraphControl1.GraphPane.XAxis.Scale.TextLabels = GenerateTimeLabels(_currentTime, _timeIncrement, _maxPoints);// 使图表无效以触发重绘zedGraphControl1.Invalidate();}private string[] GenerateTimeLabels(double currentTime, double increment, int maxPoints){string[] labels = new string[maxPoints];double startTime = currentTime - (maxPoints * increment);for (int i = 0; i < maxPoints; i++){labels[i] = (startTime + i * increment).ToString("0.0");}return labels;}private void Form1_Load(object sender, EventArgs e){// 窗体加载事件处理方法(目前为空)}}
}

在这里插入图片描述

添加了时间刻度跟随时间扫描变化

using System;
using System.Windows.Forms;
using ZedGraph;
using System.Timers;namespace ECGPlot
{public partial class Form1 : Form{// 定义导联数量和每个导联的电压偏移量private const int ChannelCount = 8;private const int VoltageOffset = 700; // 每个导联的偏移量// 用于存储每个导联的数据点列表和曲线对象private PointPairList[] _dataLists;private LineItem[] _curves;// 定时器用于模拟ECG信号数据更新private System.Timers.Timer _timer;private int _currentIndex = 0;private int _maxPoints = 800;private double[][] _yValues;private double _timeIncrement = 0.1;private double _currentTime = 0;private Random _random = new Random();private DateTime[] _timeLabels;public Form1(){InitializeComponent();InitializeGraph(); // 初始化图表StartTimer(); // 启动定时器}private void InitializeGraph(){// 获取图表区域对象GraphPane myPane = zedGraphControl1.GraphPane;// 设置图表标题和轴标题myPane.Title.Text = "ECG Data";myPane.XAxis.Title.Text = "Time";myPane.YAxis.Title.Text = "Voltage";// 初始化数据点列表和曲线数组_dataLists = new PointPairList[ChannelCount];_curves = new LineItem[ChannelCount];_yValues = new double[ChannelCount][];_timeLabels = new DateTime[_maxPoints];for (int i = 0; i < ChannelCount; i++){// 为每个导联创建数据点列表和曲线对象,并添加到图表中_dataLists[i] = new PointPairList();_curves[i] = myPane.AddCurve("", _dataLists[i], GetColor(i), SymbolType.None);_yValues[i] = new double[_maxPoints];}// 移除图例myPane.Legend.IsVisible = false;// 设置X轴和Y轴的范围myPane.XAxis.Scale.Min = 0;myPane.XAxis.Scale.Max = _maxPoints;myPane.YAxis.Scale.Min = -800;myPane.YAxis.Scale.Max = 800 + VoltageOffset * (ChannelCount - 1);// 显示网格线myPane.XAxis.MajorGrid.IsVisible = true;myPane.YAxis.MajorGrid.IsVisible = true;// 隐藏Y=0的实线myPane.YAxis.MajorGrid.IsZeroLine = false;// 自定义Y轴刻度标注Scale yScale = myPane.YAxis.Scale;yScale.MajorStep = VoltageOffset;yScale.MinorStep = VoltageOffset;yScale.MajorStepAuto = false;yScale.MinorStepAuto = false;myPane.YAxis.ScaleFormatEvent += new Axis.ScaleFormatHandler(FormatYScale);// 设置X轴为文本类型myPane.XAxis.Type = AxisType.Text;// 设置X轴刻度字体大小myPane.XAxis.Scale.FontSpec.Size = 7; // 可以根据需要调整字体大小myPane.XAxis.Scale.FontSpec.FontColor = System.Drawing.Color.Black;// 初始化时间标签DateTime startTime = DateTime.Now;for (int i = 0; i < _maxPoints; i++){_timeLabels[i] = startTime;}// 应用更改并刷新图表zedGraphControl1.AxisChange();}private string FormatYScale(GraphPane pane, Axis axis, double val, int index){// 自定义Y轴刻度标注int leadIndex = (int)Math.Round(val / VoltageOffset);if (leadIndex >= 0 && leadIndex < ChannelCount){return $"Lead {leadIndex + 1}";}return "";}private System.Drawing.Color GetColor(int index){// 定义一组颜色用于不同导联的曲线System.Drawing.Color[] colors = {//System.Drawing.Color.Black,//System.Drawing.Color.Red,//System.Drawing.Color.Blue,//System.Drawing.Color.Green,//System.Drawing.Color.Purple,//System.Drawing.Color.Orange,//System.Drawing.Color.Brown,//System.Drawing.Color.MagentaSystem.Drawing.Color.Black,System.Drawing.Color.Black,System.Drawing.Color.Black,System.Drawing.Color.Black,System.Drawing.Color.Black,System.Drawing.Color.Black,System.Drawing.Color.Black,System.Drawing.Color.Black};// 根据索引返回颜色return colors[index % colors.Length];}private void StartTimer(){// 创建并配置定时器_timer = new System.Timers.Timer(1); // 100毫秒的更新频率_timer.Elapsed += OnTimedEvent; // 绑定定时器事件_timer.AutoReset = true; // 自动重置_timer.Enabled = true; // 启用定时器}private void OnTimedEvent(Object source, ElapsedEventArgs e){// 记录当前时间DateTime currentTime = DateTime.Now;// 为每个导联生成模拟ECG信号数据并更新曲线for (int i = 0; i < ChannelCount; i++){double voltage = _random.Next(-200, 200) + i * VoltageOffset; // 生成带偏移量的电压数据_yValues[i][_currentIndex] = voltage;if (_dataLists[i].Count < _maxPoints){// 添加新的数据点_dataLists[i].Add(_currentIndex, voltage);}else{// 更新现有数据点_dataLists[i][_currentIndex].Y = voltage;}}// 更新时间标签_timeLabels[_currentIndex] = currentTime;// 更新时间和当前索引_currentTime += _timeIncrement;_currentIndex = (_currentIndex + 1) % _maxPoints;// 更新X轴刻度显示zedGraphControl1.GraphPane.XAxis.Scale.TextLabels = GenerateTimeLabels();// 使图表无效以触发重绘zedGraphControl1.Invalidate();}private string[] GenerateTimeLabels(){string[] labels = new string[_maxPoints];for (int i = 0; i < _maxPoints; i++){labels[i] = _timeLabels[i].ToString("HH:mm:ss.fff");}return labels;}private void Form1_Load(object sender, EventArgs e){// 窗体加载事件处理方法(目前为空)}}
}

在这里插入图片描述

添加了个竖线,扫描分界线

using System;
using System.Windows.Forms;
using ZedGraph;
using System.Timers;namespace ECGPlot
{public partial class Form1 : Form{// 定义导联数量和每个导联的电压偏移量private const int ChannelCount = 8;private const int VoltageOffset = 500; // 每个导联的偏移量// 用于存储每个导联的数据点列表和曲线对象private PointPairList[] _dataLists;private LineItem[] _curves;// 定时器用于模拟ECG信号数据更新private System.Timers.Timer _timer;private int _currentIndex = 0;private int _maxPoints = 500;private double[][] _yValues;private double _timeIncrement = 0.1;private double _currentTime = 0;private Random _random = new Random();private DateTime[] _timeLabels;private LineObj _scanLine;public Form1(){InitializeComponent();InitializeGraph(); // 初始化图表StartTimer(); // 启动定时器}private void InitializeGraph(){// 获取图表区域对象GraphPane myPane = zedGraphControl1.GraphPane;// 设置图表标题和轴标题myPane.Title.Text = "ECG Data";myPane.XAxis.Title.Text = "Time (hh:mm:ss.fff)";myPane.YAxis.Title.Text = "Voltage";// 初始化数据点列表和曲线数组_dataLists = new PointPairList[ChannelCount];_curves = new LineItem[ChannelCount];_yValues = new double[ChannelCount][];_timeLabels = new DateTime[_maxPoints];for (int i = 0; i < ChannelCount; i++){// 为每个导联创建数据点列表和曲线对象,并添加到图表中_dataLists[i] = new PointPairList();_curves[i] = myPane.AddCurve("", _dataLists[i], GetColor(i), SymbolType.None);_yValues[i] = new double[_maxPoints];}// 移除图例myPane.Legend.IsVisible = false;// 设置X轴和Y轴的范围myPane.XAxis.Scale.Min = 0;myPane.XAxis.Scale.Max = _maxPoints;myPane.YAxis.Scale.Min = -800;myPane.YAxis.Scale.Max = 800 + VoltageOffset * (ChannelCount - 1);// 显示网格线myPane.XAxis.MajorGrid.IsVisible = true;myPane.YAxis.MajorGrid.IsVisible = true;// 隐藏Y=0的实线myPane.YAxis.MajorGrid.IsZeroLine = false;// 自定义Y轴刻度标注Scale yScale = myPane.YAxis.Scale;yScale.MajorStep = VoltageOffset;yScale.MinorStep = VoltageOffset;yScale.MajorStepAuto = false;yScale.MinorStepAuto = false;myPane.YAxis.ScaleFormatEvent += new Axis.ScaleFormatHandler(FormatYScale);// 设置X轴为文本类型myPane.XAxis.Type = AxisType.Text;// 设置X轴刻度字体大小myPane.XAxis.Scale.FontSpec.Size = 10; // 可以根据需要调整字体大小// 初始化时间标签DateTime startTime = DateTime.Now;for (int i = 0; i < _maxPoints; i++){_timeLabels[i] = startTime;}// 初始化扫描竖线_scanLine = new LineObj(System.Drawing.Color.Black, 0, -800, 0, 800 + VoltageOffset * (ChannelCount - 1));_scanLine.Line.Style = System.Drawing.Drawing2D.DashStyle.Dash;_scanLine.IsClippedToChartRect = true;myPane.GraphObjList.Add(_scanLine);// 应用更改并刷新图表zedGraphControl1.AxisChange();}private string FormatYScale(GraphPane pane, Axis axis, double val, int index){// 自定义Y轴刻度标注int leadIndex = (int)Math.Round(val / VoltageOffset);if (leadIndex >= 0 && leadIndex < ChannelCount){return $"Lead {leadIndex + 1}";}return "";}private System.Drawing.Color GetColor(int index){// 定义一组颜色用于不同导联的曲线System.Drawing.Color[] colors = {System.Drawing.Color.Gray,System.Drawing.Color.Gray,System.Drawing.Color.Gray,System.Drawing.Color.Gray,System.Drawing.Color.Gray,System.Drawing.Color.Gray,System.Drawing.Color.Gray,System.Drawing.Color.Gray,};// 根据索引返回颜色return colors[index % colors.Length];}private void StartTimer(){// 创建并配置定时器_timer = new System.Timers.Timer(50); // 100毫秒的更新频率_timer.Elapsed += OnTimedEvent; // 绑定定时器事件_timer.AutoReset = true; // 自动重置_timer.Enabled = true; // 启用定时器}private void OnTimedEvent(Object source, ElapsedEventArgs e){// 记录当前时间DateTime currentTime = DateTime.Now;// 为每个导联生成模拟ECG信号数据并更新曲线for (int i = 0; i < ChannelCount; i++){double voltage = _random.Next(-200, 200) + i * VoltageOffset; // 生成带偏移量的电压数据_yValues[i][_currentIndex] = voltage;if (_dataLists[i].Count < _maxPoints){// 添加新的数据点_dataLists[i].Add(_currentIndex, voltage);}else{// 更新现有数据点_dataLists[i][_currentIndex].Y = voltage;}}// 更新时间标签_timeLabels[_currentIndex] = currentTime;// 更新时间和当前索引_currentTime += _timeIncrement;_currentIndex = (_currentIndex + 1) % _maxPoints;// 更新X轴刻度显示zedGraphControl1.GraphPane.XAxis.Scale.TextLabels = GenerateTimeLabels();// 更新扫描竖线位置UpdateScanLine();// 使图表无效以触发重绘zedGraphControl1.Invalidate();}private string[] GenerateTimeLabels(){string[] labels = new string[_maxPoints];for (int i = 0; i < _maxPoints; i++){labels[i] = _timeLabels[i].ToString("HH:mm:ss.fff");}return labels;}private void UpdateScanLine(){// 移除旧的扫描竖线zedGraphControl1.GraphPane.GraphObjList.Remove(_scanLine);// 添加新的扫描竖线_scanLine = new LineObj(System.Drawing.Color.Black, _currentIndex, -800, _currentIndex, 800 + VoltageOffset * (ChannelCount - 1));_scanLine.Line.Style = System.Drawing.Drawing2D.DashStyle.Dash;_scanLine.IsClippedToChartRect = true;zedGraphControl1.GraphPane.GraphObjList.Add(_scanLine);// 应用更改并刷新图表zedGraphControl1.AxisChange();}private void Form1_Load(object sender, EventArgs e){// 窗体加载事件处理方法(目前为空)}}
}

在这里插入图片描述

我修改了扫描线左边和右边是不同颜色

using System;
using System.Windows.Forms;
using ZedGraph;
using System.Timers;namespace ECGPlot
{public partial class Form1 : Form{// 定义导联数量和每个导联的电压偏移量private const int ChannelCount = 8;private const int VoltageOffset = 500; // 每个导联的偏移量// 用于存储每个导联的数据点列表和曲线对象private PointPairList[] _dataListsLeft;private PointPairList[] _dataListsRight;private LineItem[] _curvesLeft;private LineItem[] _curvesRight;// 定时器用于模拟ECG信号数据更新private System.Timers.Timer _timer;private int _currentIndex = 0;private int _maxPoints = 500;private double[][] _yValues;private double _timeIncrement = 0.1;private double _currentTime = 0;private Random _random = new Random();private DateTime[] _timeLabels;private LineObj _scanLine;public Form1(){InitializeComponent();InitializeGraph(); // 初始化图表StartTimer(); // 启动定时器}private void InitializeGraph(){// 获取图表区域对象GraphPane myPane = zedGraphControl1.GraphPane;// 设置图表标题和轴标题myPane.Title.Text = "ECG Data";myPane.XAxis.Title.Text = "Time";myPane.YAxis.Title.Text = "Voltage";// 初始化数据点列表和曲线数组_dataListsLeft = new PointPairList[ChannelCount];_dataListsRight = new PointPairList[ChannelCount];_curvesLeft = new LineItem[ChannelCount];_curvesRight = new LineItem[ChannelCount];_yValues = new double[ChannelCount][];_timeLabels = new DateTime[_maxPoints];for (int i = 0; i < ChannelCount; i++){// 为每个导联创建数据点列表和曲线对象,并添加到图表中_dataListsLeft[i] = new PointPairList();_dataListsRight[i] = new PointPairList();_curvesLeft[i] = myPane.AddCurve("", _dataListsLeft[i], System.Drawing.Color.Black, SymbolType.None);_curvesRight[i] = myPane.AddCurve("", _dataListsRight[i], System.Drawing.ColorTranslator.FromHtml("#CCCCCC"), SymbolType.None);_yValues[i] = new double[_maxPoints];// 初始化右边灰色波形for (int j = 0; j < _maxPoints; j++){_dataListsRight[i].Add(j, double.NaN); // 初始化为NaN,表示没有数据}}// 移除图例myPane.Legend.IsVisible = false;// 设置X轴和Y轴的范围myPane.XAxis.Scale.Min = 0;myPane.XAxis.Scale.Max = _maxPoints;myPane.YAxis.Scale.Min = -800;myPane.YAxis.Scale.Max = 800 + VoltageOffset * (ChannelCount - 1);// 显示网格线myPane.XAxis.MajorGrid.IsVisible = true;myPane.YAxis.MajorGrid.IsVisible = true;// 隐藏Y=0的实线myPane.YAxis.MajorGrid.IsZeroLine = false;// 自定义Y轴刻度标注Scale yScale = myPane.YAxis.Scale;yScale.MajorStep = VoltageOffset;yScale.MinorStep = VoltageOffset;yScale.MajorStepAuto = false;yScale.MinorStepAuto = false;myPane.YAxis.ScaleFormatEvent += new Axis.ScaleFormatHandler(FormatYScale);// 设置X轴为文本类型myPane.XAxis.Type = AxisType.Text;// 设置X轴刻度字体大小myPane.XAxis.Scale.FontSpec.Size = 4; // 可以根据需要调整字体大小// 初始化时间标签DateTime startTime = DateTime.Now;for (int i = 0; i < _maxPoints; i++){_timeLabels[i] = startTime;}// 初始化扫描竖线_scanLine = new LineObj(System.Drawing.Color.Black, 0, -800, 0, 800 + VoltageOffset * (ChannelCount - 1));_scanLine.Line.Style = System.Drawing.Drawing2D.DashStyle.Dash;_scanLine.IsClippedToChartRect = true;myPane.GraphObjList.Add(_scanLine);// 应用更改并刷新图表zedGraphControl1.AxisChange();}private string FormatYScale(GraphPane pane, Axis axis, double val, int index){// 自定义Y轴刻度标注int leadIndex = (int)Math.Round(val / VoltageOffset);if (leadIndex >= 0 && leadIndex < ChannelCount){return $"Lead {leadIndex + 1}";}return "";}private void StartTimer(){// 创建并配置定时器_timer = new System.Timers.Timer(50); // 50毫秒的更新频率_timer.Elapsed += OnTimedEvent; // 绑定定时器事件_timer.AutoReset = true; // 自动重置_timer.Enabled = true; // 启用定时器}private void OnTimedEvent(Object source, ElapsedEventArgs e){// 记录当前时间DateTime currentTime = DateTime.Now;// 为每个导联生成模拟ECG信号数据并更新曲线for (int i = 0; i < ChannelCount; i++){double voltage = _random.Next(-200, 200) + i * VoltageOffset; // 生成带偏移量的电压数据_yValues[i][_currentIndex] = voltage;if (_dataListsLeft[i].Count < _maxPoints){// 添加新的数据点_dataListsLeft[i].Add(_currentIndex, voltage);}else{// 更新现有数据点_dataListsLeft[i][_currentIndex].Y = voltage;}// 更新右边灰色波形数据点_dataListsRight[i][_currentIndex].Y = voltage;}// 更新时间标签_timeLabels[_currentIndex] = currentTime;// 更新时间和当前索引_currentTime += _timeIncrement;_currentIndex = (_currentIndex + 1) % _maxPoints;// 更新曲线数据UpdateCurves();// 更新X轴刻度显示zedGraphControl1.GraphPane.XAxis.Scale.TextLabels = GenerateTimeLabels();// 更新扫描竖线位置UpdateScanLine();// 使图表无效以触发重绘zedGraphControl1.Invalidate();}private void UpdateCurves(){for (int i = 0; i < ChannelCount; i++){// 更新左边(黑色)部分PointPairList leftPoints = _curvesLeft[i].Points as PointPairList;leftPoints.Clear();for (int j = 0; j < _maxPoints; j++){if (j <= _currentIndex){leftPoints.Add(j, _yValues[i][j]);}else{leftPoints.Add(j, double.NaN);}}}}private string[] GenerateTimeLabels(){string[] labels = new string[_maxPoints];for (int i = 0; i < _maxPoints; i++){labels[i] = _timeLabels[i].ToString("HH:mm:ss.fff");}return labels;}private void UpdateScanLine(){// 移除旧的扫描竖线zedGraphControl1.GraphPane.GraphObjList.Remove(_scanLine);// 添加新的扫描竖线_scanLine = new LineObj(System.Drawing.Color.Black, _currentIndex, -800, _currentIndex, 800 + VoltageOffset * (ChannelCount - 1));_scanLine.Line.Style = System.Drawing.Drawing2D.DashStyle.Dash;_scanLine.IsClippedToChartRect = true;zedGraphControl1.GraphPane.GraphObjList.Add(_scanLine);// 应用更改并刷新图表zedGraphControl1.AxisChange();}private void Form1_Load(object sender, EventArgs e){// 窗体加载事件处理方法(目前为空)}}
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/388944.html

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

相关文章

Bugku-ctf-web

Simple_SSTI_1 1.启动场景&#xff0c;http://114.67.175.224:12592 2.页面提示传入参数flag&#xff0c;F12查看源码得到第二个提示 3.SECRET_KEY(秘钥)是Flask中重要的一个配置值&#xff0c;在这题&#xff0c;构造语句查看它&#xff0c;得到flag&#xff0c;也可以构造?…

python+selenium+unittest自动化测试框架

前言 关于自动化测试的介绍&#xff0c;网上已有很多资料&#xff0c;这里不再赘述&#xff0c;UI自动化测试是自动化测试的一种&#xff0c;也是测试金字塔最上面的一层&#xff0c;selenium是应用于web的自动化测试工具&#xff0c;支持多平台、多浏览器、多语言来实现自动化…

AGV系统设计解析:布局-车体-对接-数量计算-路径规划

AGV AGV是实现柔性制造、装配及自动化物流的关键设备之一&#xff0c;近几年来&#xff0c;随着各国智能制造政策的不断实施&#xff0c;促进了AGV产业的快速发展。 目前&#xff0c;AGV系统广泛应用于各个行业之中&#xff0c;比如物流行业、新能源行业、汽车行业、制药行业等…

Python爬虫入门02:Fiddler下载使用教程

文章目录 手机抓包全攻略&#xff1a;Fiddler 工具深度解析引言Fiddler 工具简介为什么选择 Fiddler&#xff1f; 安装与配置 Fiddler步骤一&#xff1a;下载与安装步骤二&#xff1a;配置浏览器代理步骤三&#xff1a;安装 HTTPS 证书 配置手机以使用 Fiddler步骤一&#xff1…

堆的创建和说明

文章目录 目录 文章目录 前言 小堆&#xff1a; 大堆&#xff1a; 二、使用步骤 1.创建二叉树 2.修改为堆 3.向上调整 结果实现 总结 前言 我们已经知道了二叉树的样子&#xff0c;但是一般的二叉树是没有什么意义的&#xff0c;所以我们会使用一些特殊的二叉树来进行实现&a…

码农职场:一本专为IT行业求职者量身定制的指南

目录 写在前面 推荐图书 推荐理由 写在后面 写在前面 本期博主给大家推荐一本专为IT行业求职者量身定制的指南&#xff1a;《码农职场》。 推荐图书 https://item.jd.com/14716160.html 内容简介 这是一本专为广大IT 行业求职者量身定制的指南&#xff0c;提供了从职前…

Netty 必知必会(四)—— Channel-Pipeline 责任链

一、责任链模式 适用场景: 对于一个请求来说&#xff0c;如果每个对象都有机会处理它&#xff0c;而且不明确到底是哪个对象会处理请求时&#xff0c;我们可以考虑使用责任链模式实现它&#xff0c;让请求从链的头部往后移动&#xff0c;直到链上的一个节点成功处理了它为止 …

python爬虫初识

一、什么互联网 互联网&#xff08;Internet&#xff09;是全球范围内最大的计算机网络&#xff0c;它将数以百万计的私人、公共、学术、商业和政府网络通过一系列标准通信协议&#xff08;如TCP/IP&#xff09;连接起来形成的一个庞大的国际网络。 互联网的起源可以追溯到196…

Java 后端已经过时的技术,也是我逝去的青春

最近这段时间收到了一些读者的私信&#xff0c;问我某个技术要不要学&#xff0c;还有一些的同学竟然对 Java 图形化很感兴趣&#xff0c;还想找这方面的工作。 我接触 Java 已近 10多年了&#xff0c;见证了许多 Java 技术变迁&#xff0c;包括&#xff1a; JavaEE 框架&…

常见的应急救援设备有哪些_鼎跃安全

在我们的生活中&#xff0c;应急事件的发生常常是突如其来的&#xff0c;它们对人民的生命财产安全构成重大威胁&#xff0c;同时也对社会稳定提出严峻挑战。在这样的紧急情况下&#xff0c;迅速开展有效的救援工作显得尤为重要。而在整个救援过程中&#xff0c;应急设备的使用…

1-4章节复习总结

1-4章节总结 章节重点回顾-第一章-中央处理单元练习题 章节重点回顾-第一章-进制章节重点回顾-第一章-校验码奇偶校验码CRC循环冗余校验码海明码练习题 多草节重点回顾-第一草-计算机体系结构分类章节重点回顾-第一章-计算机指令练习题 章节重点回顾-第一章-指令流水线练习题 章…

canvas绘制表格

canvas绘制表格 最近在为公司产品做技术预研&#xff0c;经理让用canvas做一个表格&#xff0c;于是就有了这篇博客。 我们的数据是后端通过MQTT推送过来的 我在代码中也直接使用了 具体MQTT的实现代码&#xff0c;可见博客 在vue使用MQTT 在这里为了方便实用我直接封装成组件…

POI 快速入门 Excel导入导出

Excel导入导出 1 什么是POI POI简介&#xff08;Apache POI&#xff09;&#xff0c;Apache POI是Apache软件基金会的开放源码函式库&#xff0c;POI提供API给Java程序对Microsoft Office格式档案读和写的功能。 Apache POI官网http://poi.apache.org/ HSSF &#xff0d; 提…

攻防世界之《这个按钮做什么》题解

下载解压后&#xff0c;发现只有一个文件。 放入exeinfope软件里看看 根据activity猜测可能是安卓软件&#xff0c;修改文件后缀为.apk 然后用模拟器打开这个软件并会自动安装。 打开软件界面如下&#xff1a; 看得出来只有一个密码输入框&#xff0c;应该找到对应的密码就会…

每日一面系列之美团面试拷打:ConcurrentHashMap 为何不能插入 null?HashMap 为何可以

ConcurrentHashMap 为什么 key 和 value 不能为 null&#xff1f; ConcurrentHashMap 的 key 和 value 不能为 null 主要是为了避免二义性。null 是一个特殊的值&#xff0c;表示没有对象或没有引用。如果你用 null 作为键&#xff0c;那么你就无法区分这个键是否存在于 Concu…

仓颉语言 -- 网络编程

使用新版本 &#xff08;2024-07-19 16:10发布的&#xff09; 1、网络编程概述 网络通信是两个设备通过计算机网络进行数据交换的过程。通过编写软件达成网络通信的行为即为网络编程。 仓颉为开发者提供了基础的网络编程功能&#xff0c;在仓颉标准库中&#xff0c;用户可使用…

资源|Python入门必看书籍,适合零基础小白,附PDF

小编为初学Python的朋友们汇总了7本零基础入门书籍&#xff0c;包括Python三剑客等&#xff0c;都是在编程届多年畅销的书籍&#xff0c;也是众多从业者的选择&#xff0c;全文详细介绍了书籍主要内容&#xff0c;有需要的宝子根据自身情况自取 需要书籍PDF的宝子评论区留言哦 …

IIS解析漏洞~IIS6.X漏洞分析

类型代码量作用一句话木马代码量极少配合webshell管理工具使用小马代码量比小马多大马代码量最多功能比较完善&#xff08;执行命令&#xff0c;文件操作等&#xff09;图片马里面传有一句话木马 文件解析漏洞是由于中间件错误的将特殊格式的文件解析成可执行网页文件(脚本)&am…

我在高职教STM32——串口通信(4)

大家好,我是老耿,高职青椒一枚,一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次,同行应该都懂的,老师在课堂上教学几乎是没什么成就感的。正因如此,才有了借助 CSDN 平台寻求认同感和成就感的想法。在这里,我准备陆续把自己花了很多心思的教学设计分享…

Python机器学习实战:分类算法之支持向量机-垃圾邮件识别

为了解决特定问题而进行的学习是提高效率的最佳途径。这种方法能够使我们专注于最相关的知识和技能&#xff0c;从而更快地掌握解决问题所需的能力。 目录 支持向量机算法介绍 练习题 Python代码与分析 支持向量机和朴素贝叶斯的联系 支持向量机算法介绍 支持向量机&#…