Цикл ctrl формы Excel

Я пытаюсь зациклить все элементы управления (после игнорирования индексов вкладок 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

Похоже, что индекс вкладки к чему-то привязан, и цикл игнорирует способ, которым он установлен в Свойствах. Где я ошибаюсь или как я могу это исправить?

Цикл VBA - это не табуляция (это действие пользовательского интерфейса). Почему порядок циклов должен быть таким же, как порядок табуляции? Если вы этого хотите, вы можете создать свою собственную коллекцию. Это интересный вопрос.

John Coleman 04.05.2018 18:24
Преобразование HTML-таблицы в профессиональный документ Excel
Преобразование HTML-таблицы в профессиональный документ Excel
Это самый простой способ создания Excel из HTML-таблицы.
Импорт excel в laravel в базу данных
Импорт excel в laravel в базу данных
Здравствуйте, дорогой читатель, в этой статье я расскажу практическим и быстрым способом, как импортировать файл Excel в вашу базу данных с помощью...
1
1
90
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Цикл 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.

Спасибо! Теперь это имеет смысл, я решил предложить вам ваше первое решение, чтобы разобраться в проблеме и обновить мой код, чтобы изменить имя формы на меня. Хорошего дня :)

Robert Bluszcz 08.05.2018 09:17

Другие вопросы по теме