- Community Pick
- Experts Exchange Approved
- Editor's Choice
If you have written some VBA code for Excel (or Word, or Access), and it takes a long time to execute, it is important to keep the user informed that the code is progressing. Psychologically, it can also have a tremendously positive effect on the perceived responsiveness and speed of your program if the user can see a visual representation of the current progress.
Common methods of keeping the user informed
Currently, a lot of people keep the user informed by allowing the actions of the macro to be seen. (i.e., the flicker of sheets being activated, cells being changed, etc...). This is generally a terrible idea unless the whole routine is finished very quickly. Excel experts should have learned by now that by setting Application.ScreenUpdating
Now that Excel's interface is frozen to speed up procedures, it's especially important to inform the user. Many people do this by setting the value of Application.StatusBar. This can hold any text, and updates even when screen updating is disabled. By changing this regularly, the programmer can give a play by play of the current position in the code, or display a percentage completion in a large loop.
Something truly impressive
If you want a great tool for keeping the user informed you should create a progress bar form, show the form before beginning code execution, and hide it afterwards. This is something you could do yourself, but to get you started, I've been employing and improving on my own custom progress bar for quite some time now. I think you should find it useful and very customizable:
Features
- Programmer can configure the progress bar with one function call, then all that is needed to update is to call SetValue.
- The progress bar's position and percentage label are automatically computed based on the minimum, maximum, and last set value.
- The status (caption above the progress bar) can be set dynamically to indicate additional information, such as the current stage of execution.
- An optional cancel button allows the user a mechanism to halt your lengthy process. The cancel button text can also be set, for instance to "Stop" or "Cancel Generation". The default caption is "Cancel". If set to vbNullString, the cancel button is hidden entirely.
- An optional label can show the time elapsed since the dialogue box was configured. (It is assumed that you will configure the dialogue directly before showing it). If this option is disabled, the progress bar update routine will not waste time in computing the elapsed time.
- An optional label can estimate the time remaining before completion. This is a very accurate estimate if you have appropriately set the min and max values. (You can test this in the example below.) This can be disabled, in which case no time is wasted in computing the remaining time.
- Your calling routine can get the current value of the progress bar, as well as the formatted run time. I use this, for instance, for logging, or to display on the status bar the final run time of the routine after it is complete.
Using the progress bar practically
You are responsible for picking an appropriate minimum and maximum value. For instance, if you are looping over R rows (from 1 to R) and C columns (from 1 to C), you should set the minimum to 0 and the maximum to ( R*C ). Furthermore, if you are currently on row i and column j, (and you are looping over all rows within each column), you should be setting the current value to [ i + (j-1)*R ]
If the cancel button is being displayed, you are responsible for periodically checking whether or not the cancel button has been pressed. Do this by checking whether ProgressDialogue.cancelIsP
The following code block shows the function calls you should remember to include in your loops when using the progress bar dialogue:
This produces the following progress bar:
If you are looping over code where you are making a large number of iterations over code that is very quick to execute, then you might find that updating the dialogue becomes your bottleneck. To prevent this, you can only update the progress bar periodically, using a quick check. For instance, you can say:
If index MOD 1000 = 0 Then ProgressDialogue.SetValue(
This way, the dialogue will only get updated every 1000 loops, and it will have much less impact on your code. You will want to play around with how often you update it, to balance the refresh rate with the amount of time spent updating the progress bar. Ideally, in other applications, a progress bar is kept up to date in a thread, but VBA has no support for threading.
Implemented Example and Code
Here, I've attached a workbook containing the 'wasting time' example above. You can use this to experiment with the ProgressDialogue form, and take a look at its implementation.
For convenience, I've also included in this article the code within the ProgressDialogue class:
Because .frm and .frx files cannot be attached on experts-exchange, I cannot provide you with those directly, but you can easily add this progress bar to any project by following these steps:
1. Download the example excel file above
2. Open the file, and open the VBA project (Alt+F11)
3. Export the ProgressDialogue form. (Save it somewhere you will remember in 5 seconds).
4. Import the exported file in any other excel project. (You can now delete the exported .frm and .frx files from your system.)
Remember that this same concept can be adapted to other Microsoft Applications, Excel is simply where I've built it here.
Building pleasant user interfaces is crucial to the success and reception of your VBA applications and I think this progress bar dialogue can go a long way to improving that. Feel free to use these ideas and code, and build on them. I wish you success!
--
Alain Bryden
References
Progress bar with a user form in Excel - http://support.microsoft.
GetTickCount system function in VBA - http://msdn.microsoft.com
by: DrewBowen on 2010-02-08 at 13:42:26ID: 9347
This is a really nice upgrade from the basic progress bar that I have been using. Thanks!