How to reduce flicker when using Graphics.DrawString in C # for timer?

Below is the C # code that outputs text to the progress bar. It is used to add text to a progress bar showing the remaining countdown time. I used the Graphics class to draw the string instead of the Windows Form label, as the label's background could not be set transparent when placed on the progress bar.

However, with this code, the text flickers every time it is updated (this method is called inside a timer that ticks once a second), so it flickers constantly and unusable all the time.

/// <summary>
    /// Adds time remaining text into a System.Windows.Forms.ProgressBar
    /// </summary>
    /// <param name="target">The target progress bar to add text into</param>
    /// <param name="remainingTimeText">The text to add into the progress bar.</param>
    private void set_progress_bar_text( System.Windows.Forms.ProgressBar target, string remainingTimeText )
    {
        // Make sure we do not have a null progress bar.
        if( target == null )
        {
            throw new ArgumentException( "Null Target" );
        }

        // Use the progress bar label font and size.
        Font textFont = new Font( labelProgress.Font.Name, labelProgress.Font.Size );

        // gr will be the graphics object we use to draw on the progress bar.
        using( Graphics gr = target.CreateGraphics() )
        {
            gr.DrawString( remainingTimeText,
                textFont,
                new SolidBrush( Color.Black ), // The brush we will use to draw the string, using a black colour.

                // The position on the progress bar to put the text.
                new PointF(
                // X location of text, to be placed at the centre of the progress bar.
                    progressBar.Width / 2 - ( gr.MeasureString( remainingTimeText,
                    textFont ).Width / 2.0F ),
                // Y Location
                progressBar.Height / 2 - ( gr.MeasureString( remainingTimeText,
                    textFont ).Height / 2.0F ) ) );
        }
    }

      

I tried setting DoubleBuffered = true

in this method as suggested in the related Stack Overflow questions, but that doesn't stop blinking. I cannot reduce the number of times the text is updated as the text is a countdown hour that needs to be updated once a second. Is there a way to prevent double buffered flickering or any other potential solutions?

+3


source to share


1 answer


The ProgressBar seems to be one of those controls that tries to hide the painting. Therefore, we need to roll our own. Just share your ProgressBar with this.

Added CreateParams parameter to reduce flicker as pointed out in comments.

public class MyLovelyProgressBar : ProgressBar
{
    public MyLovelyProgressBar()
    {
        SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
    }

    private string foregroundText;
    public string ForegroundText 
    {
        get { return foregroundText;  }
        set 
        {
            if (foregroundText != value)
            {
                Invalidate();
                foregroundText = value;
            }
        } 
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams result = base.CreateParams;
            result.ExStyle |= 0x02000000; // WS_EX_COMPOSITED 
            return result;
        }
    }

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        switch (m.Msg)
        {
            case 15: //WmPaint
                using (var graphics = Graphics.FromHwnd(Handle))
                    PaintForeGroundText(graphics);
                break;
        }
    }

    private void PaintForeGroundText(Graphics graphics)
    {
        if (!string.IsNullOrEmpty(ForegroundText))
        {
            var size = graphics.MeasureString(ForegroundText, this.Font);
            var point = new PointF(Width / 2.0F - size.Width / 2.0F, Height / 2.0F - size.Height / 2.0F);
            graphics.DrawString(ForegroundText, this.Font, new SolidBrush(Color.Black), point);
        }
    }
}

      



and then just change the ForegroundText of that ProgressBar in your timer event.

myLovelyProgressBar1.ForegroundText = "A constantly changing lovely text";

      

+4


source







All Articles