Search code examples
c#winformspicturebox

PictureBox Refresh causes layers above to flicker


I am trying to read data from ports and show that on a dial. the background is a PictureBox containing the image of a circular scale giving readings, and a Lineshape has been used to represent the dial. The PictureBox has been 'sent to back' to allow visibility of the Lineshape. I'm enclosing representative codes: if i do this:

    private void timer1_Tick(object sender, EventArgs e)
    {
        ang += 2.0 * Math.PI / 180.0;
        lineShape1.X1 = Convert.ToInt32(lineShape1.X2 - r * Math.Sin(ang));
        lineShape1.Y1 = Convert.ToInt32(lineShape1.Y2 - r * Math.Cos(ang));

    }

then it leaves a trace on the PictureBox.

But if i use the Refresh function of the PictureBox, then the dial appears to flicker. i have tried with timer intervals of 10, 15, 20, 50 and 100, but the problem persists.

    private void timer1_Tick(object sender, EventArgs e)
    {
        ang += 2.0 * Math.PI / 180.0;
        lineShape1.X1 = Convert.ToInt32(lineShape1.X2 - r * Math.Sin(ang));
        lineShape1.Y1 = Convert.ToInt32(lineShape1.Y2 - r * Math.Cos(ang));
        pictureBox1.Refresh();
    }

For the sake of the actual problem, it is not possible to increase the interval. What can i do to Show a smooth variation of the dial?


Solution

  • As @Hans Passant suggested, you should not be using a LineShape object. This is a example of code that implement his suggestion (quick, untested):

    private void timer1_Tick(object sender, EventArgs e)
    {
        pictureBox1.Invalidate();
    }
    
    void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        ang += 2.0 * Math.PI / 180.0;
        var X1 = Convert.ToInt32(X2 - r * Math.Sin(ang));
        var Y1 = Convert.ToInt32(Y2 - r * Math.Cos(ang));
    
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    
        e.Graphics.DrawLine(
            new Pen(Color.Yellow, 1f),
            new Point(X1, Y1), 
            new Point(X2, Y2 ));
    }
    

    Also, try to set this.DoubleBuffered = true; to avoid the flickering problem.