Dynamic UserForms in VBA

Dynamic UserForms in VBA

by David Horowitz

Did you know that you can add and remove controls from a UserForm (also known as custom dialog boxes) at run-time? This means that you can change your UserForms based on certain conditions that exist during the operation of your VBA project—you’re not limited to the design of the UserForm that you created in the VBE designer!

To illustrate the technique, we’ll create a Word VBA Template which will prompt the user for the number of cars they own. (It allows for up to 20—hopefully that will be enough for most of us!) It will then display the correct number of textboxes to allow the user to enter the make of each car. When the user is done, the list of cars will be added to the document.

The key thing here we want to illustrate is the part where the dialog box will actually change to display the correct number of textboxes (with accompanying labels).

The primary method that accomplishes this task is Form.Controls.Add. (You can look it up in VBA Help.) Its syntax is like this:

Set ctl = Me.Controls.Add(ControlClass, Name, Visible)

For our purposes, ControlClass can have one of the following values:

"Forms.CheckBox.1"
"Forms.ComboBox.1"
"Forms.CommandButton.1"
"Forms.Frame.1"
"Forms.Image.1"
"Forms.Label.1"
"Forms.ListBox.1"
"Forms.MultiPage.1"
"Forms.OptionButton.1"
"Forms.ScrollBar.1"
"Forms.SpinButton.1"
"Forms.TabStrip.1"
"Forms.TextBox.1"
"Forms.ToggleButton.1"

These are text strings, so you must enclose them in quotes.

You can optionally specify the name of the new control using the Name parameter, for example, “TextBox7”, “txtFirstName”, “lblPrompt”, or “chkChicago”, whatever’s appropriate for your use.

Finally, you can choose to make the new control invisible by specifying False for the Visible parameter. The default is for Visible to be True.

So, for example, let’s say you would like to add a new label to your form. The form is named frmMyForm, and the new label should have the name “lblPrompt”. The method call would look like:

Dim myLabel as Label
Set myLabel = frmMyForm.Controls.Add _
    ("Forms.Label.1", "lblPrompt")

Don’t get confused about myLabel and lblPrompt. myLabel is an Object variable in VBA which is now set to refer to the control on the form by the name of “lblPrompt”.

Once you add a control to a form, you will certainly need to set some properties on the control, at least things like Top, Left, Width and Height. You can do this right after creation if you want, using, in our example, myLabel:

With myLabel
    .Left = 10
    .Top = 10
    .Width = 30
    .Caption = "Enter your name:"
End With

We’ve let the Height property default to whatever VBA sets for it initially.

Now later on in your code, if you want to refer to the newly added control, but you no longer have the myLabel reference, you can either use:

frmMyForm.Controls("lblPrompt”)

or

frmMyForm!lblPrompt

You cannot use the other syntax to refer to a control:

frmMyform.lblPrompt

when the control has been created dynamically using Controls.Add.

The example which accompanies this article, Dynamic UserForms Demo.dot, is a Word template which illustrates the techniques we’ve just describes in greater detail and in actual usage. You can download a copy of this template demo by clicking: HERE.

When you open this template, the Document_New method will call ShowCarsDialog, which will call the frmCars.Show method. frmCars has a label (lblNumCars) and textbox (txtNumCars), which prompt you to enter the number of cars you have. When you click on the Show Cars button (cmdShowCars), you will see a number of labels and textboxes equal to the number of cars you entered, allowing you to enter a make for each car. Then, when you click the Done button (cmdDone), all the car makes you entered will be inserted into the document and the dialog form (frmCars) will be unloaded.

If you want to change the number of cars again before you press Done, you can do that and when you click on Show Cars, the number of car labels and textboxes will change again to accommodate. So you can Add and Remove cars from the list before you click Done.

When you look at the code, you will see that each car make has a label and a textbox called lblCarN and txtCarN, where N is the number of the car. Each label is added to the form using this line of code:

Set theLabel = Me.Controls.Add _
    ("Forms.Label.1", "lblCar" & CurrentNumberOfCars)

Each textbox is added to the form using this line of code:

Set theTextBox = Me.Controls.Add _
    ("Forms.TextBox.1", "txtCar" & CurrentNumberOfCars)

After creating each control, we set a number of properties on it. We set each label’s caption using this line of code:

theLabel.Caption = "Car #" & CurrentNumberOfCars & ":"

You can see we even set the Accelerator property on each label to the number of the car using this line of code:

theLabel.Accelerator = CurrentNumberOfCars

If you tell the dialog box to remove some cars, the following lines of code are used:

Me.Controls.Remove "lblCar" & CurrentNumberOfCars
Me.Controls.Remove "txtCar" & CurrentNumberOfCars

In this article, we’ve learned how to use Form.Controls.Add to add controls to a form’s Controls collection at run-time. We then set properties on the control to make it look and function the way we want. We also learned how to dynamically remove a control from a form’s Controls collection using Form.Controls.Remove.

Now you can experiment with adding and removing controls to your forms whenever you need them. You will find many uses for this technique once you’ve learned how to do it.


This article originally appeared in Vol 3, Issue 2 of TechTrax.

Need further help getting your VBA code working right? Contact us or check out TechTrax’s free VBA support groups. See these links for details: http://groups.yahoo.com/group/Word_VBA/ and/or http://groups.yahoo.com/group/ExcelVBA/.

2 thoughts on “Dynamic UserForms in VBA

  1. David Horowitz Post author

    Mat, for TextBoxes, you want to reference the Value property.
    If you have a single textbox control object, using the code in your comment, you could use theTextBiox.Value as in:

    theTextBox.Value = "This is the value"

    or

    MsgBox theTextBox.Value

    If you have more than one, or need to reference it later in your code when you don’t have theTextBox anymore, then you’ll need to use the name of the control that you specified as the second parameter to the call to Me.Controls.Add. So let’s say for example, you know it was the second textbox. It’s name in the example above is “txtCar2”. To reference its Value property, you use either:

    MyForm.Controls("txtCar2").Value

    or

    MyForm!txtCar2.Value

    or if you are in the code for MyForm, you could simply use:

    Me!txtCar2.Value

    or perhaps even simply

    txtCar2.Value

    I hope this helps. If you have further questions, please feel free to ask.
    David

  2. Mat

    Hi!
    Thanks for the explanation.
    Regarding the textboxes named using “Set theTextBox = Me.Controls.Add _
    (“Forms.TextBox.1”, “txtCar” & CurrentNumberOfCars)”, how would you reference one of these specific textboxes in further code (if you wanted to get the value they contain)?

Leave a Reply

Your email address will not be published. Required fields are marked *