Cominterm 是正确的,“您需要将 Textbox 控件放入控件数组中”。不幸的是,我不觉得他建议的链接特别有用。
多年来我不需要按数字访问表单控件,所以我很生疏。我以我自己的方式解决了这个问题:隔离我不知道的功能并编写宏来探索该功能。我记得 Controls 集合,但不记得如何访问控件的类型,所以我查了一下。
表单上每个控件的详细信息都记录在 Controls 集合中,就像每个工作表的详细信息都记录在 Worksheets 集合中一样。如果txtName1 是第6 个控件,您可以访问其属性,因为Controls(5),因为控件从零开始编号。例如,您可以写成Controls(5) .Text = "xxxxxx",而不是txtName1.Text = "xxxxxx"。
我创建了一个用户表单并在其中填写了每种类型的控件中的一两个。然后,我以您要提供的格式添加了三行:
我创建了一个模块,其中包含:
Option Explicit
Sub Test1()
Load UserForm1
UserForm1.Show vbModal
End Sub
我在表单中写了以下代码:
Private Type TypeCtrl
Height As Single
Left As Single
Name As String
Parent As String
Top As Single
TypeName As String
Width As Single
End Type
Dim CtrlDtl() As TypeCtrl
Private Sub cmdExit_Click()
Unload Me
End Sub
Private Sub UserForm_Initialize()
Dim InxCtrl As Long
Dim NameLenMax As Long
Dim ParentLenMax As Long
Dim TypeNameLenMax As Long
ReDim CtrlDtl(0 To Controls.Count - 1)
For InxCtrl = 0 To Controls.Count - 1
CtrlDtl(InxCtrl).Name = Controls(InxCtrl).Name
CtrlDtl(InxCtrl).Top = Controls(InxCtrl).Top
CtrlDtl(InxCtrl).Left = Controls(InxCtrl).Left
CtrlDtl(InxCtrl).Width = Controls(InxCtrl).Width
CtrlDtl(InxCtrl).Height = Controls(InxCtrl).Height
CtrlDtl(InxCtrl).Parent = Controls(InxCtrl).Parent.Name
CtrlDtl(InxCtrl).TypeName = TypeName(Controls(InxCtrl))
If NameLenMax < Len(CtrlDtl(InxCtrl).Name) Then
NameLenMax = Len(CtrlDtl(InxCtrl).Name)
End If
If ParentLenMax < Len(CtrlDtl(InxCtrl).Parent) Then
ParentLenMax = Len(CtrlDtl(InxCtrl).Parent)
End If
If TypeNameLenMax < Len(CtrlDtl(InxCtrl).TypeName) Then
TypeNameLenMax = Len(CtrlDtl(InxCtrl).TypeName)
End If
Next
If NameLenMax < Len("Name") Then
NameLenMax = Len("Name")
End If
If ParentLenMax < Len("Parent") Then
ParentLenMax = Len("Parent")
End If
Debug.Print "Inx Name" & Space(NameLenMax - 2) & _
" Top Left Height Width Parent" & _
Space(ParentLenMax - 6) & " Type name"
For InxCtrl = 0 To UBound(CtrlDtl)
With CtrlDtl(InxCtrl)
Debug.Print Right(" " & InxCtrl, 3) & " " & _
Left(.Name & Space(NameLenMax), NameLenMax) & " " & _
Right(Space(8) & Format(.Top, "#,###.00"), 8) & " " & _
Right(Space(8) & Format(.Left, "#,###.00"), 8) & " " & _
Right(Space(8) & Format(.Height, "#,###.00"), 8) & " " & _
Right(Space(8) & Format(.Width, "#,###.00"), 8) & " " & _
Left(.Parent & Space(ParentLenMax), ParentLenMax) & " " & _
.TypeName
End With
Next
End Sub
第一个代码块读取 Controls 集合,提取选定属性的值,然后将其存储在我指定用于保存选定属性的 TypeCtrl 类型的数组中。第二个块将数组中的值输出到即时窗口以给出:
Inx Name Top Left Height Width Parent Type name
0 Label1 12.00 24.00 18.00 72.00 UserForm1 Label
1 Label2 12.00 114.00 18.00 72.00 UserForm1 Label
2 TextBox1 12.00 210.00 18.00 72.00 UserForm1 TextBox
3 TextBox2 12.00 294.00 18.00 72.00 UserForm1 TextBox
4 ComboBox1 12.00 390.00 18.00 72.00 UserForm1 ComboBox
5 ComboBox2 48.15 24.00 18.00 72.00 UserForm1 ComboBox
6 ListBox1 42.00 120.00 72.00 72.00 UserForm1 ListBox
7 CheckBox1 48.00 294.00 18.00 108.00 UserForm1 CheckBox
8 OptionButton1 138.00 12.00 18.00 108.00 UserForm1 OptionButton
9 ListBox2 42.00 204.00 72.00 72.00 UserForm1 ListBox
10 CheckBox2 72.00 294.00 18.00 108.00 UserForm1 CheckBox
11 OptionButton2 162.00 12.00 18.00 108.00 UserForm1 OptionButton
12 ToggleButton1 132.00 144.00 40.00 36.00 UserForm1 ToggleButton
13 ToggleButton2 132.00 192.00 40.00 36.00 UserForm1 ToggleButton
14 Frame1 120.00 246.00 42.00 66.00 UserForm1 Frame
15 Frame2 120.00 324.00 54.00 72.00 UserForm1 Frame
16 Label3 18.00 12.00 18.00 48.00 Frame2 Label
17 cmdExit 126.00 414.00 24.00 72.00 UserForm1 CommandButton
18 CommandButton2 162.00 414.00 24.00 72.00 UserForm1 CommandButton
19 TabStrip1 192.00 18.00 54.00 90.00 UserForm1 TabStrip
20 TabStrip2 198.00 120.00 48.00 66.00 UserForm1 TabStrip
21 MultiPage1 198.00 186.00 66.00 102.00 UserForm1 MultiPage
22 MultiPage2 204.00 306.00 60.00 72.00 UserForm1 MultiPage
23 ScrollBar1 204.00 390.00 63.80 12.75 UserForm1 ScrollBar
24 SpinButton1 204.00 462.00 25.50 12.75 UserForm1 SpinButton
25 Image1 270.00 18.00 72.00 72.00 UserForm1 Image
26 SpinButton2 204.00 486.00 25.50 12.75 UserForm1 SpinButton
27 ScrollBar2 204.00 414.00 63.80 12.75 UserForm1 ScrollBar
28 txtName1 282.00 108.00 18.00 42.00 UserForm1 TextBox
29 txtStreet1 282.00 156.00 18.00 42.00 UserForm1 TextBox
30 txtTown1 282.00 204.00 18.00 42.00 UserForm1 TextBox
31 txtCounty1 282.00 252.00 18.00 42.00 UserForm1 TextBox
32 txtPostcode1 282.00 300.00 18.00 42.00 UserForm1 TextBox
33 txtName2 306.00 108.00 18.00 42.00 UserForm1 TextBox
34 txtStreet2 306.00 156.00 18.00 42.00 UserForm1 TextBox
35 txtTown2 306.00 204.00 18.00 42.00 UserForm1 TextBox
36 txtCounty2 306.00 252.00 18.00 42.00 UserForm1 TextBox
37 txtPostcode2 306.00 300.00 18.00 42.00 UserForm1 TextBox
38 txtName3 330.00 108.00 18.00 42.00 UserForm1 TextBox
39 txtStreet3 330.00 156.00 18.00 42.00 UserForm1 TextBox
40 txtTown3 330.00 204.00 18.00 42.00 UserForm1 TextBox
41 txtCounty3 330.00 252.00 18.00 42.00 UserForm1 TextBox
42 txtPostcode3 330.00 300.00 18.00 42.00 UserForm1 TextBox
我相信您只需要访问名称,但对此进行编码让我对可能发生的事情有了新的记忆。当我第一次需要了解 Control 集合时,我会为自己编写这种宏,我推荐这种方法。我仔细选择了每种控件都存在的属性。但是,通过检查类型,我可以访问仅限于特定类型的属性。
我记忆犹新,准备编写符合您要求的宏。
您没有命名所有五个专栏,所以我自己编了五个名字。我只定义了三行足以演示该方法。您可以在上面列表的底部看到它们。
我创建了一个工作表“数据”并在其中放置了一些数据:
我不知道您的数据是固定的还是可移动的,但为了我的演示,我已将其固定并用常量定义了它的位置。您可以根据需要替换我的常量的值或用变量替换我的常量。
我丢弃了表单的原始代码并将其替换为:
Option Explicit
Const WshtName As String = "Data"
Const RowDataTop As Long = 3
Const ColDataLeft As Long = 2
Const RowDataBot As Long = 5
Const ColDataRight As Long = 6
Dim CtrlForAddressElement(1 To ColDataRight - ColDataLeft + 1, _
1 To RowDataBot - RowDataTop + 1) As Long
Private Sub cmdExit_Click()
Unload Me
End Sub
Private Sub UserForm_Initialize()
Dim ColDataCrnt As Long
Dim ColFormCrnt As Long
Dim InxCtrl As Long
Dim RowDataCrnt As Long
Dim RowFormCrnt As Long
ReDim CtrlDtl(0 To Controls.Count - 1)
' Store index number for each control of the address block
For InxCtrl = 0 To Controls.Count - 1
If Left(Controls(InxCtrl).Name, 7) = "txtName" Then
RowFormCrnt = Val(Mid(Controls(InxCtrl).Name, 8))
CtrlForAddressElement(1, RowFormCrnt) = InxCtrl
ElseIf Left(Controls(InxCtrl).Name, 9) = "txtStreet" Then
RowFormCrnt = Val(Mid(Controls(InxCtrl).Name, 10))
CtrlForAddressElement(2, RowFormCrnt) = InxCtrl
ElseIf Left(Controls(InxCtrl).Name, 7) = "txtTown" Then
RowFormCrnt = Val(Mid(Controls(InxCtrl).Name, 8))
CtrlForAddressElement(3, RowFormCrnt) = InxCtrl
ElseIf Left(Controls(InxCtrl).Name, 9) = "txtCounty" Then
RowFormCrnt = Val(Mid(Controls(InxCtrl).Name, 10))
CtrlForAddressElement(4, RowFormCrnt) = InxCtrl
ElseIf Left(Controls(InxCtrl).Name, 11) = "txtPostcode" Then
RowFormCrnt = Val(Mid(Controls(InxCtrl).Name, 12))
CtrlForAddressElement(5, RowFormCrnt) = InxCtrl
End If
Next
' Move data from worksheet to form
With Worksheets(WshtName)
For RowDataCrnt = RowDataTop To RowDataBot
RowFormCrnt = RowDataCrnt - RowDataTop + 1
For ColDataCrnt = ColDataLeft To ColDataRight
ColFormCrnt = ColDataCrnt - ColDataLeft + 1
InxCtrl = CtrlForAddressElement(ColFormCrnt, RowFormCrnt)
Controls(InxCtrl).Text = .Cells(RowDataCrnt, ColDataCrnt).Value
Next
Next
End With
End Sub
我有一个全局数组 CtrlForAddressElement,我根据需要调整其大小以处理由常量定义的范围。
第一个代码块将带有索引的数组加载到 15 个文本框的 Controls 集合中。
第二个代码块使用这个数组将数据从工作表移动到表单中:
第二个代码块应该很容易适应您的要求。