C#自定义UserControl绘制动态波形图详解

苏见山
苏见山
发布时间:2026-10-14 | 3人浏览过
原创

在C#开发Windows Forms应用时,有时需要展示随时间变化的连续数据(如心率、传感器读数等)。通过创建自定义 UserControl 并重写绘图逻辑,可以灵活实现轻量级的动态波形图,无需引入第三方庞大库。

实现思路与准备

该控件的核心原理是利用 System.Windows.Forms.Timer 触发重绘事件,在每次绘制周期内更新数据点数组,并使用 Graphics 对象将网格线(背景)和折线图(前景)绘制到屏幕上。由于涉及内存操作,需注意窗口大小改变时的数据数组适配。

关键步骤解析

第1步:定义基础属性与画刷

首先需要声明用于控制界面表现的私有变量和公共属性。这包括背景网格颜色 LINEPEN、前景线条颜色 FORELINEPEN、模拟数据的抖动幅度 shake 以及当前数值 Value。

  • SIZE: 定义网格单元的大小,影响视觉密度。
  • oldLine数组: 用于存储历史数据点的高度值,配合索引实现滚动效果。
  • 属性封装: 使用 [DefaultValue] 等特性允许设计器修改 Shake(抖动率)、Value(当前值)和 LinePen(背景画笔),并在值改变时调用 Invalidate() 强制刷新。

第2步:实现定时器驱动的数据更新

添加一个Timer控件(文中设为50ms间隔),其 Tick 事件负责推进滚动偏移量并触发界面刷新。

private void timer1_Tick(object sender, EventArgs e)
{
    // limits 用于控制垂直网格的滚动偏移
    limits++;
    if (limits >= SIZE) { limits = 0; }
    
    // 触发 Paint 事件进行重绘
    this.Invalidate();
}

第3步:绘制网格背景

在 UserControl1_Paint 事件中,首先遍历横纵坐标,使用 g.DrawLine 绘制背景网格线。注意在横向循环中引入 limits 变量以产生向左滚动的视觉效果。

int h = (int)(this.Size.Height / SIZE);
int w = (int)(this.Size.Width / SIZE) + 1;
// 绘制水平线
for (; h >= 0; h--)
{
    g.DrawLine(LINEPEN, new Point(0, h * SIZE), new Point(this.Size.Width, h * SIZE));
}
// 绘制垂直线(含偏移量 limits)
for (; w >= 0; w--)
{
    g.DrawLine(LINEPEN, new Point((w * SIZE) - limits, 0), new Point((w * SIZE) - limits, this.Size.Height));
}

第4步:绘制动态前景波形

这是最核心的部分。在绘制新帧前,先对数据进行随机抖动处理(如果开启了 Shake 模式),然后更新 oldLine 数组:

  1. 数据更新: 将数组整体左移一位,并将最新计算的 Value 放入数组末尾。
  2. 边界约束: 确保 Value 始终保持在 0 到 100 之间。
  3. 坐标映射: 将 0-100 的数值比例映射为控件高度的像素值,依次连接相邻点形成折线。
// 数据移动与新增
for (int j = 0; j < oldLine.Length - 1; j++)
{
    oldLine[j] = oldLine[j + 1];
}
oldLine[oldLine.Length - 1] = Value;

// 绘制连线
for (int i = 0; i < oldLine.Length - 1; i++)
{
    // 计算 y 坐标:高度减去对应比例的像素数
    float ratio = (float)oldLine[i] / 100f;
    int y1 = this.Height - (int)(ratio * this.Height) - 1;
    
    ratio = (float)oldLine[i + 1] / 100f;
    int y2 = this.Height - (int)(ratio * this.Height) - 1;
    
    g.DrawLine(FORELINEPEN, new Point(i, y1), new Point(i + 1, y2));
}

第5步:处理窗口缩放异常

当控件宽度发生剧烈变化(Resize)时,原有的 oldLine 数组长度可能与新的显示宽度不匹配。代码中提供了简单的对齐逻辑:
- 若窗口变宽,扩展数组长度。
- 若窗口变窄,裁剪数组长度。
此步骤保证波形不会因布局改变而错位或报错。

完成判断

编译通过后,在工具箱中找到自定义的 UserControl 拖入窗体。设置 Timer 启动,并在业务逻辑中动态修改控件的 Value 属性,即可看到平滑滚动的波形动画。若开启 Shake 属性,波形将呈现自然抖动的模拟信号特征。

以上就是C#自定义控件绘制动态波形图的详细内容,更多关于C# GDI+图形编程的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表