sarath
sarath

Reputation: 508

Creating a custom graph in Winforms

I am trying to make a simple graph for my application which shows real-time data for every 100 ms. So I thought I could draw the graph line using the DrawCurve method and started with the following code:

class BufferedPanel : Panel
{
     public BufferedPanel()
     {
        this.DoubleBuffered = true;         //to avoid flickering of the panel
     }                    
}



class Form2: Form
{
    BufferedPanel panel1 = new BufferedPanel();
    List<Point> graphPoints = new List<System.Drawing.Point>();

    private void Form2_Load(object sender, EventArgs e)
    {
       this.panel1.Paint += new System.Windows.Forms.PaintEventHandler(this.panel1_Paint);
    }

    private void panel1_Paint(object sender, PaintEventArgs e)
    {
        using (Graphics g = e.Graphics)
        {
            Point[] points = graphPoints.ToArray();
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            if (points.Length > 1)
               g.DrawCurve(graphPen, points);
         }
     }

     private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
     {
         graphPoints.Add(new System.Drawing.Point(counter * steps, (int)(float)e.UserState));      //x - regular interval decided by a constant; y - simulated by background worker
         panel1.Refresh();
         counter++;
     }

}

As of now, I am simulating the values of graphPoints from a background worker thread. My problem is that, I could not get the graph lines visible when I doublebuffer my panel. It works well when I set doublebuffering to false. I am new to drawing using Graphics. So I am not very sure of how it works. Please help me in this.

Also, I would like to achieve AutoScrolling when the graphlines reach to end of the panel. Could you suggest an idea on how to do it?

This is an image of my working graph:

enter image description here

Upvotes: 1

Views: 3400

Answers (1)

Hans Passant
Hans Passant

Reputation: 942237

    using (Graphics g = e.Graphics)

That's bad. That destroys the Graphics object that was passed to your Paint event handler. Nothing can be done with that object when your event handler returns, it is a dead parrot. So don't expect anything to work afterwards, including what needs to happen when you turn on double-buffering, the buffer needs to be drawn to the screen to be visible.

There's a simple rule to using the using statement or the Dispose() method correctly. If you create an object then you own it and it is yours to destroy it. Hands off it you didn't create it.

Some evidence that you are also getting it wrong with the "graphPen" variable. Pens are definitely an object that you create and destroy in a Paint event handler. Don't store one, that just needlessly occupies space in the GDI heap, that isn't worth the few microseconds needed to create one. You'd definitely use the using statement for the pen.

So the quick fix is:

    var g = e.Graphics;

Upvotes: 2

Related Questions