Я пытаюсь зациклить все элементы управления (после игнорирования индексов вкладок 1 и 2) в форме Excel и использовать индекс вкладок для каждого элемента управления для поиска значения на листе. Я установил порядок индекса табуляции с помощью свойств, надеясь, что цикл будет идти в числовом порядке, но когда я отлаживаю. Распечатываю цикл управления, я получаю следующий порядок: 2,3,20,5,6,7
Все элементы управления начинаются с txt.
Код:
For Each ctrl In PipelineUpdateForm.Controls
If Left(ctrl.Name, 3) = "txt" And ctrl.TabIndex > 2 Then
ColumnN = ColumnN + 1
ctrl.Value = Application.WorksheetFunction.VLookup(LookupObject, Sheets("PipelineRawEntries").Range("B2:AS4"), ColumnN, False)
End If
Next ctrl
Похоже, что индекс вкладки к чему-то привязан, и цикл игнорирует способ, которым он установлен в Свойствах. Где я ошибаюсь или как я могу это исправить?


Цикл For Each будет перебирать элементы управления в том порядке, в котором они были добавлены в форму (хотя я не думаю, что это определено или гарантировано каким-либо образом), как это было бы с любым другим типом Collection.
For Each работает, вытягивая счетчик коллекции. Если вы посмотрите на MSForms.Controls в Обозреватель объектов (F2), щелкните правой кнопкой мыши пустую область в обозревателе объектов и отметьте опцию «Показать скрытые элементы», вы увидите скрытый член _NewEnum на типе.
_NewEnum также существует в Excel.Workbooks, Excel.Range, VBA.Collection и во всем остальном, что вы можете повторять с помощью цикла For Each: если вы пишете собственный класс коллекции, вам также понадобится член NewEnum() As IUnknown со специальным атрибутом члена (VB_UserMemId = -4) - это счетчик это то, что среда выполнения VBA использует для получения следующей ссылки на объект в коллекции.
И он ничего не знает о TabIndex элемента управления. TabIndex определяет, что элементы управления порядком получают фокус, когда пользователь нажимает клавишу Tab для итерации элементов управления - это не имеет ничего общего с циклом For Each.
Если вам нужно выполнить итерацию ваших элементов управления в определенном порядке (FWIW, я не могу придумать законную причину для этого), вы можете указать порядок в самих именах элементов управления (например, txtSomethingSomething1, txtSomethingSomething2, ...) и затем получить элементы управления по имени, используя цикл For...Next (который был бы менее эффективным, поскольку коллекции объектов хочу должны быть перечисленный):
Dim i As Long
Dim currentTextBox As TextBox
For i = 1 To 20
Set currentTextBox = Me.Controls("txtSomethingSomething" & i)
currentTextBox.Value = Application.WorksheetFunction.VLookup(...)
Next
В качестве альтернативы вы можете сохранить нужный вам индекс ColumnN в свойстве Tag каждого элемента управления - и получить гораздо более эффективный фрагмент логики (хотя надежность спорна ... есть много способов сделать это, это просто способ один):
For Each ctrl In Me.Controls
If ctrl.Tag <> vbNullString Then
columnN = ctrl.Tag
ctrl.Value = Application.WorksheetFunction.VLookup(...)
End If
Next
Обратите внимание, что я использовал Me.Controls вместо PipelineUpdateForm.Controls; Я предполагаю, что этот код находится в коде программной части формы - в этом случае вы должны ссылаться на свой экземпляр формы с ключевым словом Me, а не с именем формы. Рано или поздно вы неизбежно столкнетесь с довольно распространенными проблемами, если будете продолжать ссылаться на форму экземпляр по умолчанию в ее коде программной части. Моя статья о UserForm1.Show в октябре прошлого года подробно описывает все это.
Боковое примечание, вы, вероятно, захотите перетащить Sheets("PipelineRawEntries").Range("B2:AS4") в локальную объектную переменную вместо того, чтобы разыменовывать один и тот же объект снова и снова на каждой итерации цикла:
Dim lookupRange As Range
Set lookupRange = ActiveWorkbook.Workheets("PipelineRawEntries").Range("B2:AS4")
А затем используйте lookupRange в функции VLookup.
Спасибо! Теперь это имеет смысл, я решил предложить вам ваше первое решение, чтобы разобраться в проблеме и обновить мой код, чтобы изменить имя формы на меня. Хорошего дня :)
Цикл VBA - это не табуляция (это действие пользовательского интерфейса). Почему порядок циклов должен быть таким же, как порядок табуляции? Если вы этого хотите, вы можете создать свою собственную коллекцию. Это интересный вопрос.