Ali Tor
Ali Tor

Reputation: 2995

How can I draw the current Graphics object without clear?

I want to draw a function graphic using a list of points. But it is slowing down when so many points exist. So I think if I can draw without erasing current drawing I don't need to store the points. I know Invalidate clears the current drawing. How can I do this trick?

I an using this method currently:

    CoordinateSystem cos = new CoordinateSystem();
    List<PointF> points = new List<PointF>();
    float a = -20;
    void Form1_Tick(object sender, EventArgs e)
    {
        panel1.Invalidate();
    }
    void panel1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        double x = a;
        double y = Root(x, 3);
        cos.DrawSystem(e.Graphics);
        points.Add(cos.RelativePoint(new PointF((float)x, (float)y)));
        for (int i = 1; i < points.Count - 1; i++)
        {
         e.Graphics.DrawLine(Pens.Red,points[i],points[i+1]);
        }
        a += 0.05f;

    }

UPDATE

As you suggest I have used a Bitmap to redraw. But the quality of the result is not good for me. Additionally, I have no idea how to call Invalidate only when the data is changed. Because here, the data changes when Invalidate method is called.

Code:

CoordinateSystem cos = new CoordinateSystem();
    Bitmap bmp;
    float a = -20;
    void Form1_Tick(object sender, EventArgs e)
    {
        panel1.Invalidate();
    }

    void panel1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        double x = a;
        double y = Root(x, 3);
        PointF rel = cos.RelativePoint(new PointF((float)x, (float)y));
        using (Graphics grp = Graphics.FromImage(bmp))
        {
            grp.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            cos.DrawSystem(grp);
            grp.DrawEllipse(Pens.Red, rel.X - 0.5f, rel.Y - 0.5f, 1, 1);
        }
        e.Graphics.DrawImage(bmp, 0, 0);
        a += 0.01f;
    }

As you see in the result, the number texts haven't a good quality: enter image description here

UPDATE 2: Ok, I changed my code a little. Just drawing once the coordinate system at Load event it has a good quality now. Thanks everyone for help!

Upvotes: 0

Views: 1379

Answers (2)

Ren&#233; Vogt
Ren&#233; Vogt

Reputation: 43896

There is no way to "not clear" the graphics. When a Control needs to be drawn (has been invalidated) you have to draw everything again.

One way to improve your code a little is to use Graphics.DrawLines() instead of iterating through the points and call Graphics.DrawLine() for each seperate line.

void panel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    double x = a;
    double y = Root(x, 3);
    cos.DrawSystem(e.Graphics);
    points.Add(cos.RelativePoint(new PointF((float)x, (float)y)));
    e.Graphics.DrawLines(Pens.Red, points.ToArray());
}

Upvotes: 2

Matt Wilko
Matt Wilko

Reputation: 27342

The Paint event has a e.ClipRectangle property.

This is the actual rectangle that needs to be repainted, as it is not always necessary to redraw everything (e.g. part of a form is moved over your form and moved off again).

So one thing you can do is only draw the lines that fall within that rectangle.

But having said that if you are calling Invalidate, that signals that the whole things needs to be redrawn.

It would be better to keep a track of which ones you have drawn perhaps and only draw the new ones?

Upvotes: 1

Related Questions