Tuesday, October 05, 2010

WinForms ProgressBar with text

Progress bar with textSomebody asked how to use my transparent label on top of a ProgressBar control, since it disappeared when the progress bar changed its state. I had a look at it, but the transparent label wasn’t getting any notification of changes, even when I hooked into the WndProc method. So I wondered if it would be possible to sub-class the ProgressBar control and write some text on top of it that way. And that seems to work OK, as shown below.

Update – I’ve fixed the flickering

Update 2 – It now picks up the text colour from the ForeColor property

Update 3 – Should now work on Windows XP

Update 4 – Now lets you specify the font used for the text

using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System;

namespace WinFormControls
{
 
  public class TextProgressBar : ProgressBar
  {
    protected override CreateParams CreateParams
    {
      get
      {
        CreateParams result = base.CreateParams;
        if (Environment.OSVersion.Platform == PlatformID.Win32NT
            && Environment.OSVersion.Version.Major >= 6)
        {
          result.ExStyle |= 0x02000000; // WS_EX_COMPOSITED 
        }

        return result;
      }
    }

    protected override void WndProc(ref Message m)
    {
      base.WndProc(ref m);
      if (m.Msg == 0x000F)
      {
        using (Graphics graphics = CreateGraphics())
        using (SolidBrush brush = new SolidBrush(ForeColor))
        {
          SizeF textSize = graphics.MeasureString(Text, Font);
          graphics.DrawString(Text, Font, brush, (Width - textSize.Width) / 2, (Height - textSize.Height) / 2);
        }
      }
    }

    [EditorBrowsable(EditorBrowsableState.Always)]
    [Browsable(true)]
    public override string Text
    {
      get
      {
        return base.Text;
      }
      set
      {
        base.Text = value;
        Refresh();
      }
    }

    [EditorBrowsable(EditorBrowsableState.Always)]
    [Browsable(true)]
    public override Font Font
    {
      get
      {
        return base.Font;
      }
      set
      {
        base.Font = value;
        Refresh();
      }
    }
  }
}

17 comments:

Anonymous said...

Could you please explain me how do you use/implement this text on ProgressBar?

I appreciate your help.

Thanks.

Doogal said...

Just copy the code to a new C# file and use the TextProgressBar class instead of the ProgressBar class in your application.

Anonymous said...

Great contro! but is there a solution for the flickering?

Doogal said...

Indeed there is, I figured it out and it flickers no more

Anonymous said...

Excellent! works perfectly!
Is there a also a way to change the text color?

Doogal said...

There is now, just use the ForeColor property

Vonny232 said...

Hi,

Useful mod, works fine on Win7, but on win XP the label is not visible?? Any ideas?

Danny

Vonny232 said...

Hi,

Great Mod. Works Fine on Win 7 PCs.

Unfortunately it does not work on XP machines, the label is not visible.

Any ideas why? Perhaps the Win7 Visual styles??

Cheers

Danny

Doogal said...

Unfortunately I don't have access to an XP machine to investigate. Maybe the progress bar is implemented differently there whcih is causing the problem? Maybe try removing the CreateParams as well to see if that's causing the problem (might start flickering a bit though)

Vonny232 said...

Hi,

Sorry for the double post. Feel free to delete the first one.

You were right about the CreateParams.

I did a bit a trawling on the net and read somewhere that simply apply the command to Vista upwards.


http://stackoverflow.com/questions/1282911/windows-form-paints-repeatedly-in-xp-but-not-in-vista


protected override CreateParams CreateParams
{
get
{
CreateParams result = base.CreateParams;
if (Environment.OSVersion.Platform == PlatformID.Win32NT
&& Environment.OSVersion.Version.Major >= 6)
{
result.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
}

return result;
}
}

thanosazlin said...

great code , it worked perfectly. i was able to figure out how to change the color of the text half way through using get/set on ForeColor... i am new to C Sharp so i am learning, but i can't seem to figure out how to make the text font BOLD or a Different font type as well???

Doogal said...

You need to change the reference to SystemFonts.DefaultFont to your own choice of font. I'll add it as a property of the control at some point, but I'm going to be busy for the next few days

Doogal said...

Now has a Font property

Anonymous said...

Thanks for this great control. It helped me a lot. In my project I had about 10 progressbars in different places showing progress of very long operations. Just changed reference in design.cs and have Text property! Awesome piece of code!

Anonymous said...

Thanks for this great control. It helped me a lot as well

Anonymous said...

Thanks for the code. But somehow, when I test this on a loop from 1 to 10000, the text gets to display 10000 before the progress bar reaches to its maximum. Here is the simple code that I have:

ProgressBar1.Minimum = 0;
ProgressBar1.Value = 0;
ProgressBar1.Maximum = 10000;
ProgressBar1.Text = "";

for (int iIdx = 1; iIdx <= ProgressBar1.Maximum; iIdx++)
{
ProgressBar1.Text = "Item " + iIdx.ToString() + " of " + ProgressBar1.Maximum.ToString() + " ...";
ProgressBar1.Value = iIdx;
}

For hundreds of itertaions at the end, the text says Item 10000 of 10000 ... while the progress bar clearly has not finished yet. Something is really not working.

Also, I have seen that in some compilers versions, it is complaining about the overridden Text property. The compiler is throwing an error saying that the Text property cannot be overriden because it is not abstract, virtual etc. Just thought putting this out ther.

Doogal said...

To be honest it years since I've looked at this code. You may want to put an Application.ProcessMessages() in your loop to ensure everything is getting repainted which might fix it