【问题标题】:Looping to get data row by row to the userform rows循环以逐行获取数据到用户表单行
【发布时间】:2015-07-08 00:18:21
【问题描述】:

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

每一行文本框都针对它们所在的行进行索引。例如。 txt.Name1txt.City1...txt,County1。那么下一行文本框是txt.Name2,txt.City2...txt,County2...

如何在不为每一行编写代码的情况下遍历每一行并将其传输到等待的文本框行?

【问题讨论】:

标签: loops excel vba


【解决方案1】:

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

第二个代码块使用这个数组将数据从工作表移动到表单中:

第二个代码块应该很容易适应您的要求。

【讨论】:

    猜你喜欢
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-15
    • 2012-11-12
    • 1970-01-01
    相关资源
    最近更新 更多