Questions similar to this appear on the Bentley Discussion Groups. This appeared in the VBA discussion group.
Q You are writing code that may take a long time to execute, and want to provide feedback to your users. You are looking for answers to questions like these …
A A solution to those questions is to pop a modeless UserForm with a
Progress Bar. Put a Cancel button on there while you're at it, to let your user stop a lengthy task.
Unfortunately there's a catch, but it's one you can work around: VBA does not provide a Progress Bar control.
However, there's one on your Windows system right now, and you can borrow it for your VBA project.
VBA lets you add controls that are present in your computer. Microsoft provide many different types of control,
usually bundled in a .dll or .ocx COM library. You can add these controls to your VBA
project by taking the following steps …
UserForm for editing
ProgressBar on your UserForm
Now you need some code. You can download the VBA project with the code shown here. Your worker module probably contains a loop, and inside that loop is a lengthy task.
Each time your code goes through the loop, you want to increment the ProgressBar.
You also want to check to see if the Cancel button was pressed. Here's some example code,
with a trivial operation that does nothing but waste time …
Public Sub Main()
Dim frm As New frmProgressBar
frm.Show vbModeless
Dim bStop As Boolean
bStop = False
Const MaxCount As Long = 100
' Set the maximum value on the Progress Bar
frm.FinalValue = MaxCount
' A variable that measures our progress
Dim counter As Long
counter = 0
Do While (Not bStop And counter < MaxCount)
Dim delay As Long
Dim trivial As Long
trivial = 0
For delay = 1 To 500000
trivial = CLng(1.17 + CDbl(trivial))
Next delay
counter = 1 + counter
frm.Increment
frm.ProgressBar1.Refresh
DoEvents ' Essential to let VBA respond to a user action
bStop = frm.Cancel
Loop
If (bStop) Then
MsgBox "Cancel Pressed", vbInformation Or vbOKOnly, "Operation Cancelled"
ShowMessage "User cancelled operation", "User cancelled operation", msdMessageCenterPriorityWarning
Else
ShowMessage "Operation completed normally", "Operation completed normally", msdMessageCenterPriorityInfo
End If
Unload frm
End Sub
Without the DoEvents statement in the loop, your code won't know about the Cancel button.
DoEvents momentarily stops your code while Windows catches up with itself. This give the ProgressBar
an opportunity to redraw itself and, most importantly, lets VBA know whether the user wants to cancel.
Your UserForm also requires some code to monitor the Cancel button.
This examples assume that you have placed a ProgressBar control with the name ProgressBar1.
We set a flag to
indicate that the user has pressed that Cancel button, with a read-only property that lets your main loop interrogate that flag …
Private m_bCancel As Boolean' ---------------------------------------------------------------------Public Property Get Cancel() As Boolean Cancel = m_bCancel End Property' ---------------------------------------------------------------------Public Property Let FinalValue(ByVal v As Long) ProgressBar1.Max = CSng(v) End Property' ---------------------------------------------------------------------Public Sub Increment() If (ProgressBar1.Value < ProgressBar1.Max) Then ProgressBar1.Value = ProgressBar1.Value + 1 End If End Sub' ---------------------------------------------------------------------Private Sub cmdCancel_Click() m_bCancel = True End Sub' ---------------------------------------------------------------------Private Sub UserForm_Initialize() m_bCancel = False ProgressBar1.Min = 0 End Sub
A sample project is available. It includes code similar to that above and the progress form.
You can download a ZIP file, and then extract ProgressBarExample.mvba to a folder
that MicroStation can find. A good place to put it would be
C:\Program Files\Bentley\WOrkspace\Standards\vba, or any other folder specified
in the MS_VBASEARCHDIRECTORIES configuration variable.