Prometheus
Prometheus

Reputation: 153

Reduce/Remove flicker of text inside progress bar

I am executing a DLL using backgroundWorker1 which updates a variable i by reference. To update a progress bar using i, I use the following code. I also want to show the percentage as text. The problem is that the text (NOT the progress bar) flickers a lot. How can I reduce/remove this flicker? Increasing sleep duration is not an option.

BackgroundWorker backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += (s, args) =>
{
   Mydll.MyCFunction(ref i);
};
backgroundWorker1.RunWorkerAsync();

while (backgroundWorker1.IsBusy)
{
    backgroundWorker1.ReportProgress(i * 100);               
    backgroundWorker1.ProgressChanged += (s, e) =>
    {
       progressBar1.Refresh();
       progressBar1.Value = e.ProgressPercentage;
       progressBar1.CreateGraphics().DrawString(e.ProgressPercentage.ToString() + "%",
            SystemFonts.DefaultFont, Brushes.Black,
            new PointF(progressBar1.Width / 2 - 10, progressBar1.Height / 2 - 7));
    };
    Application.DoEvents();
    System.Threading.Thread.Sleep(200);
}

Thanks.

Upvotes: 0

Views: 3045

Answers (4)

joell
joell

Reputation: 426

If graphics flicker you should enable double buffering.

DoubleBuffered = true

Or

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

For more information: http://msdn.microsoft.com/en-us/library/3t7htc9c.aspx

Upvotes: 1

DGibbs
DGibbs

Reputation: 14618

Firstly, I'd remove the line Application.DoEvents(); (excellent post on do events), this is usually indicative of bad multithreaded design. I'd also remove the Thread.Sleep call personally as well.

Secondly, you should be subscribing to ProgressChanged OUTSIDE of the worker loop. For example:

public Form1()
{
    bgWorker.ProgressChanged += bgWorker_ProgressChanged;
}

private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar.Value = e.ProgressPercentage;
    progressBar1.CreateGraphics().DrawString(e.ProgressPercentage.ToString() + "%",
            SystemFonts.DefaultFont, Brushes.Black,
            new PointF(progressBar1.Width / 2 - 10, progressBar1.Height / 2 - 7));
}

Upvotes: 0

nvoigt
nvoigt

Reputation: 77304

Your code has multiple bugs. One of them, generally speaking is calling Application.DoEvents. That may have been useful in VB6 15 years ago, but that's technology stone age. You are also attaching the same handler to the event multiple times, which means after 100 loops your drawing will be called 100 times per percent.

With so much wrong it's hard to suggest a simple fix. Have a look here for two simple ways to make this work. Try to understand what happends, in which order and why.

Upvotes: 0

Jamie Kelly
Jamie Kelly

Reputation: 309

Your code will be subscribing to the ProgressChanged event many, many times over. You should only need to subscribe one event to it. Having all these events will mean that for every progress changed, an increasing number of refreshes on the progress bar will occur.

I'd suggest creating a separate event handler for the progress changed event and making sure you only subscribe once.

So, trying to keep your design:

Subscribe event handler to ProgressChanged (Event Handler declared elsewhere)

Loop {

ReportProgress

DoEvents

Sleep }

As a side note, why are you sleeping the thread?

Upvotes: 1

Related Questions