Click here to Skip to main content
15,892,161 members
Articles / Programming Languages / C#

TSmartProgressBar: A Smart C# ProgressBar with Percent Text

Rate me:
Please Sign up or sign in to vote.
3.68/5 (15 votes)
18 Sep 2008CPOL3 min read 91.3K   2.5K   29   14
Customize a ProgressBar control with Label

Image 1

Figure 1. Design in VS2005 (bar width = 12, space width = 3)

Introduction

TSmartProgressBar is an open source progressbar control in C# applications, and it has the functions below:

  • shows percent text and its color when progress go
  • customizes backcolor and progress bar's color
  • customizes bar width and space width between bars
  • sets borderstyle
  • shows or hides the bar topoffset and bottomoffset

Background

We all feel the .NET ProgressBar control lacks smartness, we cannot show percent, cannot change the backcolor or progress bar color, and so on. Usually, we override the OnPaint of one control if we want to set backcolor, but it fails because the .NET ProgressBar control does not allow OnPaint event to be overridden (Note: It is not correct, please see the discussion messages at the bottom of the page).

Furthermore, if we customize a control from UserControl or Control, we must consider the famous and troublesome problem of background flicker when progress goes fast, which has been solved at How to create a smooth progress bar in Visual C#. However, we cannot show percent text according to the methods in this article since the rectangle of percent text flickers still! Why?

  • It does not flicker when percent is smaller than 50%, because the invalidated region positions left to percent text whose background color is the same as that of the control.
  • It will flicker when progress goes fast and percent is over 50%, since we must invalidate two rectangles and repaint their background color: one is the rectangle of bar, the other is that of percent text.

When I try to design one control from Label, I find that I can use the Text property to show percent, and its background does not flicker anyway.So, I customize TSmartProgressBar from Label, and successfully solve the two main problems: one is background flicker, the other is showing percent text. Furthermore, I find that it is simpler than that described in the article before: I need not consider the problem of text alignment and drawing, I need not calculate the invalid update rectangle for method Invalidate() too.

Key Point

We can set the bar width or space width between bars in TSmartProgressBar, if we do not handle the tail part at the rightmost, it will be too wide as shown in Figure 2.

Image 2

Figure 2. The white space at the rightmost is too wide.

So, we must calculate the width of tail partial bar, and draw it. The method for drawing task is DrawProgressBar whose code is listed below:

C#
private void DrawProgressBar(Graphics g)
{
   decimal percent = (decimal)m_Value / (decimal)m_Maximum;
 
   int valueWidth = (int)((this.ClientRectangle.Width - 
	this.GetLeftOffSet() * 2) * percent);	// width corresponds to Value
   int oneBlockWidth = m_ProgressBarBlockWidth + 
	m_ProgressBarBlockSpace;  		// bar width + space width
   int blockWidth = (valueWidth / oneBlockWidth) * 
	(oneBlockWidth);  			// width corresponds to real blocks

   if (percent > 0.99m)  			// add block length to avoid trunc error
   {
       if (this.ClientRectangle.Width - this.GetLeftOffSet() * 2 - blockWidth > 0)
       {
          blockWidth += (this.ClientRectangle.Width - 
		this.GetLeftOffSet() * 2 - blockWidth) / (oneBlockWidth);
       }
   }

   int left = this.ClientRectangle.Left + this.GetLeftOffSet();
   int top = this.ClientRectangle.Top + this.GetTopOffSet();
   int height = this.ClientRectangle.Height - this.GetTopOffSet() * 2;

   int drawnBlockWidth = oneBlockWidth;
   while (drawnBlockWidth <= blockWidth)  	// draw progress bars
   {
      g.FillRectangle(m_ProgressBarFillBrush, left, top, m_ProgressBarBlockWidth, height);
      left += oneBlockWidth;
      drawnBlockWidth += oneBlockWidth;
   }

   // below code used to draw the tail part.
           
   int tailBarWidth = this.ClientRectangle.Width - left - this.GetLeftOffSet();
   if (tailBarWidth > 0 && tailBarWidth < oneBlockWidth)  // tail is not a full bar
   {
      drawnBlockWidth = this.ClientRectangle.Width - left - this.GetLeftOffSet();
      if (drawnBlockWidth > 0)
      {
         g.FillRectangle(m_ProgressBarFillBrush, left, 
		top, drawnBlockWidth, height);	// draw partial bar
      }
   }
} 

We calculate the tailBarWidth and draw it if it is the rightmost bar, and we can see the result in Figure 3.

Image 3

Figure 3. The white space at the rightmost is filled.

Using the Code

After unzipping the TSmartProgressBar.zip, we can click doubly the solution fileTestTSmartProgressBar.sln to view the test project if we have Visual Studio 2005/2008, or we can run file TestTSmartProgressBar.exe in folder \bin\debug\ to test the control.

The TSmartProgressBar has the properties given below:

  • BackColor: control background color
  • ForeColor: percent text color
  • ProgressBarFillColr: bar color
  • ProgressBarBlockWidth: bar's width
  • ProgressBarBlockSpace: space width between bars
  • ProgressBarBorderStyle: border style
  • ProgressBarMarginOffset: shows or hides topOffset and bottomOffset
  • ProgressBArPercent: shows or hides percent text

Obviously, TSmartProgressBar can be extended. For example, show elapsed time, draw 2D bar as .NET ProgressBar does, display percent text at right hand, and so on.

We can download the TSmartProgressBar demo at the Chinese web page http://download.csdn.net/source/612515 too, which I uploaded before (only demo and no source code).

Points of Interest

There is always a short way if we find the correct method!

History

  • Release 9/18/2008

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Instructor / Trainer CSUST
China China
College teacher and free programmer who expertises application sofwares for statistics reports,finance data handling,and MIS using Visual C#, Delphi, SQL, etc..

Comments and Discussions

 
Suggestionlittle confuse Pin
Member 1174759324-Feb-19 21:14
Member 1174759324-Feb-19 21:14 
GeneralMy vote of 5 Pin
Leonel Gurdian26-Apr-13 8:32
Leonel Gurdian26-Apr-13 8:32 
Very smooth Progress Bar w/ awesome options surpassing the weak .Net version.
GeneralExlent 5 Pin
Mentalarray16-May-11 21:02
Mentalarray16-May-11 21:02 
Generalgood Pin
wang200712-Feb-11 15:43
wang200712-Feb-11 15:43 
GeneralMy vote of 5 Pin
mkyounes2web29-Jun-10 9:09
mkyounes2web29-Jun-10 9:09 
QuestionAdding this to a new project Pin
PaulLundberg28-Nov-08 1:32
PaulLundberg28-Nov-08 1:32 
AnswerRe: Adding this to a new project Pin
PaulLundberg28-Nov-08 5:40
PaulLundberg28-Nov-08 5:40 
GeneralRe: Adding this to a new project Pin
HU Lihui1-Dec-08 3:45
HU Lihui1-Dec-08 3:45 
AnswerRe: Adding this to a new project Pin
HU Lihui1-Dec-08 3:43
HU Lihui1-Dec-08 3:43 
QuestionCan't override OnPaint? Pin
Chris Kolkman18-Sep-08 9:29
Chris Kolkman18-Sep-08 9:29 
AnswerRe: Can't override OnPaint? [modified] Pin
HU Lihui18-Sep-08 16:15
HU Lihui18-Sep-08 16:15 
GeneralRe: Can't override OnPaint? Pin
Chris Kolkman19-Sep-08 3:03
Chris Kolkman19-Sep-08 3:03 
GeneralRe: Can't override OnPaint? Pin
HU Lihui19-Sep-08 6:49
HU Lihui19-Sep-08 6:49 
GeneralRe: Can't override OnPaint? Pin
Chris Kolkman19-Sep-08 9:59
Chris Kolkman19-Sep-08 9:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.