循环以逐行获取数据到userform行

时间:2015-04-28 23:01:08

标签: loops excel-vba vba excel

我正在使用VBS Excel 2010,我正在尝试编写一个循环来将WS中的17行,5列中的单元格传输到我的用户表单,该用户表单还有17行,5列文本框。

每行文本框都为它们所在的行编制索引。例如。 txt.Name1txt.City1 ... txt,County1。然后下一行文本框为txt.Name2txt.City2 ... txt,County2 ...

如何遍历每一行并将其传输到等待的一行文本框,而不是为每一行编写代码?

1 个答案:

答案 0 :(得分:0)

Cominterm是正确的,“你需要将Textbox控件放入控件数组中”。不幸的是,我发现他建议的链接特别有帮助。

我不需要按照数字访问表单控件多年,所以我生锈了。我按照我自己的方式处理了这个答案:隔离我不知道的功能并编写宏来探索该功能。我记得Controls集合,但不记得如何访问控件的类型,所以我查了一下。

表单上每个控件的详细信息都记录在Controls集合中,就像每个工作表的详细信息都记录在Worksheets集合中一样。如果txtName1是第6个控件,则可以将其属性设置为Controls(5),因为控件的编号为零。例如,代替txtName1.Text = "xxxxxx",您可以编写Controls(5) .Text = "xxxxxx"

我创建了一个用户表单,并用一种​​或两种控件填充它。然后我以你想要的格式添加了三行:

Design view of form

我创建了一个包含以下内容的模块:

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的数组中,我已指定该数组来保存所选属性。第二个块将数组中的值输出到立即Windows,以提供:

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集合时,我会为自己编写这种宏,我推荐这种方法。我仔细选择了适用于每种控件的属性。但是,通过检查类型,我可以访问限制为特定类型的属性。

刷新了我的记忆后,我准备编写符合您要求的宏。

您没有为所有五个列命名,所以我创建了五个我自己的列。我只定义了三行足以证明这种方法。您可以在上面列表的底部看到它们。

我创建了一个工作表“Data”并在其中放置了一些数据:

Sample data

我不知道您的数据是固定的还是可移动的,但是对于我的演示,我已将其修复并使用常量定义其位置。您可以替换我的常量的值或根据需要用变量替换我的常量。

我放弃了表单的原始代码,并将其替换为:

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集合中。

第二个代码块使用此数组将数据从工作表移动到表单以提供:

Form loaded with values from the worksheet

第二段代码应该可以很容易地适应您的要求。