0

I want to create a vbModeless dynamic user form during run-time. The user form has just one button, that's it. The form works fine using vbModal but unfortunately with vbModeless I can't get the click event for the button to work. Clicking the button does not call the event. I'm using the following steps/code:

  • Created an empty user form named UserForm1

  • Created a module named Modul1 with the following code:

    Sub CreateFormControls()
    
      'Create Command Button
      Dim Button01 As MSForms.CommandButton
      Set Button01 = UserForm1.Controls.Add("Forms.CommandButton.1", "dynButton01", False)
      Button01.Visible = True
    
      'Reference click event
      Dim ClickEvents As New Class1
      Set ClickEvents.ButtonEvent = Button01
    
      'Show User Form
      UserForm1.Show vbModeless '-> THIS DOES NOT WORK, only vbmodal works
    
    End Sub
    
  • Created a class module named Class1 with the following code:

     Public WithEvents ButtonEvent As MSForms.CommandButton
    
     Private Sub ButtonEvent_Click()
         MsgBox "Test"
         Unload UserForm1
     End Sub
    

Is there a way to get this working with vbModeless or is there a different work around?

Note: I haven't used dynamic forms very much yet, and I copied/modified the shown implementation using an existing code snippet without completely understanding how the button object references the click event e.g. why a separate class is needed and I can't do it within the procedure in Modul1. I assume within lies the reason why it doesn't work opening the form non-modal. A little light on this issue would be appreciated as well.

Albin
  • 1,000
  • 1
  • 11
  • 33
  • `ClickEvents` should be declared at the module level, that is, at the top of the module before any other procedure. – Domenic Nov 01 '20 at 17:07
  • By the way, it looks like you have a typo. It looks like it should be `Set ClickEvents.ButtonEvent = Button01`. – Domenic Nov 01 '20 at 17:15
  • I would suggest that you routinely place `Option Explicit` at the very top of any module to help catch errors, such as the one above. – Domenic Nov 01 '20 at 17:16
  • @Domenic yeah, you are correct about the typo, thanks. I changed it in my code but I forgot to change that here in the question (so it's not the issue in the actual code). Also I use Option Explicit, it's just not relevant for this question, so I left it out. The deceleration of the event In the class module it is on top, before any procedure (in fact the class and module in my test only contains the code shown in this example) – Albin Nov 01 '20 at 17:48

1 Answers1

1

ClickEvents should be declared at the module level...

Option Explicit

Dim ClickEvents As New Class1 'declared at the module level

Sub CreateFormControls()

  'etc
  '
  '

End Sub
Domenic
  • 7,844
  • 2
  • 9
  • 17
  • Ah, I see, you meant the class deceleration. Why is that? Is the class instance destroyed once the sub in the module finishes when the deceleration is done within the sub (as in the question)? And how long does the class instance live if it's declared in the module? – Albin Nov 01 '20 at 18:52
  • Yes, that's correct. A variable declared within a procedure is destroyed once the procedure ends, whereas a variable declared at the module level is destroyed when the program ends. The former is referred to as a local variable, and the latter a global variable. – Domenic Nov 01 '20 at 19:24
  • that I know, but what exactly does "program ends" mean in this context (strictly speaking the "program" is just the one sub, so it should end once the sub ends, which obviously isn't the case)? – Albin Nov 01 '20 at 19:34
  • 1
    The "program" in this case is the VBProject associated with whatever object you're running this in (workbook? document?). Eg. see https://stackoverflow.com/questions/7041138/what-is-the-lifetime-of-a-global-variable-in-excel-vba/7043901#7043901 – Tim Williams Nov 01 '20 at 19:43