Цикл через переменные VBA

Я делаю пользовательскую форму в VBA, где у меня есть текстовое поле, где я могу искать элементы. У меня около 30 текстовых полей, поэтому я хочу сократить код, используя цикл, вместо того, чтобы копировать и вставлять один и тот же код 30 раз.

Проблема: я не знаю, как пройти через общедоступную переменную

Public Variable: Public oEventHandler(Number) As New clsSearchableDropdown
     oEventHandler would go from 1 to 30 (e.g oEventHandler2,oEventHandler3...oEventHandler30)
     clsSearchableDropdown is the Class Module for the search feature

Text Box: TextBox(Number)
ListBox: ListBox(Number)

Вот исходный код (нет проблем только для сравнения):

  With oEventHandler1
                            
    ' Attach the textbox and listbox to the class
                                        
        Set .SearchListBox = Me.ListBox1
        Set .SearchTextBox = Me.TextBox1
                                        
    ' Default settings
                                    
        .MaxRows = 10
        .ShowAllMatches = True
        .CompareMethod = vbTextCompare
        .WindowsVersion = False
                            
  End With

Вот что я пытаюсь сделать:

  Dim i As Integer

  for i = 1 to 30

    With Me.Controls.Item("oEventHandler" & i)
                            
      ' Attach the textbox and listbox to the class
                                        
          Set .SearchListBox = Me.Controls.Item("ListBox" & i)
          Set .SearchTextBox = Me.Controls.Item("TextBox" & i)
                                        
      ' Default settings
                                    
          .MaxRows = 10
          .ShowAllMatches = True
          .CompareMethod = vbTextCompare
        .WindowsVersion = False
                              
    End With

  Next i

Я знаю, что oEventHandler не является элементом управления, но есть ли аналогичный код, который я могу использовать для перебора общедоступной переменной?

То, что вы предлагаете, не кажется мне экстремальным. Это не работает, когда вы пытаетесь это сделать? Объекты VBA UserForm имеют только 3 коллекции (страницы, вкладки и элементы управления), поэтому ваш пользовательский класс должен быть в одной из них. Вы можете циклически печатать название каждого предмета, пока не найдете то, что ищете. В качестве альтернативы вы можете зациклиться на списке и текстовых полях и запустить свой пользовательский класс поиска таким образом, а не наоборот.

Word Nerd 08.12.2022 19:56

@WordNerd Кажется, что это не работает, когда я запускаю его. Это дает мне ошибку времени выполнения (не удалось найти указанный объект) на: With Me.Controls.Item("oEventHandler" & i) Я также зациклился, хотя все элементы управления в моей пользовательской форме и oEventHandler не подошли.

Liam Russell 08.12.2022 22:04

Если приведенный ниже ответ Karma не работает для вашего проекта, вам может быть полезно создать собственный класс «коллекции» для ваших пользовательских объектов класса clsSearchableDropdown. Затем вы сможете повторять их как членов этой коллекции, как вы это делаете сейчас с пользовательскими элементами управления формы. См. этот ответ , а также эту документацию от MS по VB, которая должна быть справедливой и для VBA.

Word Nerd 09.12.2022 18:52

@WordNerd Спасибо! Вы направили меня в правильном направлении. Я разместил код, который работал для меня.

Liam Russell 12.12.2022 20:35
Преобразование HTML-таблицы в профессиональный документ Excel
Преобразование HTML-таблицы в профессиональный документ Excel
Это самый простой способ создания Excel из HTML-таблицы.
Импорт excel в laravel в базу данных
Импорт excel в laravel в базу данных
Здравствуйте, дорогой читатель, в этой статье я расскажу практическим и быстрым способом, как импортировать файл Excel в вашу базу данных с помощью...
0
4
80
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если я правильно вас понял, в пользовательской форме у вас есть 30 текстовых полей и 30 списков, где каждое текстовое поле (N) предназначено для поиска значения в списке (N), расположенном под этим текстовым полем (N). Так это выглядит примерно так :

Слева находится TextBox01, под TextBox01 находится ListBox01
Справа находится TextBox02, под TextBox02 находится ListBox02.

Если анимация соответствует вашим ожиданиям....

Подготовка :

  • Создайте именованный диапазон (столько, сколько необходимо) с чем-то вроде List01, List02, List03 и т. д. для значения, заполняющего каждый ListBox.
  • Назовите каждый ListBox, например, ListBox01, ListBox02 и т. д.
  • Присвойте каждому TextBox имя, например TextBox01, TextBox02 и т. д.

В модуле пользовательской формы:

Dim MyTextBoxes As Collection

Private Sub UserForm_Initialize()

'populate the ListBoxes with value in a named range
Dim LBname As String: Dim RGname As String: Dim i As Integer
For i = 1 To 2
LBname = "ListBox" & Format(i, "00")
RGname = "List" & Format(i, "00")
Controls(LBname).List = Application.Transpose(Range(RGname))
Next i

'add each TextBox to class
Set MyTextBoxes = New Collection
    For Each ctl In Me.Controls
        Set TextBoxClass = New Class1
        If TypeName(ctl) = "TextBox" And InStr(ctl.Name, "TextBox") Then Set TextBoxClass.obj = ctl
        MyTextBoxes.Add TextBoxClass
    Next
    
End Sub

В модуле класса с именем Class1:

Private WithEvents tb As MSForms.TextBox

Property Set obj(t As MSForms.TextBox)
Set tb = t
End Property

Private Sub tb_Change()
Dim idx As String: Dim LBname As String: Dim arr
idx = Right(tb.Name, 2)
LBname = "ListBox" & idx
arr = Application.Transpose(Range("List" & idx))
    With Userform1.Controls(LBname)
        If tb.text = "" Then
            .Clear
            .List = arr
        Else
            .Clear
            For i = LBound(arr, 1) To UBound(arr, 1)
                If LCase(arr(i)) Like "*" & LCase(tb.value) & "*" Then .AddItem arr(i)
            Next i
        End If
    End With
End Sub

Если в вашей пользовательской форме у вас есть другое текстовое поле, которое не следует использовать для поиска элементов в соответствующем списке, то, возможно, не называйте текстовое поле «TextBox», а что-то другое, например «blablabla».

если ваше существующее текстовое поле и список уже назвали что-то вроде ListBox1, ListBox2, ListBox3 и т. д., TextBox1, TextBox2, TextBox3 и т. д., то назовите именованный диапазон, например List1, List2, List3 и т. д. В модуле класса измените код для idx с помощью метода replace, что-то вроде idx = replace(tb.name,"TextBox",""). Также в модуле Userform для LBname и RGname используйте метод замены.

Поскольку я ограничен в английском языке, мне жаль, что я не могу детализировать код для дальнейшего объяснения.

Спасибо, что нашли время написать комментарий и попытались мне помочь! Я смог понять, чего я хотел.

Liam Russell 12.12.2022 20:38
Ответ принят как подходящий

Вот код, который работал у меня:

' Make a New Collection

  Dim coll As New Collection

' Add all Public Variables to Collection (n = Number 1 to 30)

  coll.Add uQuote.oEventHandler(n) 
     (e.g oEventHandler1, oEventHandler2... oEventHandler30)

  Dim i As Integer

  for i = 1 to 30

    With coll(i)
                            
      ' Attach the textbox and listbox to the class
                                        
          Set .SearchListBox = Me.Controls.Item("ListBox" & i)
          Set .SearchTextBox = Me.Controls.Item("TextBox" & i)
                                        
      ' Default settings
                                    
          .MaxRows = 10
          .ShowAllMatches = True
          .CompareMethod = vbTextCompare
        .WindowsVersion = False
                              
    End With

  Next i

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