Порядок, в котором For Each
выполняет итерацию коллекции объектов, зависит от реализации (я обвиняю Excel, а не VBA), и, хотя он, вероятно, является детерминированным и предсказуемым, в его спецификации нет ничего, что гарантировало бы конкретный порядок итераций. Поэтому код VBA, написанный для итерации коллекции объектов, не должен быть написан с предположением о конкретном порядке итерации, поскольку это может очень хорошо меняться в зависимости от версии используемой библиотеки типов (в данном случае Excel).
Очень неясно, какова форма вашего Range
/ Selection
, но если вам нужно перебрать выбранные ячейки в определенном порядке, то цикл For Each
не следует использовать, по крайней мере, не для перебора. клетки как таковые.
Так как диапазоны не являются смежными, Range
будет иметь кратное Areas
; вам нужно будет итерировать Selection.Areas
и для каждой выбранной области, итерировать ячейки в определенном порядке. For Each
, безусловно, является наиболее эффективным способом итерации коллекции объектов , которой является Range.Areas
.
Debug.Assert TypeOf Selection Is Excel.Range
Dim currentArea As Range
For Each currentArea In Selection.Areas
'todo
Next
Вместо того, чтобы вкладывать циклы , создайте отдельную процедуру, которая принимает currentArea
в качестве параметра - в этой процедуре вы будете повторять отдельные ячейки:
Private Sub ProcessContiguousArea(ByVal area As Range)
Dim currentRow As Long
For currentRow = 1 To area.Rows.Count
Debug.Print area.Cells(currentRow, 1).Address
Next
End Sub
Теперь внешний цикл выглядит так:
Debug.Assert TypeOf Selection Is Excel.Range
Dim currentArea As Range
For Each currentArea In Selection.Areas
ProcessContiguousArea currentArea
Next
Процедура ProcessContiguousArea
может делать все, что нужно с заданной смежной областью, используя цикл For
для итерации диапазона по строкам, не заботясь о фактическом адресе выбранной области: используя Range.Cells(RowIndex, ColumnIndex)
, строка 1 / столбец 1 представляет верхнюю левую ячейку этого диапазона, независимо от того, где этот диапазон расположен на листе.
Невыбранные ячейки могут быть доступны с помощью Range.Offset
:
Debug.Print area.Cells(currentRow, 1).Offset(ColumnOffset:=10).Address
Строка верхней левой ячейки area
на рабочем листе возвращается area.Row
, а столбец верхней левой ячейки area
на рабочем листе получается с area.Column
.