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

发布于:2024-08-02 ⋅ 阅读:(80) ⋅ 点赞:(0)

本代码调用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.Magenta

                 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,
                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)
        {
            // 窗体加载事件处理方法(目前为空)
        }
    }
}

在这里插入图片描述