Why does Showing a UserForm as Modal Stop Code Execution?

modal-dialog, userform, vba

Solution

I think I figured this out.

After `Me.Show` the UserForm_Activate event fires. If there is no code in the UserForm_Activate procedure nothing will happen because VBA is waiting for `Me.Hide`.

So the order of events is: `Me.Show` > `UserForm_Activate` > `Me.Hide`

Any code that I want to run must be in the UserForm_Activate procedure and must be before `Me.Hide`.

The structure is very strict, but I may be able to use that structure to my advantage.

Problem

The following VBA code stops at `Me.Show`. From my tests, it seems that `Me.Show` stops all code execution, even if the code is inside the UserForm. This part is outside the UserForm: ``` Public Sub TestProgress() Dim objProgress As New UserForm1 objProgress.ShowProgress Unload objProgress End Sub ``` This part is inside the UserForm: ``` Private Sub ShowProgress() Me.Show vbModal Dim intSecond As Integer For intSecond = 1 To 5 Application.Wait Now + TimeValue("0:00:01") Me.ProgressBar1.Value = intSecond / 5 * 100 Next intSecond Me.Hide End Sub ``` The code stops at `Me.Show`, after the UserForm is displayed. There is no error, it just discontinues executing code. It seems that the only way to execute code inside a modal UserForm in VBA is to include it in the UserForm_Activate procedure like this: This part is outside the UserForm: ``` Public Sub TestProgress() Dim objProgress As New UserForm1 Load objProgress Unload objProgress End Sub ``` This part is inside the UserForm: ``` Private Sub UserForm_Initialize() Me.Show vbModal End Sub Private Sub UserForm_Activate() Dim intSecond As Integer For intSecond = 1 To 5 Application.Wait Now + TimeValue("0:00:01") Me.ProgressBar1.Value = intSecond / 5 * 100 Next intSecond Me.Hide End Sub ``` Of course, I can't put `Me.Show` inside UserForm_Activate because that procedure only fires after the UserForm Show event. The documentation for `UserForm.ShowModal` says "When a UserForm is modal, the user must supply information or close the UserForm before using any other part of the application. No subsequent code is executed until the UserForm is hidden or unloaded." I am trying to use a modal UseForm as a progress bar to prevent the user from interacting with the application while a process runs. But this will be difficult to accomplish if all my code has to be within the UserForm_Activate procedure. Am I missing something here? Why does all code execution stop at `Me.Show`?

Original source