VBA控件集合(数组?)

4

在寻找一种在用户窗体上模拟可填写网格的方法时,我发现了Mr. Excel网站上的这个内容:

Dim Grid(1 To 10, 1 To 5) As MSForms.TextBox

Private Sub UserForm_Initialize()

Dim x As Long
Dim y As Long

For x = 1 To 10
    For y = 1 To 5
        Set Grid(x, y) = Me.Controls.Add("Forms.Textbox.1")
        With Grid(x, y)
            .Width = 50
            .Height = 20
            .Left = y * .Width
            .Top = x * .Height
            .SpecialEffect = fmSpecialEffectFlat
            .BorderStyle = fmBorderStyleSingle
        End With
    Next y
Next x

End Sub

我认为这太棒了。不要告诉我的客户,但我不知道你可以通过使用Dim Groupname(1 to x, 1 to y)作为MSForms.TextBox来创建“文本框”的“数组”。

我试图了解更多信息,但搜索“控件数组”并没有指向这个功能。所以在这里问一下:

  1. “Array”是这种能力的真正术语吗?(这样我就可以进行更好的搜索以获取更多信息。)
  2. “网格”中的所有控件都是文本框。我想我可以像标签、按钮等一组控件一样做到同样的效果。但是是否有办法包括不同类型的控件?(例如,我希望第一列是标签,最后一列是组合框)

2
好的,这是一个控件数组,所以术语上没有问题... 但如果你搜索“控件数组”,你可能会得到略有不同的结果,这些结果涉及处理控件网格中的事件,而无需为每个控件编写单独的处理程序 - 例如,请参见https://bettersolutions.com/excel/macros/vba-control-arrays.htm。 如果您将数组声明为As Object,则可以将任何类型的对象放入其中。 - Tim Williams
2个回答

5
您可以按以下方式实现:
Option Explicit

Dim Grid(1 To 10, 1 To 5) As Object  ' declare as object so it can take any control you like

Private Sub UserForm_Initialize()
    Dim iCol As Long
    For iCol = LBound(Grid, 2) To UBound(Grid, 2)  ' loop through all columns 1 to 5

        Dim iRow As Long
        For iRow = LBound(Grid, 1) To UBound(Grid, 1)  ' loop through all rows 1 to 10

            Select Case iCol                
                Case LBound(Grid, 2)  ' first column
                    Set Grid(iRow, iCol) = Me.Controls.Add("Forms.Label.1")
                    With Grid(iRow, iCol)
                        .Width = 50
                        .Height = 20
                        .Left = iCol * .Width
                        .Top = iRow * .Height
                        .Caption = iRow
                        .SpecialEffect = fmSpecialEffectFlat
                        .BorderStyle = fmBorderStyleSingle
                    End With
                    
                Case UBound(Grid, 2)  ' last column
                    Set Grid(iRow, iCol) = Me.Controls.Add("Forms.Combobox.1")
                    With Grid(iRow, iCol)
                        .Width = 50
                        .Height = 20
                        .Left = iCol * .Width
                        .Top = iRow * .Height
                        .SpecialEffect = fmSpecialEffectFlat
                        .BorderStyle = fmBorderStyleSingle
                    End With
                    
                Case Else  ' all other columns
                    Set Grid(iRow, iCol) = Me.Controls.Add("Forms.Textbox.1")
                    With Grid(iRow, iCol)
                        .Width = 50
                        .Height = 20
                        .Left = iCol * .Width
                        .Top = iRow * .Height
                        .SpecialEffect = fmSpecialEffectFlat
                        .BorderStyle = fmBorderStyleSingle
                    End With
                    
            End Select
        Next iRow
    Next iCol
End Sub

但你需要按列进行循环。因此,首先是列循环,然后再进行行循环。使用 Select Case 可以在标签、组合框和文本框之间切换列。

所以在你的情况下,仍然有5列,每列有10个控件,但第一列是标签,最后一列是组合框:

enter image description here


我喜欢这个。你有没有注意到“带网格”块大多数是相同的,所以你可以将它们移动到Case块之外?(除了那个讨厌的“.Caption”)。 - Shawn V. Wilson
@ShawnV.Wilson 是的,你可以把它们移到外面,我没有这样做是因为我猜在实际情况下它们可能不再如此相同。例如,您可能想要使用一些数据填充组合框,也许您不希望标签具有边框或不同的大小。所以我把它们放在了Case语句中。但是,如果它们适用于所有类型的控件,则将参数定义在Case之外是有意义的。 - Pᴇʜ

3
实际上,表单有一个名为“controls”的属性,它是一个集合(而不是数组)。当你通过代码动态添加控件时,它会自动进入“controls”集合。你当然可以创建一个控件数组(就像你在问题中展示的那样),但是当你使用代码动态创建控件时,并没有涉及到数组。这里有一篇文章展示了如何编程添加标签: 使用代码添加标签 这里有一个页面谈论如何添加组合框: 使用代码添加组合框 如果您需要将事件处理程序添加到动态添加的控件中,则存在一些限制,并且可能有些复杂。这是一个链接,讨论了这个问题: 向动态生成的控件添加事件处理程序 祝您成功完成这个项目!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接