Bildsoe
Bildsoe

Reputation: 1340

C#: Why is drawing slow?

Im drawing a linear gradient manually by drawing lines with changing colors. However, this is very slow, and i seems to update, when i resize the window. How do i make it faster? The color scale is linear in this example, but later i wan't to make non-linear gradients.

protected override void OnPaintBackground(PaintEventArgs paintEvnt)
        {
            SuspendLayout();

            // Get the graphics object
            Graphics gfx = paintEvnt.Graphics;
            // Create a new pen that we shall use for drawing the line

            // Loop and create a horizontal line 10 pixels below the last one
            for (int i = 0; i <= 500; i++)
            {
                Pen myPen = new Pen(Color.FromArgb(i/2,0,0));
                gfx.DrawLine(myPen, 0, i, 132, i);
            }

            ResumeLayout();

        }

Upvotes: 2

Views: 3483

Answers (4)

Peter Lillevold
Peter Lillevold

Reputation: 33920

You could pre-compute the color values so you won't have to do it on every redraw. Other than that, there's not much more you can do without resorting to more lowlevel APIs, like XNA.

Update: it is perfectly feasible to host XNA within WinForms controls. There's some nice links forward in this question.

Upvotes: 1

Cody Gray
Cody Gray

Reputation: 244742

Perhaps specifying a ColorBlend to use with the LinearGradientBrush suggested by Pieter will address your concerns about being able to paint non-linear gradients in the future?

You can create a ColorBlend object that specifies the colors of your choice and an arbitrary position for each. By setting the InterpolationColors property of the LinearGradientBrush to your ColorBlend object, you should be able to get any effect that you want.

MSDN gives the following sample:

protected override void OnPaint(PaintEventArgs e)
{
    //Draw ellipse using ColorBlend.
    Point startPoint2 = new Point(20, 110);
    Point endPoint2 = new Point(140, 110);
    Color[] myColors = {Color.Green, Color.Yellow, Color.Yellow, Color.Blue, Color.Red, Color.Red};
    float[] myPositions = {0.0f,.20f,.40f,.60f,.80f,1.0f};
    ColorBlend myBlend = new ColorBlend();
    myBlend.Colors = myColors;
    myBlend.Positions = myPositions;
    LinearGradientBrush lgBrush2 = new LinearGradientBrush(startPoint2, endPoint2, Color.Green, Color.Red);
    lgBrush2.InterpolationColors = myBlend;
    Rectangle ellipseRect2 = new Rectangle(20, 110, 120, 80);
    e.Graphics.FillEllipse(lgBrush2, ellipseRect2);
}

Upvotes: 0

Pieter van Ginkel
Pieter van Ginkel

Reputation: 29632

The problem is that GDI+ is incredibly slow.

You should use high level constructs with GDI+ which are relatively fast (relative to drawing lines like you do now). See http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.lineargradientbrush.aspx for more information about e.g. the LinearGradientBrush. There are much more of these brushes and pens which should help you increase your performance.

One more thing: the Suspend/ResumeLayout doesn't do anything in your example. These methods only apply when you are doing layout by e.g. adding Controls to the current form or changing properties on existing Controls like the Dock property or the Height and Width.

Upvotes: 3

Joachim VR
Joachim VR

Reputation: 2340

If you want to paint it once and only once, without resizing, I suggest you write this to a Bitmap object once, and then draw this bitmap to the background. Also, you can enable double buffering on the form. this should be a property called DoubleBuffering, or something similar. This should reduce the flashing you get when redrawing your form.

Upvotes: 3

Related Questions