简体   繁体   English

使用 VBA 向 Excel 用户窗体中的框架添加控件

[英]Adding controls to a frame in an Excel userform with VBA

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.看起来它应该比实际更容易。

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.在我使用的窗体中,我有一个名为 Frame1 的框架控件,因此在 UserForm_Initialize 中调用 Frame1.Controls.Add 将控件嵌入到框架中。 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...您可以设置返回到您在 UserForm 代码模块中定义的 WithEvents 控件变量的控件,以便您可以响应您想要的任何控件上的事件...

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

My variation on the theme above.我对上述主题的变体。 This is just for a 4x4 array of buttons though.不过,这仅适用于 4x4 按钮阵列。 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

The Add Method Add方法

To add controls to a userform or a frame you use the add method.要将控件添加到用户窗体或框架,请使用add方法。

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第一个参数将引用您要添加的控件类型,它是ProgID ,定义为

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). ProgID 的标准语法是... ProgID 映射到类标识符 (CLSID)。

A Functional Solution功能性解决方案

To make this process easier, let's use an enum to help manage the various controls for us.为了使这个过程更容易,让我们使用枚举来帮助我们管理各种控件。

' 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 for all controls.有了这个枚举,我们现在可以轻松创建一个函数来获取所有控件的 ProgID 字符串。

' 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

The beauty of using enums like this is that we now have a intellisense for all the controls and don't have to memorize them all.像这样使用枚举的美妙之处在于我们现在对所有控件都有智能感知,而不必记住所有控件。

演示显示智能感知

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
    ' (Although this looks odd, you can actually loop enums this way.)
    Dim control As MSFormControls
    For control = CheckBox To ToggleButton
        With AddControl(Me, control)
            .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

带有所有控件的演示用户表单

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM