tags:

views:

549

answers:

5

i have no previous experience in plotting in winforms, in one form i want to plot ecg. or lets say a sin wave or any wave function in a specific area, but what i am doing is e.c.g.. rest of the form will be normal form with buttons and labels,

can anybody be nice enough to through in a tutorial

:)

+1  A: 

You have few choices, you can write your own control, that will process data and render it. For more complicated plots, that can be a bit complicated, but the basics are always the same, setting X and Y values ranges and then just draw a line using GDI going from left to right, nothing fancy.
As this can get a bit complicated for more advanced features, you could use some charting controls, I'd read this post or check codeproject.com, I remember, that I saw few attempts to write some decent charting controls, which are open source, new articles will probably be coded in WPF, but you should find something older as well.
Edit:
Some links that you can find useful: Graph plotting lib that's main goal is to simulate ECG or another graph plotting lib

Ravadre
thanks a lots :)
Junaid Saeed
+1  A: 

You need to create a custom control.

public class MyECGDrawer : Control{}

In it, you override the OnPaint event

protect override OnPaint(PaintEventArgs pe ){}

Then in the paint function, you draw your graphics the way you want it, let's say 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);
}

To force the ECG to redraw, you call the .Invalidate() function on the control. You should be able to drag and drop the control in your form from the designer.

In the end, the class would look like

public class MyECGDrawer : Control{}

In it, you override the OnPaint event

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);
    }
}
}
ADB
thanks a lots :)
Junaid Saeed
A: 

Unless you are doing this as a learning experience, you may want to consider looking at the free Microsoft Chart Controls for .NET available here.

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

That being said, I would offer the following guidelines if you want to roll your own.

  1. Create a user control to encapsulate the plot rendering rather than render directly on the form.
  2. In your control, expose properties to get/set the data you wish to render and add any other properties you want to control the rendering (scaling, panning, colors, etc.)
  3. In you control, either override the OnPaint method or create an event handler for the Paint event. These methods will have a PaintEventArgs object passed to them, which contains a Graphics object as a property. The methods of the Graphics object are used to render points, lines, etc onto the control when it needs to be painted. Most of the drawing operations require either a pen (outlines / lines) or a brush (filled areas). You can use stock objects for these operations (e.g. Pens.Black or Brushes.Red) or you can create your own (see documentation). If you create you own objects, make sure you dispose of them after using them (e.g. using the "using" statement or by calling Dispose).

There are a couple good books on GDI+. I suggest picking one up if you are going in deep.

Michael McCloskey
thanks a lots :)
Junaid Saeed
+1  A: 

I wrote up the following and tested it. It seems to do what you want, but note that it is simply plotting sin(x) in a loop with no delay - i.e. the plot for sin(x) streams off the left edge so fast you can hardly see it. You can, however, put a break on any line inside the loop and then step through the loop with F5 to see it work slowly - presumably your streaming ECG data will only arrive at some fixed speed so this should not be a problem in your implementation.

In the following, monitor is a PictureBox on a winforms form. Everything else is local.

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;
  }
}

Some additional info that may be helpful:

  1. The origin in a picture box starts out at the top left corner. TranslateTransform allows you to translate (i.e. move) the origin. In the example, I translate it by half the picture box's width and half its height.
  2. ScaleTransform changes the magnification of the picturebox - note that it even magnifies the width of the pen used to draw on the picturebox - this is why the pen's width is set to 0.01.
  3. CopyFromScreen performs a bitblt. Its source point is relative to the screen, the destination is relative to the picturebox and the size of the rectangle to move disregards any transforms (like the scale and translation transforms we added).
  4. Notice that the X coordinates in the DrawLine method are -stepx and 0. All drawing basically occurs right on the y axis (i.e. x = 0) and then CopyFromScreen moves the drawn portion to the left so that it "streams" off to the left.
Chris Judge
thanks a lots :)
Junaid Saeed
@Chris Judge: most US ECG's are 25mm/s and overseas you can get 50mm/s (or in a Cardiac ICU or telemetry floor in the US). So if you put a sleep in of ~10ms (so probably 40-50ms) you would have roughly the right rate assuming 96dpi.
sixlettervariables
A: 

i read your answers and i wander to design the ecg the only function you need is the sin()???