2

我以前没有在winforms中绘图的经验,我想以一种形式绘制心电图。或者让我们说一个特定区域的正弦波或任何波函数,但我正在做的是心电图。表单的其余部分将是带有按钮和标签的普通表单,

任何人都可以很好地完成教程吗

:)

4

4 回答 4

2

您几乎没有选择,您可以编写自己的控件,它将处理数据并呈现它。对于更复杂的绘图,这可能有点复杂,但基本原理始终相同,设置 X 和 Y 值范围,然后使用 GDI 从左到右画一条线,没什么特别的。
由于这对于更高级的功能可能会有点复杂,您可以使用一些图表控件,我会阅读这篇文章或查看 codeproject.com,我记得,我看到很少有人尝试编写一些像样的图表控件,它们是开源的,新文章可能会在 WPF 中编码,但您也应该找到较旧的文章。
编辑:
您会发现一些有用的链接:Graph plotting lib 的主要目标是模拟 ECG另一个绘图库

于 2009-08-19T13:14:51.033 回答
1

您需要创建一个自定义控件。

public class MyECGDrawer : Control{}

在其中,您覆盖 OnPaint 事件

protect override OnPaint(PaintEventArgs pe ){}

然后在paint函数中,按照你想要的方式绘制你的图形,比如说sin(x)

// refresh background
pe.Graphics.FillRectangle( Brushes.White, 0, 0, Width, Height );
int prevX = -1, prevY = -1;
for(int x = 0; x < Width; x++ )
{
    if( prevX >= 0 )
    {
        pe.Graphics.DrawLine( Pens.Black, prevX, prevY, x, Math.sin(x) );
    }
    prevX = x;
    prevY = Math.sin(x);
}

要强制心电图重绘,请调用控件上的 .Invalidate() 函数。您应该能够从设计器中拖放表单中的控件。

最后,课程看起来像

公共类 MyECGDrawer:控制{}

在其中,您覆盖 OnPaint 事件

public class MyECGDrawer : Control
{
protect override OnPaint(PaintEventArgs pe )
{
   // refresh background
    pe.Graphics.FillRectangle( Brushes.White, 0, 0, Width, Height );
    int prevX = -1, prevY = -1;
    for(int x = 0; x < Width; x++ )
    {
        if( prevX >= 0 )
            pe.Graphics.DrawLine( Pens.Black, prevX, prevY, x, Math.sin(x) );
        prevX = x;
        prevY = Math.sin(x);
    }
}
}
于 2009-08-19T13:24:49.750 回答
1

我写了以下内容并进行了测试。它似乎在做你想做的事,但请注意,它只是在没有延迟的循环中简单地绘制 sin(x) - 即 sin(x) 的图从左边缘流出的速度如此之快,以至于你几乎看不到它。但是,您可以在循环内的任何行上打断,然后使用 F5 单步执行循环以查看它是否运行缓慢 - 大概您的流式 ECG 数据只会以某个固定速度到达,因此这在您的实施中应该不是问题.

在下文中,monitor 是一个 winforms 窗体上的 PictureBox。其他一切都是本地的。

private void drawStream(){
  const int scaleX = 40;
  const int scaleY = 40;
  Point monitorTopLeft = new Point(0, 0);
  Point MonitorTopLeftMinus1 = new Point(-1, 0);

  int halfX = monitor.Width / 2;
  int halfY = monitor.Height / 2;
  Size size = new Size(halfX + 20, monitor.Height);

  Graphics g = monitor.CreateGraphics();
  g.TranslateTransform(halfX, halfY);
  g.ScaleTransform(scaleX, scaleY);
  g.Clear(Color.Black);
  g.ResetClip();

  float lastY = (float)Math.Sin(0);
  float y = lastY;
  Pen p = new Pen(Color.White, 0.01F);
  float stepX = 1F / scaleX;

  for (float x = 0; x < 10; x += stepX) {
    g.CopyFromScreen(monitor.PointToScreen(monitorTopLeft), MonitorTopLeftMinus1, size, CopyPixelOperation.SourceCopy);
    y = (float)Math.Sin(x);
    g.DrawLine(p, -stepX, lastY, 0, y);
    lastY = y;
  }
}

一些可能有用的附加信息:

  1. 图片框中的原点从左上角开始。TranslateTransform 允许您平移(即移动)原点。在示例中,我将它平移了图片框宽度的一半和高度的一半。
  2. ScaleTransform 更改图片框的放大倍数 - 请注意,它甚至会放大用于在图片框上绘图的笔的宽度 - 这就是笔的宽度设置为 0.01 的原因。
  3. CopyFromScreen 执行 bitblt。它的源点是相对于屏幕的,目标点是相对于图片框的,要移动的矩形的大小不考虑任何变换(如我们添加的缩放和平移变换)。
  4. 请注意,DrawLine 方法中的 X 坐标是 -stepx 和 0。所有绘图基本上都发生在 y 轴的右侧(即 x = 0),然后 CopyFromScreen 将绘制的部分向左移动,使其“流”向左侧.
于 2009-08-19T23:06:08.647 回答
0

除非您将此作为一种学习体验,否则您可能需要考虑查看此处提供的免费 Microsoft Chart Controls for .NET。

http://www.microsoft.com/downloads/details.aspx?FamilyID=130f7986-bf49-4fe5-9ca8-910ae6ea442c&displaylang=en#QuickInfoContainer

话虽如此,如果您想自己动手,我会提供以下指导方针。

  1. 创建一个用户控件来封装绘图渲染,而不是直接在表单上渲染。
  2. 在您的控件中,公开属性以获取/设置您希望渲染的数据,并添加您想要控制渲染的任何其他属性(缩放、平移、颜色等)
  3. 在您的控制下,要么重写 OnPaint 方法,要么为 Paint 事件创建事件处理程序。这些方法将有一个 PaintEventArgs 对象传递给它们,该对象包含一个 Graphics 对象作为属性。Graphics 对象的方法用于在需要绘制控件时将点、线等渲染到控件上。大多数绘图操作需要笔(轮廓/线条)或画笔(填充区域)。您可以将库存对象用于这些操作(例如 Pens.Black 或 Brushes.Red),或者您可以创建自己的对象(参见文档)。如果您创建自己的对象,请确保在使用它们后将其处理掉(例如,使用“using”语句或调用 Dispose)。

有几本关于 GDI+ 的好书。如果您要深入,我建议您选择一个。

于 2009-08-19T13:25:20.653 回答