当前位置:   article > 正文

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

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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130

注释解释:

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170

在这里插入图片描述

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

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199

在这里插入图片描述

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

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215

在这里插入图片描述

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

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237

在这里插入图片描述

第一次扫描时间刻度的设置

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

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 = 1000;
        private double[][] _yValues;
        private double _timeIncrement = 0.1;
        private double _currentTime = 0;
        private Random _random = new Random();
        private DateTime[] _timeLabels;
        private LineObj _scanLine;
        private bool _firstScan = true;

        public Form1()
        {
            InitializeComponent();
            InitializeGraph(); // 初始化图表
            InitializeDataFile(); // 初始化数据文件
            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], Color.FromArgb(100, Color.Black), 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 = false; // 关闭纵向主要网格线
            myPane.XAxis.MinorGrid.IsVisible = false; // 关闭纵向次要网格线
            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);
            myPane.YAxis.Scale.FontSpec.Size = 8;
            myPane.YAxis.Scale.FontSpec.Family = "Times New Roman"; // 设置字体为

            // 设置X轴为文本类型
            myPane.XAxis.Type = AxisType.Text;

            // 设置X轴刻度字体大小
            myPane.XAxis.Scale.FontSpec.Size = 5; // 可以根据需要调整字体大小
            myPane.XAxis.Scale.FontSpec.Family = "Times New Roman"; // 设置字体为

            // 初始化时间标签
            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;

            // 实时保存数据到文件
            SaveCurrentDataToFile(_currentIndex, currentTime);

            // 更新时间和当前索引
            _currentTime += _timeIncrement;
            _currentIndex = (_currentIndex + 1) % _maxPoints;

            // 更新曲线数据
            UpdateCurves();

            // 更新X轴刻度显示
            zedGraphControl1.GraphPane.XAxis.Scale.TextLabels = GeneratePartialTimeLabels();

            // 更新扫描竖线位置
            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[] GeneratePartialTimeLabels()
        {
            string[] labels = new string[_maxPoints];
            for (int i = 0; i < _maxPoints; i++)
            {
                if (i <= _currentIndex || !_firstScan)
                {
                    labels[i] = _timeLabels[i].ToString("HH:mm:ss.fff");
                }
                else
                {
                    labels[i] = ""; // 未扫描到的位置使用空字符串
                }
            }

            // 仅在第一次扫描后将_firstScan设为false
            if (_currentIndex == _maxPoints - 1)
            {
                _firstScan = false;
            }

            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.Solid;
            _scanLine.IsClippedToChartRect = true;
            zedGraphControl1.GraphPane.GraphObjList.Add(_scanLine);

            // 应用更改并刷新图表
            zedGraphControl1.AxisChange();
        }

        private void SaveCurrentDataToFile(int index, DateTime time)
        {
            string filePath = "ECGData.txt"; // 可以修改为需要保存的文件路径

            try
            {
                using (StreamWriter writer = new StreamWriter(filePath, true)) // 以追加模式打开文件
                {
                    // 写入索引
                    writer.Write($"{index},");

                    // 写入8个导联的数据
                    for (int j = 0; j < ChannelCount; j++)
                    {
                        writer.Write($"{_yValues[j][index]},");
                    }

                    // 写入时间
                    writer.WriteLine(time.ToString("HH:mm:ss.fff"));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error saving data: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void InitializeDataFile()
        {
            string filePath = "ECGData.txt"; // 可以修改为需要保存的文件路径

            try
            {
                using (StreamWriter writer = new StreamWriter(filePath, false)) // 以覆盖模式打开文件
                {
                    // 写入表头
                    writer.WriteLine("Index,Lead1,Lead2,Lead3,Lead4,Lead5,Lead6,Lead7,Lead8,Time");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error initializing data file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void btnSaveData_Click(object sender, EventArgs e)
        {
            using (SaveFileDialog saveFileDialog = new SaveFileDialog())
            {
                saveFileDialog.Filter = "Text files (*.txt)|*.txt";
                saveFileDialog.Title = "Save ECG Data";
                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    SaveDataToFile(saveFileDialog.FileName);
                }
            }
        }

        private void SaveDataToFile(string filePath)
        {
            try
            {
                using (StreamWriter writer = new StreamWriter(filePath))
                {
                    // 写入表头
                    writer.WriteLine("Index,Lead1,Lead2,Lead3,Lead4,Lead5,Lead6,Lead7,Lead8,Time");

                    for (int i = 0; i < _maxPoints; i++)
                    {
                        // 写入索引
                        writer.Write($"{i},");

                        // 写入8个导联的数据
                        for (int j = 0; j < ChannelCount; j++)
                        {
                            writer.Write($"{_yValues[j][i]},");
                        }

                        // 写入时间
                        writer.WriteLine(_timeLabels[i].ToString("HH:mm:ss.fff"));
                    }
                }

                MessageBox.Show("Data saved successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error saving data: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 窗体加载事件处理方法(目前为空)
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353

在这里插入图片描述

提高响应速度

Windows窗体应用程序中使用System.Timers.Timer,其回调在不同于UI线程的线程上运行。如果你要更新UI控件(如ZedGraphControl),最好使用System.Windows.Forms.Timer,因为它在UI线程上执行。下面是你如何改进代码以使用System.Windows.Forms.Timer来避免线程间的调度问题并提高响应速度。
此外,确保图表在更新时不会频繁刷新,这样可以减少卡顿。

修改后的代码

using System;
using System.Windows.Forms;
using ZedGraph;
using System.Drawing;
using System.IO;

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.Windows.Forms.Timer _timer;
        private int _currentIndex = 0;
        private int _maxPoints = 1101;
        private double[][] _yValues;
        private double _timeIncrement = 0.1;
        private double _currentTime = 0;
        private Random _random = new Random();
        private DateTime[] _timeLabels;
        private LineObj _scanLine;
        private bool _firstScan = true;

        public Form1()
        {
            InitializeComponent();
            InitializeGraph(); // 初始化图表
            InitializeDataFile(); // 初始化数据文件
            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], Color.FromArgb(100, Color.Black), 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);

            // 设置X轴主刻度步长,使刻度标签不那么密集
            myPane.XAxis.Scale.MajorStep = 100; // 可以根据需要调整这个值

            // 网格线
            myPane.XAxis.MajorGrid.IsVisible = false; // 关闭纵向主要网格线
            myPane.XAxis.MinorGrid.IsVisible = false; // 关闭纵向次要网格线
            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);
            myPane.YAxis.Scale.FontSpec.Size = 8;
            myPane.YAxis.Scale.FontSpec.Family = "Times New Roman"; // 设置字体为

            // 设置X轴为文本类型
            myPane.XAxis.Type = AxisType.Text;

            // 设置X轴刻度字体大小
            myPane.XAxis.Scale.FontSpec.Size = 8; // 可以根据需要调整字体大小
            myPane.XAxis.Scale.FontSpec.Family = "Times New Roman"; // 设置字体为

            // 初始化时间标签
            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.Windows.Forms.Timer();
            _timer.Interval = 50; // 50毫秒的更新频率
            _timer.Tick += OnTimedEvent; // 绑定定时器事件
            _timer.Start(); // 启用定时器
        }

        private void OnTimedEvent(Object source, EventArgs 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;

            // 实时保存数据到文件
            SaveCurrentDataToFile(_currentIndex, currentTime);

            // 更新时间和当前索引
            _currentTime += _timeIncrement;
            _currentIndex = (_currentIndex + 1) % _maxPoints;

            // 更新曲线数据
            UpdateCurves();

            // 更新X轴刻度显示
            zedGraphControl1.GraphPane.XAxis.Scale.TextLabels = GeneratePartialTimeLabels();

            // 更新扫描竖线位置
            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[] GeneratePartialTimeLabels()
        {
            string[] labels = new string[_maxPoints];
            for (int i = 0; i < _maxPoints; i++)
            {
                if (i <= _currentIndex || !_firstScan)
                {
                    labels[i] = _timeLabels[i].ToString("HH:mm

:ss.fff");
                }
                else
                {
                    labels[i] = ""; // 未扫描到的位置使用空字符串
                }
            }

            // 仅在第一次扫描后将_firstScan设为false
            if (_currentIndex == _maxPoints - 1)
            {
                _firstScan = false;
            }

            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.Solid;
            _scanLine.IsClippedToChartRect = true;
            zedGraphControl1.GraphPane.GraphObjList.Add(_scanLine);

            // 应用更改并刷新图表
            zedGraphControl1.AxisChange();
        }

        private void SaveCurrentDataToFile(int index, DateTime time)
        {
            string filePath = "ECGData.txt"; // 可以修改为需要保存的文件路径

            try
            {
                using (StreamWriter writer = new StreamWriter(filePath, true)) // 以追加模式打开文件
                {
                    // 写入索引
                    writer.Write($"{index},");

                    // 写入8个导联的数据
                    for (int j = 0; j < ChannelCount; j++)
                    {
                        writer.Write($"{_yValues[j][index]},");
                    }

                    // 写入时间
                    writer.WriteLine(time.ToString("HH:mm:ss.fff"));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error saving data: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void InitializeDataFile()
        {
            string filePath = "ECGData.txt"; // 可以修改为需要保存的文件路径

            try
            {
                using (StreamWriter writer = new StreamWriter(filePath, false)) // 以覆盖模式打开文件
                {
                    // 写入表头
                    writer.WriteLine("Index,Lead1,Lead2,Lead3,Lead4,Lead5,Lead6,Lead7,Lead8,Time");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error initializing data file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void btnSaveData_Click(object sender, EventArgs e)
        {
            using (SaveFileDialog saveFileDialog = new SaveFileDialog())
            {
                saveFileDialog.Filter = "Text files (*.txt)|*.txt";
                saveFileDialog.Title = "Save ECG Data";
                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    SaveDataToFile(saveFileDialog.FileName);
                }
            }
        }

        private void SaveDataToFile(string filePath)
        {
            try
            {
                using (StreamWriter writer = new StreamWriter(filePath))
                {
                    // 写入表头
                    writer.WriteLine("Index,Lead1,Lead2,Lead3,Lead4,Lead5,Lead6,Lead7,Lead8,Time");

                    for (int i = 0; i < _maxPoints; i++)
                    {
                        // 写入索引
                        writer.Write($"{i},");

                        // 写入8个导联的数据
                        for (int j = 0; j < ChannelCount; j++)
                        {
                            writer.Write($"{_yValues[j][i]},");
                        }

                        // 写入时间
                        writer.WriteLine(_timeLabels[i].ToString("HH:mm:ss.fff"));
                    }
                }

                MessageBox.Show("Data saved successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error saving data: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 窗体加载事件处理方法(目前为空)
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357

解释

  1. 将定时器从System.Timers.Timer更改为System.Windows.Forms.Timer,使其在UI线程上执行更新操作。
  2. System.Windows.Forms.Timer的回调在UI线程上运行,消除了跨线程更新控件的问题。
  3. 调整_timer.Interval来控制刷新频率,这里设置为50毫秒。
  4. OnTimedEvent方法中直接更新UI,消除了跨线程调用的开销。
    能够改善响应速度和卡顿问题。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/935973
推荐阅读
  

闽ICP备14008679号