By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,729 Members | 1,559 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,729 IT Pros & Developers. It's quick & easy.

Dev Tools: simplest Progress Bar

Expert 100+
P: 1,240
Here is my take on the progress bar. In my view it's the simplest progress bar possible, and provides the greatest control to the developer. You can choose to base your progress bar on a text box, label, rectangle or line. You get to choose the colors, size and other attributes of the progress bar object. No Active/X object or class definition necessary.

To use the progress bar just add one (textbox or label) or two (rectangle or line) objects to your form. Decide on the position, dimensions and colors as you like. I prefer to make them invisible until used. Then call the wsProgressBar subroutine, providing the control(s) to be used and the variables necessary to compute progress percentage.

The sample attached to this article has 1 form showing 9 variations on the progress bar; 10 if you consider the two slanted lines together as representing one progress bar object. It was a kind of neat surprise to see that.

Here's the code. In the sample it's within the code-behind of the form; normally it would be in some public module so it would be callable from any form. I've included the kitchen sink; you might want to strip out some options.

Expand|Select|Wrap|Line Numbers
  1. ' Procedure : ProgressBar
  2. ' Author    : Jim Wolf, Wolf Software, LLC
  3. ' Date      : 5/30/2014
  4. ' Purpose   : Simple progress bar made up of on-screen controls (label, textbox, line or rectangle)
  5. '             1 Rectangle/line will have a length or height that represents progress so far
  6. '             2nd rectangle/line's max length or height gives something to measure progress against
  7. ' progress - how many units have been completed
  8. ' goal - # of units that is 100% complete
  9. ' bDoEvents - yes/no flag to indicate whether this routine should DoEvents before returning
  10. ' pbPctCtl - control to show the percent complete on. Use NULL if no % display wanted
  11. ' pbCTL1 = the control that represents 100%
  12. ' pbCTL2 = the control that grows to show percent complete
  13. '
  14. '---------------------------------------------------------------------------------------
  15. '
  16. Public Sub wsProgressBar(progress As Long, goal As Long, bDoEvents As Boolean, pbPctCtl, pbCTL1 As Control, Optional pbCTL2 As Control)
  17.  
  18.    On Error GoTo ProgressBar_Error
  19.  
  20.     Dim dblPCT As Double
  21.     Dim pbOrientation As Byte   ' = 1 for making the control wider as progress increases
  22.                                 ' not 1 for making the control taller as progress increases
  23.     Dim pbCTL As Control        ' The control that will vary based on progress
  24.  
  25.     If goal = 0 Then Exit Sub
  26.     If goal > 0 And progress < 0 Then Exit Sub ' if either is negative both must be
  27.     If goal < 0 And progress > 0 Then Exit Sub
  28.  
  29.     If pbCTL1.Height >= pbCTL1.Width Then
  30.         pbOrientation = 0  ' vertical progress bar
  31.     Else
  32.         pbOrientation = 1  ' progress bar will be horizontal
  33.     End If
  34.  
  35.     If pbCTL2 Is Nothing Then
  36.         Set pbCTL = pbCTL1 ' if only one control is provided there will be no goal shown
  37.     Else
  38.         Set pbCTL = pbCTL2
  39.     End If
  40.  
  41.     pbCTL1.Visible = True   ' show the goal
  42.     If progress = 0 Then
  43.         pbCTL.Visible = False
  44.     Else
  45.         pbCTL.Visible = True   ' show the progress control
  46.     End If
  47.  
  48.     dblPCT = Abs(progress) / Abs(goal) ' percentage complete
  49.     If dblPCT > 1 Then dblPCT = 1
  50.  
  51.     pbCTL.Left = pbCTL1.Left
  52.  
  53.     Select Case pbCTL1.ControlType
  54.         Case acRectangle
  55.                 pbCTL.Top = pbCTL1.Top
  56.                 If pbOrientation = 1 Then  ' horizontal?
  57.                     pbCTL.Width = pbCTL1.Width * dblPCT  ' more progress =wider control
  58.                 Else
  59.                     pbCTL.Height = pbCTL1.Height * dblPCT ' more progess=taller control
  60.                     pbCTL.Top = pbCTL1.Top + (pbCTL1.Height - pbCTL.Height) ' but start at bottom of the goal
  61.                 End If
  62.         Case acLine
  63.                 If pbCTL.Name = pbCTL1.Name Then
  64.                 Else
  65.                     If pbCTL1.Height = 0 Then    ' is this a horizontal line
  66.                         pbCTL.Top = pbCTL1.Top
  67.                         pbCTL.Width = pbCTL1.Width * dblPCT  ' more progress =wider control
  68.  
  69.                     ElseIf pbCTL1.Width = 0 Then ' is this a vertical line
  70.                         pbCTL.Left = pbCTL1.Left
  71.                         pbCTL.Height = pbCTL1.Height * dblPCT ' more progess=taller control
  72.                         pbCTL.Top = pbCTL1.Top + (pbCTL1.Height - pbCTL.Height) ' but start at bottom of the goal
  73.                     Else                        ' it must be a slanted line
  74.                         pbCTL.Height = pbCTL1.Height * dblPCT ' more progess=taller control
  75.                         pbCTL.Top = pbCTL1.Top
  76.                     End If
  77.                 End If
  78.         Case acTextBox, acLabel
  79.             If pbCTL.Vertical Then    ' is this textbox showing text vertically?
  80.                 pbCTL.TopMargin = (1 - dblPCT) * pbCTL.Height  ' make margin as big as the part not yet done
  81.             Else
  82.                 pbCTL.RightMargin = (1 - dblPCT) * pbCTL.Width ' make margin as big as the part not yet done
  83.             End If
  84.     End Select
  85.  
  86.     If IsNull(pbPctCtl) Then
  87.     Else
  88.         Select Case pbPctCtl.ControlType  ' can only show % on textboxes, labels and buttons
  89.             Case acTextBox
  90.                 pbPctCtl.Value = Format(dblPCT, "#.#%")  ' display the percentage complete
  91.             Case acLabel, acCommandButton
  92.                 pbPctCtl.Caption = Format(dblPCT, "#.#%")
  93.  
  94.         End Select
  95.     End If
  96.  
  97.     Set pbCTL = Nothing
  98.     If bDoEvents Then DoEvents
  99.     On Error GoTo 0
  100.    Exit Sub
  101.  
  102. ProgressBar_Error:
  103.  
  104.     MsgBox "Error " & Err.Number & " " & Err.Description
  105.      Resume Next
  106.  
  107. End Sub
Attached Files
File Type: zip WSProgressBar.zip (39.0 KB, 536 views)
Jun 4 '14 #1
Share this Question
Share on Google+
2 Replies


twinnyfo
Expert Mod 2.5K+
P: 3,486
jimatqsi,

I have been using a Progress Bar which operates on much simpler principles:

On your Form, you have three objects:
  1. A Rectangle (rctProgressBar), with your choice of colors.
  2. A Label (lblWorkingBottom), which is placed on top of the Rectangle.
  3. Another Label (lblWorkingTop), whihc is placed on top of the other two controls. These are not Vivisble when the Form opens.
All three of these Objects will have a maximum width, set as a Private Constant (expressed in twips) when the Form opens:

Expand|Select|Wrap|Line Numbers
  1. Option Explicit
  2. Option Compare Database
  3.  
  4. Private Const ProgressMax = 3600
Then, you need three brief Procedures in the VBA used to manipulate these objects:

Expand|Select|Wrap|Line Numbers
  1. Private Sub ShowProgressBar()
  2.     Me.rctProgressBar.Visible = True
  3.     Me.lblWorkingTop.Visible = True
  4.     Me.lblWorkingBottom.Visible = True
  5. End Sub
  6. Private Sub HideProgressBar()
  7.     Me.rctProgressBar.Visible = False
  8.     Me.lblWorkingTop.Visible = False
  9.     Me.lblWorkingBottom.Visible = False
  10. End Sub
  11. Private Sub UpdateProgressBar(Max As Integer, Current As Integer)
  12.     Dim x
  13.     Me.rctProgressBar.Width = ProgressMax * (Current / Max)
  14.     Me.lblWorkingTop.Width = ProgressMax * (Current / Max)
  15.     Me.lblWorkingBottom.Caption = "           Working...." & Format(Current / Max, "0%")
  16.     Me.lblWorkingTop.Caption = "           Working...." & Format(Current / Max, "0%")
  17.     x = DoEvents
  18. End Sub
Finally, when you are performing repeating actions in the Form, you must call the functions appropriately:

Expand|Select|Wrap|Line Numbers
  1. Private Sub PerformActions()
  2. On Error GoTo EH
  3.     Dim intCount As Integer
  4.     Dim intProgress As Integer
  5.  
  6.     ShowProgressBar
  7.  
  8.     intCount = DCount("*", "tblMyData")
  9.     For intProgress = 1 to intCount
  10.         'Perform Your actions here
  11.         UpdateProgressBar intCount, intProgress
  12.     Next intProgress
  13.  
  14.     HideProgressBar
  15.     Exit Sub
  16. EH:
  17.     MsgBox "There was an error performing these actions!  " & _
  18.         "Please contact your Database Administrator.", vbCritical, "Error!"
  19.     Exit Sub
  20. End Sub
This method is incredibly simple and highly customizable. It also manages all your Progress Bar needs in the space of only a few lines of Code, which can be added to almost any process, as long as you know the total number of processes, and the current process you are on.

I may be way off mark, but this code has worked flawlessly for me for more than two years!
Jun 9 '14 #2

Expert 100+
P: 1,240
twinnyfo,
We are using essentially the same methodology. What I intended to demonstrate was that one can make a progress bar without resorting to Active/X objects or even class definitions. We just need references to a few objects (as few as 1 for my implementation, as many as 3 for yours and mine) to make it work.

The pertinent thing from my point of view is that the developer has complete control over the progress bar's position and appearance. It doesn't have to be a pop-up, it can be embedded within the active form. Controls can even do double-duty as part-time progress bar elements, such as the button I used to launch my test and also show the progress %.

Admittedly, I threw everything including the kitchen sink into my progress bar. Most folks are going to use only one type. Who needs to be able to use rectangles and lines and labels and text boxes for that purpose? Probably nobody, but it's nice to have those options available. I've standardized on using two lines, bright red on black, but sometimes I like to put some interesting text into an expanding label.

I like your solution because of the points I made in the first paragraph. Two points, however. I prefer keeping the show, hide and updating all in one subroutine. And I pass the controls to a public subroutine so the logic can be made available to all forms rather than be made a part of each form. For my example, however, I embedded the code in the form.

Thanks for your comments.

Jim
Jun 9 '14 #3

Post your reply

Sign in to post your reply or Sign up for a free account.