Adding controls to a frame in an Excel userform with VBA

后端 未结 3 723
眼角桃花
眼角桃花 2020-12-06 06:00

I need to create labels and buttons dynamically and then add them to a frame within a userform. How do I do this? Seems like it should be easier than it really is.

相关标签:
3条回答
  • 2020-12-06 06:02

    The following code demonstrates how you can dynamically populate a frame in a userform with controls...

    In the form I used I had a frame control named Frame1, so in the UserForm_Initialize you call Frame1.Controls.Add to embed a control in the frame. You can set the control which gets returned to a WithEvents control variable that you have defined in the UserForm code module so you can respond to events on whatever controls you want...

    So with this method you need to pre-write any event code you want for any controls you create...

    Also note that you can position and size your controls even if the top, left, width, and height properties don't necessarily come up in intellisense...

    Private WithEvents Cmd As MSForms.CommandButton
    Private WithEvents Lbl As MSForms.Label
    
    Private Sub UserForm_Initialize()
        Set Lbl = Frame1.Controls.Add("Forms.Label.1", "lbl1")
        Lbl.Caption = "Foo"
        Set Cmd = Frame1.Controls.Add("Forms.CommandButton.1", "cmd1")
    End Sub
    
    Private Sub Cmd_Click()
        Cmd.Top = Cmd.Top + 5
    End Sub
    
    Private Sub Lbl_Click()
        Lbl.Top = Lbl.Top + 5
    End Sub
    
    0 讨论(0)
  • 2020-12-06 06:10

    The Add Method

    To add controls to a userform or a frame you use the add method.

    SetControl = object.Add(ProgID [, Name [, Visible ]] )

    The first argument is going to reference what type of control you want to add, and it is ProgID which is defined as

    Programmatic identifier. A text string with no spaces that identifies an object class. The standard syntax for a ProgID is ... A ProgID is mapped to a class identifier (CLSID).

    A Functional Solution

    To make this process easier, let's use and enum to help manage the various controls.

    ' List of all the MSForms Controls.
    Public Enum MSFormControls
        CheckBox
        ComboBox
        CommandButton
        Frame
        Image
        Label
        ListBox
        MultiPage
        OptionButton
        ScrollBar
        SpinButton
        TabStrip
        TextBox
        ToggleButton
    End Enum
    

    With this enum, we can now easily create a function to get the ProgID string.

    ' Gets the ProgID for each individual control. Used to create controls using `Object.add` method.
    ' @see https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/add-method-microsoft-forms
    Public Function GetMSFormsProgID(control As MSFormControls) As String
        Select Case control
          Case MSFormControls.CheckBox:       GetMSFormsProgID = "Forms.CheckBox.1"
          Case MSFormControls.ComboBox:       GetMSFormsProgID = "Forms.ComboBox.1"
          Case MSFormControls.CommandButton:  GetMSFormsProgID = "Forms.CommandButton.1"
          Case MSFormControls.Frame:          GetMSFormsProgID = "Forms.Frame.1"
          Case MSFormControls.Image:          GetMSFormsProgID = "Forms.Image.1"
          Case MSFormControls.Label:          GetMSFormsProgID = "Forms.Label.1"
          Case MSFormControls.ListBox:        GetMSFormsProgID = "Forms.ListBox.1"
          Case MSFormControls.MultiPage:      GetMSFormsProgID = "Forms.MultiPage.1"
          Case MSFormControls.OptionButton:   GetMSFormsProgID = "Forms.OptionButton.1"
          Case MSFormControls.ScrollBar:      GetMSFormsProgID = "Forms.ScrollBar.1"
          Case MSFormControls.SpinButton:     GetMSFormsProgID = "Forms.SpinButton.1"
          Case MSFormControls.TabStrip:       GetMSFormsProgID = "Forms.TabStrip.1"
          Case MSFormControls.TextBox:        GetMSFormsProgID = "Forms.TextBox.1"
          Case MSFormControls.ToggleButton:   GetMSFormsProgID = "Forms.ToggleButton.1"
        End Select
    End Function
    

    And lastly, let's create a function that adds to a form or frame using our new function.

    ' Easly add control to userform or a frame.
    ' @returns {MSForms.control} The control that was created
    Public Function AddControl(userformOrFrame As Object _
                             , control As MSFormControls _
                             , Optional name As String = vbNullString _
                             , Optional visable As Boolean = True _
                            ) As MSForms.control
        Set AddControl = userformOrFrame.Controls.Add(GetMSFormsProgID(control), name, visable)
    End Function
    

    Demo

    To demo it, we can add every control to a blank userform by looping the enum.

    Private Sub UserForm_Initialize()
        demoAddingControlsToUserform
    End Sub
    
    Private Sub demoAddingControlsToUserform()
        ' Offset used to prevent controls
        ' overlapping as well as provide
        ' a height for the scrollbars
        Dim offsetHeight As Double
        
        ' Add each control to the userform
        ' and set top to make sure they are not overlapping
        Dim index As MSFormControls
        For index = CheckBox To ToggleButton
            With AddControl(Me, index)
                .Top = offsetHeight
                offsetHeight = offsetHeight + .Height
            End With
        Next
        
        ' Show scrollbars and adjust the height to show
        ' all the added controls.
        With Me
            .ScrollBars = fmScrollBarsVertical
            .ScrollHeight = offsetHeight + 20
        End With
    End Sub
    
    0 讨论(0)
  • 2020-12-06 06:22

    My variation on the theme above. This is just for a 4x4 array of buttons though. Create a userform and add this to its code. The same concepts can be used with your labels (or see the previous answer):

    Private cmdLots(20) As MSForms.CommandButton
    
    Private Sub UserForm_Initialize()
    For i = 1 To 4
    For j = 1 To 4
        k = i + (4 * j)
        Set cmdLots(k) = UserForm2.Controls.Add("Forms.CommandButton.1", "cmd1")
        With cmdLots(k)
            .Top = i * 25
            .Left = (j * 80) - 50
            .BackColor = RGB(50 * i, 50 * j, 0)
            .Caption = "i= " & i & "  j= " & j
        End With
    Next j
    Next i
    End Sub
    
    0 讨论(0)
提交回复
热议问题