Text inside a progressbar

Master Zero

Well-known member
Joined
Sep 10, 2005
Messages
51
Programming Experience
Beginner

Can anyone tell me how to put text inside a progressbar?

For example, I want to embed the current percentage value of the progressbar within it.

Thanks in advance!
 
You draw in Paint event and you use the provided graphics instance e.Graphics to draw with.
 
Yes, that's the logical approach. But apparently the pain event isn't fired every time this bar updates (I have already tried this out by putting a messagebox in it). So putting gfx creation there will have no result whatsoever except for startup :(
 
Could you provide me with a small example of how you would do it? Maybe I'm just handling it the wrong way.

I've added my current code as attachment.
 

Attachments

  • pbar.txt
    4.6 KB · Views: 131
You don't put message boxes in Paint event. I also forgot Progressbar doesn't have a Paint event for use, have a look at this example on hwo you can draw text to progressbar when WM_PAINT messages are received: post 5 of thread Draw Text with Blend to background
 
Hey,

Your example helped me through this problem :)
I tried overriding a whole bunch of look-like-they-have-something-to-do-with-the-paint-event methods, but had no idea WndProc was the correct one xD

Cheers
BN
 
Last edited:
Great control JohnH, I'm sure to use that in my own projects when the need for a progress bar arises. Thanks! :D

By the way, placing a label with transparent background over the progress bar didn't work because transparency is not actually "not painting anything". It simply paints the same color as the one underneath it and the label thinks the pixels from the parent controls are the right ones to draw. It doesn't know there is a progress bar under it, it simply takes account of the parent control.

Stacking controls does not work because of that. I think it may be possible to add transparent controls over one another by setting this on the controls to stack (the bottom most control doesn't need it) :

VB.NET:
this.SetStyle(ControlStyles.AllPaintingInWmPaint)

I didn't test this myself, there may be some other option to set. What it does is tell the control not the clear it's drawing area with its background color before it paints the content so it just paints the content and doesn't touch the background which stays to the pixels previously drawn by the controls under it. You may need to use the ControlStyles.Opaque style too.

Unfortunatly, the SetStyle method is protected so you have to override the controls you want to use this on and not all controls are overridable...
 
Hey guys,

I created my own implementation which can be found here.

progbarwithpercentage.gif


I based this class upon the code of kulrom (alot of thnx for this btw!) Hope someone can use this :)

Cheers
BN
 
Instead of using X and Y positions for the text when you draw it, draw using a rectangle that spans the whole control and use a StringFormat instance for the alignment (it can be passed in one the the DrawString overload). This will allow you to center the text vertically independently from the font size.

You can also use the control's Padding property to change the dimensions of the rectangle so the user can choose the distance from the borders. I think the property is not used on a ProgressBar. You could also create your own property that acts like it if the former option poses problem.

Overall, good control! Keep working on it, I'm a feature junkie! :)
 
Hey,

I fixed the alignment issue (now the gfx is set again after a resize), and implemented it like you suggested, also including padding :)

Still at the same location: here.

Thnx for the help again :D

Cheers
BN
 
[RTS]BN+VS*,
I noticed you're creating multiple Graphics instances without disposing them... Have a look in help for Control.CreateGraphics Method and Graphics.FromHwnd Method for example.

Also for most other GDI+ object you need to call Dispose to clean up, see for example help for Region.Dispose Method and StringFormat.Dispose Method. Also other objects may need cleanup, this is something you should be more aware of. You're creating a lot of all these objects without disposing now. In case your application locks unmanaged resources (GDI+ for example) the problem also affect the OS and remain even after your application has closed.
 
Hey,

Multiple instances? Where?

So if I have a sub looking like this
VB.NET:
sub blaat
dim gfx as grahics = something.creategraphics
' do something with gfx
end sub
I should change it into this?
VB.NET:
sub blaat
dim gfx as grahics = something.creategraphics
' do something with gfx
gfx.dispose()
end sub

If yes: I thought that was done automatically at the end of the sub :confused:
Else: what do you mean?
 
If yes: I thought that was done automatically at the end of the sub
No, it isn't. If the scope of the Graphics instance is the Sub then that is what you must do. Dispose is not called automatically, you either have to call Dispose or use a Using block (some sort of Try-Catch-Dispose pattern).

In your Code Project code you are assigning new Graphics instance to a class field (through property setter), you can't do that without disposing the previous instance first. You do this in constructor, in OnHandleCreated method and in SizeChanged event handler. Only with the OnHandleCreated/OnHandleDestroyed pair (that you copied from the code I posted) is the current Graphics instance disposed correctly, which is of course not valid any longer when you introduce new Graphics instances from other code paths.

Your Font property does not have the same problem, here you pass the new Font object to the base class (Control class) Font property setter, which is disposing the previous instance for you before replacing the new value.

Each time your ShowPercentage method is called (many times!) you are creating one StringFormat object and two Region objects without disposing them.

All these objects are left in memory until GC collects them, GC will only call Finalize (if Dispose didn't suppress this) and free the memory, so if the object has locked unmanaged resources these will not be unlocked.

As a general rule always check if an object you are creating has a Dispose method, know the scope of the object, call the Dispose method when you are done with the object.
 
Hey,

I actually don't understand what I'm doing wrong, I have only one field holding the data, so when I give it another value the same memory is used again (that's what I learned at school, if it's wrong I have an awful lot of memory leaks in my programs).

I've tried to do what you wrote, but only got errors, can you please demonstrate the solution or give a simple example? :)

Cheers
BN
 
Back
Top