Как избежать использования Select в Excel VBA

Я много слышал о понятном отвращении к использованию.Select в Excel VBA, но я не уверен, как его избежать. Я обнаружил, что мой код был бы более пригодным для повторного использования, если бы я мог использовать переменные вместоSelect функции. Тем не менее, я не уверен, как относиться к вещам (например,ActiveCell и т. д.) если не используетеSelect.

Я нашел эта статья о диапазонах а также этот пример о преимуществах неиспользования select но ничего не могу найти нака?

 brettdj21 дек. 2014 г., 06:37
И бывают случаи - редактирование данных диаграммы в ppt с использованием базового файла Excel - когда требуется активация или выбор.
 user214017328 мая 2014 г., 17:24
@ RickTeachey Я думаю, что Сиддхарт избежал этого, так какой у тебя смысл?
 Rick Teachey28 мая 2014 г., 16:00
Важно отметить, что бывают случаи использованияSelect и / илиActiveSheet и т. д. абсолютно неизбежны. Вот пример, который я нашел: / Stackoverflow.com вопросы / 22796286 / ...
 user214017303 июн. 2014 г., 11:09
@ RickTeachey, это только ваше мнение, и дело не в мнениях, а в фактах. У меня не было за последние 10 лет даже однажды была ситуация, когда .Select был неизбежен.
 Rick Teachey28 мая 2014 г., 18:55
То, что он сделал, чтобы избежать этого, было взломом. Умный взлом, полезный взлом, но все же взлом. Суть в том, что объектная модель документа Excel VBA недостаточно полнофункциональна (в отличие от самой Visual Basic), чтобы делать абсолютно все, что вам нужно, без использования Select и Active ____.

Ответы на вопрос(13)

Решение Вопроса

ИспользуйтеDim переменные

Dim rng as Range

Set переменная в требуемом диапазоне. Есть много способов сослаться на диапазон из одной ячейк

Set rng = Range("A1")
Set rng = Cells(1,1)
Set rng = Range("NamedRange")

или диапазон нескольких ячеек

Set rng = Range("A1:B10")
Set rng = Range("A1", "B10")
Set rng = Range(Cells(1,1), Cells(10,2))
Set rng = Range("AnotherNamedRange")
Set rng = Range("A1").Resize(10,2)

Выможе используйте ярлык кEvaluate метод, но это менее эффективно и, как правило, его следует избегать в производственном коде.

Set rng = [A1]
Set rng = [A1:B10]

Все приведенные выше примеры относятся к ячейкам на активный лист. Если вы специально не хотите работать только с активным листом, лучше затемнить Worksheet переменная тоже

Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
Set rng = ws.Cells(1,1)
With ws
    Set rng = .Range(.Cells(1,1), .Cells(2,10))
End With

Если тыделат хочу работать сActiveSheet, для ясности лучше всего быть явным. Но будьте осторожны, как некоторыеWorksheet методы меняют активный лист.

Set rng = ActiveSheet.Range("A1")

Снова, это относится к активная книга. Если вы специально не хотите работать только сActiveWorkbook илиThisWorkbook, лучше приглушитьWorkbook переменная тоже.

Dim wb As Workbook
Set wb = Application.Workbooks("Book1")
Set rng = wb.Worksheets("Sheet1").Range("A1")

Если тыделат хочу работать сActiveWorkbook, для ясности лучше всего быть явным. Но будьте осторожны, как многиеWorkBook методы меняют активную книгу.

Set rng = ActiveWorkbook.Worksheets("Sheet1").Range("A1")

Вы также можете использоватьThisWorkbook объект для ссылки на книгу, содержащую исполняемый код.

Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1")

Обычный (плохой) кусок кода - открыть книгу, получить некоторые данные и снова закрыть

Это плохо

Sub foo()
    Dim v as Variant
    Workbooks("Book1.xlsx").Sheets(1).Range("A1").Clear
    Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
    v = ActiveWorkbook.Sheets(1).Range("A1").Value
    Workbooks("SomeAlreadyOpenBook.xlsx").Activate
    ActiveWorkbook.Sheets("SomeSheet").Range("A1").Value = v
    Workbooks(2).Activate
    ActiveWorkbook.Close()
End Sub

И было бы лучше, как:

SUb foo()
    Dim v as Variant
    Dim wb1 as Workbook
    Dim  wb2 as Workbook
    Set wb1 = Workbooks("SomeAlreadyOpenBook.xlsx")
    Set wb2 = Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
    v = wb2.Sheets("SomeSheet").Range("A1").Value
    wb1.Sheets("SomeOtherSheet").Range("A1").Value = v
    wb2.Close()
End Sub

Проходит диапазоны до вашегоSub иFunction как переменные диапазона

Sub ClearRange(r as Range)
    r.ClearContents
    '....
End Sub

Sub MyMacro()
    Dim rng as Range
    Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:B10")
    ClearRange rng
End Sub

Вы также должны применять методы (например,Find а такжеCopy) переменным

Dim rng1 As Range
Dim rng2 As Range
Set rng1 = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10")
Set rng2 = ThisWorkbook.Worksheets("SomeSheet").Range("B1:B10")
rng1.Copy rng2

Если вы циклически изменяете диапазон ячеек, часто лучше (быстрее) сначала скопировать значения диапазона в массив вариантов и выполнить цикл по этому

Dim dat As Variant
Dim rng As Range
Dim i As Long

Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10000")
dat = rng.Value  ' dat is now array (1 to 10000, 1 to 1)
for i = LBound(dat, 1) to UBound(dat, 1)
    dat(i,1) = dat(i,1) * 10 'or whatever operation you need to perform
next
rng.Value = dat ' put new values back on sheet

Это небольшая дегустация того, что возможно.

 Logan Reed15 июл. 2016 г., 20:20
@ chrisneilsen Крис, я полагаю, что вы также можете использовать префикс рабочего листа перед краткой записью ссылки на ячейку, чтобы уберечь вас от вводаRange так:ActiveSheet.[a1:a4] илиws.[b6].
 Qbik10 янв. 2015 г., 21:31
почему мы должны использовать 'Sub ClearRange (r как Range)' вместо прямого .ClearContents?
 TylerH13 дек. 2018 г., 16:33
@ user3932000 Мне неизвестен сценарий, в котором имена листов меняются автоматически. Что касается имен файлов, он будет делать это только в том случае, если в папке уже есть файл с таким именем. Просто используйте Сохранить ... или жестко закодируйте имя файла, чтобы сохранить его в виде строки. Если вы не можете решить эту проблему, вам следует задать отдельный вопрос, а не комментировать.
 MikeD12 янв. 2015 г., 19:07
добавляя к этому блестящему ответу, чтобы работать с диапазоном тебе не нужно знать его реальный размер до тех пор, пока ты знаешь верхний левый ... напримерrng1(12, 12) будет работать, даже если rng1 был установлен в[A1:A10] только
 ashleedawg07 апр. 2018 г., 13:38
@ AndrewWillems ... или 48 раз в этом посте, но кто считает. But ... но если серьезно, это легко забыть при работе с переменными, содержащими объекты. Avariant переменная не требуетSet до того ка Вы назначаете ему объект. Например,Dim x: x = 1 хорошо, ноDim x: x = Sheets("Sheet1") сгенерирует ошибку 438. Однако просто запутать / уточнитьDim x: x = Range("A1") волян создать ошибку. Зачем? ... потому что он назначен наценност объекта в переменную,н ссылка на сам объект (так как это эквивалентDim x: x = Range("A1").Value)

Select а такжеActivate - это шаг, который делает вас лучше разработчиком VBA. В целом,Select а такжеActivate используются при записи макроса, поэтомуParent рабочий лист или диапазон всегда считается активным.

Вот как можно избежатьSelect а такжеActivate в следующих случаях:

Добавление нового листа и копирование в него ячейки:

From (код, сгенерированный с помощью средства записи макросов):

Sub Makro2()
    Range("B2").Select
    Sheets.Add After:=ActiveSheet
    Sheets("Tabelle1").Select
    Sheets("Tabelle1").Name = "NewName"
    ActiveCell.FormulaR1C1 = "12"
    Range("B2").Select
    Selection.Copy
    Range("B3").Select
    ActiveSheet.Paste
    Application.CutCopyMode = False
End Sub

To:

Sub TestMe()
    Dim ws As Worksheet
    Set ws = Worksheets.Add
    With ws
        .Name = "NewName"
        .Range("B2") = 12
        .Range("B2").Copy Destination:=.Range("B3")
    End With
End Sub
Когда вы хотите скопировать диапазон между листами:

От

Sheets("Source").Select
Columns("A:D").Select
Selection.Copy
Sheets("Target").Select
Columns("A:D").Select
ActiveSheet.Paste

To:

Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").Range("a1")
Используя модные именованные диапазоны

Вы можете получить к ним доступ через[]. Что действительно красиво, по сравнению с другим способом. Проверь себя

Dim Months As Range
Dim MonthlySales As Range

Set Months = Range("Months")    
Set MonthlySales = Range("MonthlySales")

Set Months =[Months]
Set MonthlySales = [MonthlySales]

Пример сверху будет выглядеть так:

Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").[A1]
Не копировать значения, а принимать их

Обычно, если ты хочешьselect, скорее всего, вы что-то копируете. Если вас интересуют только значения, это хороший вариант, чтобы избежать выбора:

Range("B1:B6").Value = Range("A1:A6").Value

Старайтесь всегда ссылаться на Рабочий лист

Это, наверное, самая распространенная ошибка на @ У. Всякий раз, когда вы копируете диапазоны, иногда на рабочий лист не ссылаются, и поэтому VBA рассматривает ActiveWorksheet.

'This will work only if the 2. Worksheet is selected!
Public Sub TestMe()
    Dim rng As Range
    Set rng = Worksheets(2).Range(Cells(1, 1), Cells(2, 2)).Copy
End Sub

'This works always!
Public Sub TestMe2()
    Dim rng As Range
    With Worksheets(2)
        .Range(.Cells(1, 1), .Cells(2, 2)).Copy
    End With
End Sub
Могу ли я никогда не использовать.Select или.Activate для всего

Единственный раз, когда вы можете быть оправданы, чтобы использовать.Activate а также.Select - это когда вы хотите убедиться, что конкретная рабочая таблица выбрана по визуальным причинам. Например, ваш Excel всегда будет открываться с выбранным первым листом обложки, не учитывая, какой лист был активным при закрытии файла. Таким образом, что-то вроде этого абсолютно нормально:

Private Sub Workbook_Open()
    Worksheets("Cover").Activate
End Sub

Чтобы не использовать.Select метод, вы можете установить переменную, равную желаемому свойству.

► Например, если вы хотите значение вCell A1 вы можете установить переменную, равную значению свойства этой ячейки.

ПримерvalOne = Range("A1").Value

► Например, если вы хотите использовать кодовое имя «Sheet3», вы можете установить переменную, равную свойству кодового имени этого листа.

ПримерvalTwo = Sheets("Sheet3").Codename

Надеюсь, это поможет. Дайте знать, если у вас появятся вопросы

который очищает содержимое ячейки «А1» (или больше, если выбран тип xllastcell и т. Д.). Все сделано без необходимости выделять ячейки.

Application.GoTo Reference:=Workbook(WorkbookName).Worksheets(WorksheetName).Range("A1")
Range(Selection,selection(selectiontype)).clearcontents 

Я надеюсь, что это помогает кому-то

что ниже я сравниваю подход Select (тот, который ОП хочет избежать) с подходом Range (и это ответ на вопрос). Так что не прекращайте читать, когда увидите первый выбор.

Это зависит от того, что ты пытаешься сделать. В любом случае, простой пример может быть полезен. Предположим, вы хотите установить значение активной ячейки в «foo». Используя ActiveCell, вы могли бы написать что-то вроде этого:

Sub Macro1()
    ActiveCell.Value = "foo"
End Sub

Если вы хотите использовать его для ячейки, которая не является активной, например, для «B2», вы должны сначала выбрать ее, например, так:

Sub Macro2()
    Range("B2").Select
    Macro1
End Sub

Используя диапазоны, вы можете написать более общий макрос, который можно использовать для установки значения любой ячейки, которую вы хотите, в любое, что вы хотите:

Sub SetValue(cellAddress As String, aVal As Variant)
    Range(cellAddress).Value = aVal
End Sub

Затем вы можете переписать Macro2 как:

Sub Macro2()
    SetCellValue "B2", "foo"
End Sub

И Макро1 как:

Sub Macro1()
    SetValue ActiveCell.Address, "foo"
End Sub

Надеюсь, это поможет немного прояснить ситуацию.

 Francesco Baruchelli23 мая 2012 г., 08:50
Я не уверен, что понимаю, что вы имеете в виду, но вы можете создать Range с помощью одной инструкции (например, Range ("B5: C14")), и вы даже можете установить его значение сразу (если оно должно быть одинаковым) для каждой ячейки в диапазоне), например, Диапазон («B5: C14»). Значение = «abc»
 BiGXERO23 мая 2012 г., 08:33
Спасибо за отличный ответ так быстро. Значит ли это, что если я обычно добавляю ячейки к диапазону, называю диапазон и перебираю его, я должен сразу перейти к созданию массива?

.select исходит от людей, которые, как и я, начали изучать VBA по необходимости, записывая макросы и затем изменяя код, не осознавая этого.select и последующиеselection просто ненужный посредник.

.select можно избежать, как многие уже опубликовали, напрямую работая с уже существующими объектами, что позволяет использовать различные косвенные ссылки, такие как сложные вычисления i и j, а затем редактировать ячейку (i, j) и т. д.

В противном случае, нет ничего неявно неправильного в.select сам, и вы можете легко найти применение для этого, например, У меня есть электронная таблица, которую я заполняю датой, активирую макрос, который делает с ним что-то волшебное и экспортирует его в приемлемом формате на отдельный лист, что, однако, требует некоторых окончательных ручных (непредсказуемых) вводов в соседнюю ячейку. Вот и наступил момент для.select это избавит меня от лишних движений мыши и щелчка.

 vacip22 нояб. 2016 г., 14:25
Пока вы правы, по крайней мере одна вещь явно не так с выбором: это медленно. Очень медленный по сравнению со всем, что происходит в макросе.

Например

Thisworkbook.Worksheets("fred").cells(1,1)
Workbooks("bob").Worksheets("fred").cells(1,1)

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

Никогда не используйте индекс рабочей книги.

Workbooks(1).Worksheets("fred").cells(1,1)

Вы не знаете, какие другие рабочие книги будут открыты, когда пользователь выполнит ваш код.

 Rick Teachey23 нояб. 2014 г., 15:33
Знаешь, имена рабочих листов тоже могут меняться. Вместо этого используйте кодовые имена.

данным выше:

Вероятно, самое большое, что вы можете сделать, чтобы избежать использования Select, это насколько это возможно, используйте именованные диапазоны (в сочетании со значимыми именами переменных) в своем коде VBA. Этот момент был упомянут выше, но немного затенен; однако, это заслуживает особого внимания.

Вот пара дополнительных причин для либерального использования именованных диапазонов, хотя я уверен, что мог бы придумать еще.

Наименованные диапазоны облегчают чтение и понимание кода.

Пример

Dim Months As Range
Dim MonthlySales As Range

Set Months = Range("Months")
'e.g, "Months" might be a named range referring to A1:A12

Set MonthlySales = Range("MonthlySales")
'e.g, "Monthly Sales" might be a named range referring to B1:B12

Dim Month As Range
For Each Month in Months
    Debug.Print MonthlySales(Month.Row)
Next Month

Совершенно очевидно, что названные диапазоныMonths а такжеMonthlySales содержат, и что делает процедура.

Почему это важно? Частично потому, что другим людям легче понять это, но даже если вы единственный человек, который когда-либо увидит или использует ваш код, вы все равно должны использовать именованные диапазоны и хорошие имена переменных, потому что ВЫ ЗАБУДЕТЕ что ты хотел с этим сделать год спустя, и ты потратишь впустую 30 минут, чтобы понять, что делает твой код.

Named диапазоны гарантируют, что ваши макросы не сломаются, когда (не если!) Изменяется конфигурация электронной таблицы.

Рассмотрим, если приведенный выше пример был написан так:

Dim rng1 As Range
Dim rng2 As Range

Set rng1 = Range("A1:A12")
Set rng2 = Range("B1:B12")

Dim rng3 As Range
For Each rng3 in rng1 
    Debug.Print rng2(rng3.Row)
Next rng3

Сначала этот код будет отлично работать - пока вы или будущий пользователь не примете решение: «Ну и дела, думаю, я собираюсь добавить новый столбец с годом в столбце @A! ", или поместите столбец расходов между месяцами и столбцами продаж, или добавьте заголовок к каждому столбцу. Теперь ваш код поврежден. И поскольку вы использовали ужасные имена переменных, вам понадобится гораздо больше времени, чтобы выяснить как это исправить, чем нужно.

Если для начала вы использовали именованные диапазоны, тоMonths а такжеSalesтолбцы @ можно перемещать по своему усмотрению, и ваш код будет продолжать работать нормально.

 brettdj27 февр. 2015 г., 09:15
Дебаты о том, являются ли именованные диапазоны хорошим или плохим дизайном электронных таблиц, продолжаются - я твердо в лагере. По моему опыту, они увеличивают количество ошибок (для обычных пользователей, которым не нужен код).
 Marcus Mangelsdorf03 нояб. 2017 г., 11:35
@ brettdj: Ваша цитата верна, но вы забыли упомянуть, что за ней следуетшест "За исключением ..." фразы. Одним из них является: " За исключением замены ссылок на ячейки в макросах Всегда используйте имена Excel вместо ссылок на ячейки при создании макросов. Это сделано для того, чтобы избежать ошибок, возникающих при вставке дополнительных строк или столбцов, в результате чего макрокодирование больше не указывает на предполагаемые исходные данные. "
 DeanOC25 мар. 2015 г., 02:18
Я согласен с вашей философией развития; Однако, я думаю, что это чепуха. В нем рассказывается о том, как имена диапазонов могут сбить с толку новичков, отлаживающих электронные таблицы, но любой, кто использует новичков для просмотра сложных электронных таблиц, получает то, что заслуживает! Раньше я работал в фирме, которая проверяла финансовые таблицы, и я могу вам сказать, что это не та работа, которую вы даете новичку.
 Excel Hero21 авг. 2015 г., 02:28
Там нет значимой дискуссии. Любой, кто выступает против определенных имен, не нашел время, чтобы полностью понять их последствия. Именованные формулы могут быть единственной наиболее глубокой и полезной конструкцией во всем Excel.

.Offset Property. Это также может быть использовано, чтобы избежать использованияSelectействие @ при манипулировании определенными ячейками, особенно в отношении выбранной ячейки (как упоминается в OP сActiveCell).

Вот пара примеров.

Я также предполагаю, что "ActiveCell" - это J4.

ActiveCell.Offset(2, 0).Value = 12

Это изменит ячейкуJ6 быть значением 12 А минус -2 будет ссылаться на J2

ActiveCell.Offset(0,1).Copy ActiveCell.Offset(,2)

Это скопирует ячейку вk4 вL4. Отметим, что «0» не требуется в параметре смещения, если не требуется (, 2) Как и в предыдущем примере, минус 1 будетi4

ActiveCell.Offset(, -1).EntireColumn.ClearContents

Это очистит значения во всех ячейках столбца k.

Нельзя сказать, что они «лучше», чем описанные выше варианты, а просто перечисляют альтернативы.

Две главные причины, почему.Select/.Activate/Selection/Activecell/Activesheet/Activeworkbook и т.д ... следует избегать

олнения.

Как нам этого избежать?

1) Непосредственно работать с соответствующими объектами

Рассмотри этот код

Sheets("Sheet1").Activate
Range("A1").Select
Selection.Value = "Blah"
Selection.NumberFormat = "@"

Этот код также можно записать как

With Sheets("Sheet1").Range("A1")
    .Value = "Blah"
    .NumberFormat = "@"
End With

2) При необходимости объявите свои переменные. Тот же код выше можно записать как

Dim ws as worksheet

Set ws = Sheets("Sheet1")

With ws.Range("A1")
    .Value = "Blah"
    .NumberFormat = "@"
End With
 phrebh09 янв. 2018 г., 14:30
@ Ник Вам не нужно активировать листы, чтобы вставлять их или фильтровать. Используйте объект листа в ваших командах вставки или фильтрации. Это становится легче, когда вы изучаете объектную модель Excel на практике. Я полагаю, что единственный раз, когда я использую .Activate, это когда я создаю новый лист, но я хочу, чтобы исходный лист появлялся, когда код готов.
 robotik20 июн. 2017 г., 14:52
Я думаю, что смысл не в том, чтобы полностью избегать их использования, а в максимально возможной степени. если вы хотите сохранить рабочую книгу, чтобы, когда кто-то открыл ее, была выбрана определенная ячейка на определенном листе, то вы должны выбрать этот лист и ячейку. Копирование / вставка - плохой пример, по крайней мере, в случае значений, это может быть сделано быстрее с помощью кода, такого какSheets(2).[C10:D12].Value = Sheets(1).[A1:B3].Value
 Nick25 нояб. 2016 г., 15:34
Я считаю, что иногда вам может понадобиться сначала активировать лист, если вам нужно вставить или отфильтровать данные на нем. Я бы сказал, что лучше избегать активации, насколько это возможно, но есть случаи, когда вам нужно это сделать. Так что продолжайте активировать и выбирать до абсолютного минимума согласно ответу выше.
 GMalc28 февр. 2019 г., 19:44
@ phrebh Вам не нужно использовать.Activate, чтобы перейти к исходному листу, просто используйтеApplication.Goto
 user303268902 февр. 2016 г., 11:04
Это хороший ответ, но мне не хватает этой темы, когда нам действительно нужно активировать. Все говорят, что это плохо, но никто не объясняет случаи, когда есть смысл его использовать. Например, я работал с двумя рабочими книгами и не мог запустить макрос на одной из рабочих книг, не активировав ее сначала. Не могли бы вы уточнить немного, может быть? Кроме того, если, например, я не активирую листы при копировании диапазона с одного листа на другой, при выполнении программы он, по-видимому, активирует соответствующие листы в любом случае, неявно.

потому что все остальные дали длинный.

Вы будете получать .select и .activate всякий раз, когда будете записывать макросы и использовать их повторно. Когда вы выбираете ячейку или лист, она просто становится активной. С этого момента всякий раз, когда вы используете неквалифицированные ссылки, такие какRange.Value они просто используют активную ячейку и лист. Это также может быть проблематично, если вы не смотрите, где находится ваш код, или пользователь нажимает на книгу.

Итак, вы можете устранить эти проблемы, напрямую ссылаясь на свои ячейки. Который идет:

'create and set a range
Dim Rng As Excel.Range
Set Rng = Workbooks("Book1").Worksheets("Sheet1").Range("A1")
'OR
Set Rng = Workbooks(1).Worksheets(1).Cells(1, 1)

Или ты мог бы

'Just deal with the cell directly rather than creating a range
'I want to put the string "Hello" in Range A1 of sheet 1
Workbooks("Book1").Worksheets("Sheet1").Range("A1").value = "Hello"
'OR
Workbooks(1).Worksheets(1).Cells(1, 1).value = "Hello"

Существуют различные комбинации этих методов, но это была бы общая идея, выраженная как можно скорее для нетерпеливых людей, таких как я.

что мой код стал бы более пригодным для повторного использования, если бы я мог использовать переменные вместо функций выбора."

Пока я не могу думать о чем-то большем, чем об отдельных ситуациях, когда.Select был бы лучшим выбором, чем прямая ссылка на ячейку, я бы встал на защитуSelection и отметьте, что его не следует выбрасывать по тем же причинам, что и.Select необходимо избегать

Иногда бывают случаи, когда короткие подпрограммы макроса, позволяющие экономить время и назначаемые сочетаниям горячих клавиш, доступные с помощью нажатия нескольких клавиш, экономят много времени. Возможность выбора группы ячеек для введения в действие операционного кода творит чудеса, когда имеешь дело с карманными данными, которые не соответствуют формату данных всей таблицы. Во многом так же, как вы можете выбрать группу ячеек и применить изменение формата, выбор группы ячеек для запуска специального макрокодов может значительно сэкономить время.

Примеры подструктуры на основе выбора:

Public Sub Run_on_Selected()
    Dim rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each rng In rSEL
        Debug.Print rng.Address(0, 0)
        'cell-by-cell operational code here
    Next rng
    Set rSEL = Nothing
End Sub

Public Sub Run_on_Selected_Visible()
    'this is better for selected ranges on filtered data or containing hidden rows/columns
    Dim rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each rng In rSEL.SpecialCells(xlCellTypeVisible)
        Debug.Print rng.Address(0, 0)
        'cell-by-cell operational code here
    Next rng
    Set rSEL = Nothing
End Sub

Public Sub Run_on_Discontiguous_Area()
    'this is better for selected ranges of discontiguous areas
    Dim ara As Range, rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each ara In rSEL.Areas
        Debug.Print ara.Address(0, 0)
        'cell group operational code here
        For Each rng In ara.Areas
            Debug.Print rng.Address(0, 0)
            'cell-by-cell operational code here
        Next rng
    Next ara
    Set rSEL = Nothing
End Sub

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

Короче, не отказывайсяSelection из-за его тесной связи с.Select а такжеActiveCell. В качестве свойства листа оно имеет много других целей.

(Да, я знаю, что этот вопрос был о.Select, неSelection но я хотел убрать любые заблуждения, которые могут сделать начинающие VBA-кодеры.)

 L4220 мая 2015 г., 00:19
Selection может быть любым на рабочем листе, поэтому может сначала проверить тип объекта, прежде чем присвоить его переменной, поскольку вы явно объявили его какRange.

поэтому взяли на себя инициативу @Vityata и @Jeeped ради рисования линии на песке:

Почему бы не позвонить.Activate, .Select, Selection, ActiveSomething методы / свойства

В основном потому, что они вызваны главным образом для обработки пользовательского ввода через пользовательский интерфейс приложения. Так как они являются методами, вызываемыми, когда пользователь обрабатывает объекты через пользовательский интерфейс, они записываются макрос-рекордером, и поэтому их вызов является либо хрупким, либо избыточным для большинства ситуаций: вам не нужно выбирать объект, чтобы выполнить действие сSelection сразу после этого.

Однако это определение разрешает ситуации, к которым они обращаются:

Когда звонить.Activate, .Select, .Selection, .ActiveSomething методы / свойства

В основном, когда вы ожидаете конечный пользователь играть роль в исполнении.

Если вы разрабатываете и ожидаете, что пользователь выберет экземпляры объектов для вашего кода, а затем.Selection или.ActiveObject уместны.

С другой стороны,.Select а также.Activate полезны, когда вы можете вывести следующее действие пользователя и хотите, чтобы ваш код направлял пользователя, возможно, сэкономив ему время и щелчки мышью. Например, если ваш код только что создал новый экземпляр диаграммы или обновил его, пользователь может захотеть проверить его, и вы можете позвонить.Activate на нем или на его листе, чтобы сэкономить пользователю время на его поиск; или если вы знаете, что пользователю потребуется обновить некоторые значения диапазона, вы можете программно выбрать этот диапазон.

Ваш ответ на вопрос