简体   繁体   中英

Excel Macro/Userform: “For Each” not looping through controls in TabIndex order

Could someone help me understand how to adjust the order that a "For Each" loop will cycle through a UserForm's controls? (I know it's not cycling via "TabIndex" order, and I understand it doesn't care about the "TabIndex" when looping programatically in "For Each".)

I added controls to my current UserForm (screenshot below) by copying a single controls for a couple and then a group of controls (Ctrl+click, copy/paste) from a previous form, and adding controls after that. The group of controls ("Site Name" to "City,St,Zip") cycles in reverse-order (bottom to top). Ideally, I want to cycle from the top to bottom continuously.

I tried to re-order by right-clicking and "Send Backward/Forward" but that does nothing for my "For Each" loop.

For Each txtBox In ADSheaderForm.Controls
    If TypeName(txtBox) = "TextBox" Then
        If txtBox.Name = "stNmTxtBx" Then
            ReDim Preserve txtArr(txtNum)
            txtArr(txtNum) = txtBox.Text
            txtNum = txtNum + 1
        Else
            If txtBox.Text = "" Or txtBox.Text = "Optional" Then
                ReDim Preserve txtArr(txtNum)
                txtArr(txtNum) = "Not Entered"
                txtNum = txtNum + 1
            Else
                ReDim Preserve txtArr(txtNum)
                txtArr(txtNum) = txtBox.Text
                txtNum = txtNum + 1
            End If
        End If
    End If
Next

在此输入图像描述

The controls seem to be added into the form by copy/paste order(a group often has last as first), and you cannot change that order of controls.

You could look at the following code and see how you might use the tabIndex to reorder the controls for your purpose.

  Dim ctrl As Control
  Dim str As String
  Dim v() As Control
  Dim i As Long
  Dim arrItem As Variant

  i = ADSheaderForm.Controls.count
  ReDim v(1 To i)

  For Each ctrl In ADSheaderForm.Controls
        Set v(ctrl.TabIndex + 1) = ctrl
  Next ctrl

  For Each arrItem In v
        str = str & arrItem.Name & vbNewLine
        'Actually do your code as above within this loop e.g. if typeName = blabla
  Next arrItem

  MsgBox str

If you set the tabIndexes to run as you do, then this will push them into an array by tabIndex position. Then you cycle through the array.

I had a similar problem working with an Access form and was looking for solutions, so I stumbled upon this post. Because of my very limited knowledge of VBA syntax, I had to turn MarcoMarc's idea (thanks for that, btw) into something I would know how to write.

Here's what I came up with... It worked for me:

Dim i as Integer
Dim ctl as Control

For i = 1 To ADSheaderForm.Controls.Count
    For Each ctl In ADSheaderForm.Controls
        If ctl.TabIndex = i then
            'do something 
            Exit For
        End If
    Next ctl
Next i

You can reorder them all at once, as MacroMarc touched on, using the copy/paste function but the controls must be selected REVERSE order from what you want them to cycle.

For your example, in the userform you would select the textbox next to "Scope of Work", hold CTRL and click on each subsequent control, again in reverse order. Cut, paste and voilà, they will cycle in the correct order.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM