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

发布于 2024-07-14 01:08:33 字数 72 浏览 6 评论 0原文

我需要动态创建标签和按钮,然后将它们添加到用户窗体内的框架中。 我该怎么做呢? 看起来应该比实际情况更容易。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

友欢 2024-07-21 01:08:33

下面的代码演示了如何使用控件动态填充用户窗体中的框架...

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

因此,使用此方法,您需要预先编写您想要的任何事件代码想要您创建的任何控件...

另请注意,即使顶部、左侧、宽度和高度属性不一定出现在智能感知中,您也可以定位控件并调整其大小...

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

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
顾北清歌寒 2024-07-21 01:08:33

添加方法

要将控件添加到用户窗体或框架,您可以使用添加方法。

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

第一个参数将引用您要添加的控件类型,它是 ProgID其定义为

程序化标识符。 不带空格的文本字符串,用于标识对象类。 ProgID 的标准语法是...ProgID 映射到类标识符 (CLSID)。

功能性解决方案

为了使这个过程更容易,让我们使用枚举来帮助我们管理各种控件。

' 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

有了这个枚举,我们现在可以轻松创建一个函数来获取所有控件的 ProgID 字符串。

' Gets the ProgID for each individual control. Used to create controls using `Object.add` method.
' @see https://learn.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

最后,让我们创建一个使用新函数添加到表单或框架的函数。

' 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 visible As Boolean = True _
                        ) As MSForms.control
    Set AddControl = userformOrFrame.Controls.Add(GetMSFormsProgID(control), name, visible)
End Function

使用这样的枚举的美妙之处在于,我们现在对所有控件都有智能感知,而不必记住它们。

演示显示intellisense

演示

为了演示它,我们可以通过循环枚举将每个控件添加到空白用户窗体。

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

演示用户表单具有所有控件

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 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.

' Gets the ProgID for each individual control. Used to create controls using `Object.add` method.
' @see https://learn.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 visible As Boolean = True _
                        ) As MSForms.control
    Set AddControl = userformOrFrame.Controls.Add(GetMSFormsProgID(control), name, visible)
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 showing intellisense

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

Demo Userform with all controls

寄人书 2024-07-21 01:08:33

我对上述主题的变体。 但这仅适用于 4x4 的按钮阵列。 创建一个用户表单并将其添加到其代码中。 相同的概念可以用于您的标签(或参见前面的答案):

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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文