Ускорьте его с помощью массива полей данных
Насколько я понял, ваша главная задача - добиться повышения скорости с помощью каскадных комбинированных списков в пользовательской форме и читаемого кода, избегая многочисленных .Offset
.
[i.] Циклический просмотр диапазона всегда занимает много времени, быстрее позволяет назначить полный набор данных для варианта массива поля данных (myData
) .
[ii.] Вызов одиночной вспомогательной процедуры fillComboNo
делает _Change
процедуры событий более читабельными .
[iii.]Дополнительная вспомогательная процедура SortColl
сортирует каждой коллекции, чтобы сделать выбор удобной для пользователя .
[iv.] Кроме того, этот пример кода позволяет добавить еще больше комбинированных списков , используя ту же вспомогательную процедуру fillComboNo
в дополнительных Combobox{No}_Change
процедурах события.- Конечно, в этом случае необходимо будет расширить диапазон, назначенный массиву полей данных myData
, тоже (т.е. с 3 столбцов A:C
до, например, A:D
) .
Пример кода
В основном это решение близко к вашему подходу, так как оно также использует коллекции.Он быстрее , так как использует массив полей данных, как описано выше; он не претендует на то, чтобы предлагать наиболее эффективный способ отображения каскадных комбинированных списков.
В этом примере предполагается, что перечисляются все необходимые комбинированные списки ComboBox1
, ComboBox2
, ComboBox3
, ...
Option Explicit ' declaration head of the UserForm code module
Dim myData ' Variant 2-dim datafield array ( 1-based !)
Private Sub UserForm_Initialize()
Dim LR As Long, ws As Worksheet
Set ws = Sheet1 ' if using CodeName in thisWorkbook
' ~~~~~~~~~~~~~~~~~~~~~~~~~
' [0] get entire DATA FIELD ' e.g. columns A:C (omitting title row)
' ~~~~~~~~~~~~~~~~~~~~~~~~~
LR = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row ' get last row
myData = ws.Range("A2:C" & LR).Value2 ' << assign range values to datafield array
' [1] fill first ComboBox
FillComboNo 1 ' <~~ helper procedure FillComboNo
End Sub
Private Sub ComboBox1_Change()
FillComboNo 2 ' <~~ helper procedure FillComboNo
End Sub
Private Sub ComboBox2_Change()
FillComboNo 3 ' <~~ helper procedure FillComboNo
End Sub
Вспомогательная процедура FillComboNo
Sub FillComboNo(ByVal no As Long)
' Purpose: fill cascading comboboxes
' Note: assumes controls named as "ComboBox" & No (ComboBox1, ComboBox2, ...)
Dim myList As New Collection
Dim item As Variant
Dim i As Long, ii As Long
Dim OK As Boolean, OKTemp As Boolean
' [0] clear ComboBox{No}
Me.Controls("ComboBox" & no).Clear
' [1] assign values in column No based on prior hierarchy levels
For i = LBound(myData) To UBound(myData)
' [1a] check upper hierarchy
OK = True
For ii = 1 To no - 1
OKTemp = myData(i, ii) = Me.Controls("ComboBox" & ii): OK = OK And OKTemp
Next ii
' [1b] add to collection
If OK Then
On Error Resume Next
myList.Add myData(i, no), myData(i, no)
If Err.Number <> 0 Then Err.Clear
End If
Next i
' [1c] sort collection via helper procedure
SortColl myList ' <~~ helper procedure SortColl
' [2] fill ComboBox{No}
For Each item In myList
Me.Controls("ComboBox" & no).AddItem item
Next item
End Sub
Процедура сортировки SortColl
Sub SortColl(ByRef c As Collection)
' Purpose: sort collection by keys via bubble sort method
Dim i As Long, j As Long
Dim vTemp As Variant
For i = 1 To c.Count - 1
For j = i + 1 To c.Count
If c(i) > c(j) Then
' remember the lesser item
vTemp = c(j)
' remove the lesser item
c.Remove j
' add the lesser item before the greater one
c.Add vTemp, vTemp, i
End If
Next j
Next i
End Sub