Vba excel разница между select и activate

Обновлено: 30.06.2024

In Microsoft Excel, you usually select a cell or cells and then perform an action, such as formatting the cells or entering values in them. In Visual Basic, it is usually not necessary to select cells before modifying them.

For example, to enter a formula in cell D6 using Visual Basic, you do not need to select the range D6. Just return the Range object for that cell, and then set the Formula property to the formula you want, as shown in the following example.

For more information and examples of using other methods to control cells without selecting them, see How to: Reference Cells and Ranges.

Using the Select Method and the Selection Property

The Select method activates sheets and objects on sheets; the Selection property returns an object that represents the current selection on the active sheet in the active workbook. Before you can use the Selection property successfully, you must activate a workbook, activate or select a sheet, and then select a range (or other object) using the Select method.

The macro recorder will often create a macro that uses the Select method and the Selection property. The following Sub procedure was created using the macro recorder, and it shows how Select and Selection work together.

The following example performs the same task without activating or selecting the worksheet or cells.

Selecting Cells on the Active Worksheet

If you use the Select method to select cells, be aware that Select works only on the active worksheet. If you run your Sub procedure from the module, the Select method will fail unless your procedure activates the worksheet before using the Select method on a range of cells. For example, the following procedure copies a row from Sheet1 to Sheet2 in the active workbook.

Activating a Cell Within a Selection

You can use the Activate method to activate a cell within a selection. There can be only one active cell, even when a range of cells is selected. The following procedure selects a range and then activates a cell within the range without changing the selection.

Support and feedback

Have questions or feedback about Office VBA or this documentation? Please see Office VBA support and feedback for guidance about the ways you can receive support and provide feedback.

В Microsoft Excel обычно выбирается ячейка или ячейки, а затем выполняется действие, например форматирование ячеек или ввод значений. В Visual Basic обычно не требуется выбирать ячейки перед их изменением.

Например, чтобы ввести формулу в ячейку D6 с помощью Visual Basic, не нужно выбирать диапазон D6. Просто возвратите объект Range для этой ячейки, а затем присвойте свойству Formula нужную формулу, как показано в следующем примере.

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

Использование метода Select и свойства Selection

Метод Select активирует листы и объекты на листах; свойство Selection возвращает объект, представляющий текущее выделение на активном листе в активной книге. Перед использованием свойства Selection необходимо активировать книгу, активировать или выбрать лист, а затем выбрать диапазон (или другой объект) с помощью метода Select.

Средство записи макросов часто создает макрос, использующий метод Select и свойство Selection. Следующая процедура Sub была создана с помощью средства записи макросов и показывает, как Select и Selection работают вместе.

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

Выбор ячеек на активном листе

Если для выбора ячеек используется метод Select, имейте в виду, что Select работает только на активном листе. Если выполнить процедуру Sub из модуля, метод Select завершится ошибкой, если процедура не активирует лист перед использованием метода Select для диапазона ячеек. Например, следующая процедура копирует строку из Листа1 в Лист2 в активной книге.

Активация ячейки в выделенном фрагменте

Метод Activate можно использовать для активации ячейки в выделенном фрагменте. Активной может быть только одна ячейка, даже если выделен диапазон ячеек. Следующая процедура выделяет диапазон и активирует ячейку в диапазоне, не изменяя выделенный фрагмент.

Поддержка и обратная связь

Есть вопросы или отзывы, касающиеся Office VBA или этой статьи? Руководство по другим способам получения поддержки и отправки отзывов см. в статье Поддержка Office VBA и обратная связь.

Полагаю не совру когда скажу, что все кто программирует в VBA очень часто в своих кодах общаются к ячейкам листов. Ведь это чуть ли не основное предназначение VBA в Excel. В принципе ничего сложного в этом нет. Например, чтобы записать в ячейку A1 слово Привет необходимо выполнить код:

Тоже самое можно сделать сразу для нескольких ячеек:

Если необходимо обратиться к именованному диапазону:

Диапазон1 - это имя диапазона/ячейки, к которому надо обратиться в коде. Указывается в кавычках, как и адреса ячеек.
Но в VBA есть и альтернативный метод записи значений в ячейке - через объект Cells:

Cells(1, 1).Value = "Привет"

Синтаксис объекта Range:
Range(Cell1, Cell2)

  • Cell1 - первая ячейка диапазона. Может быть ссылкой на ячейку или диапазон ячеек, текстовым представлением адреса или имени диапазона/ячейки. Допускается указание несвязанных диапазонов(A1,B10), пересечений(A1 B10).
  • Cell2 - последняя ячейка диапазона. Необязательна к указанию. Допускается указание ссылки на ячейку, столбец или строку.

Синтаксис объекта Cells:
Cells(Rowindex, Columnindex)

Исходя из этого несложно предположить, что к диапазону можно обратиться, используя Cells и Range:

'выделяем диапазон "A1:B10" на активном листе Range(Cells(1,1), Cells(10,2)).Select

и для чего? Ведь можно гораздо короче:

Иногда обращение посредством Cells куда удобнее. Например для цикла по столбцам(да еще и с шагом 3) совершенно неудобно было бы использовать буквенное обозначение столбцов.
Объект Cells так же можно использовать для указания ячеек внутри непосредственно указанного диапазона. Например, Вам необходимо выделить ячейку в 3 строке и 2 столбце диапазона "D5:F56" . Можно пройтись по листу и посмотреть, отсчитать нужное количество строк и столбцов и понять, что это будет "E7" . А можно сделать проще:

Согласитесь, это гораздо удобнее, чем отсчитывать каждый раз. Особенно, если придется оперировать смещением не на 2-3 ячейки, а на 20 и более. Конечно, можно было бы применить Offset. Но данное свойство именно смещает диапазон на указанное количество строк и столбцов и придется уменьшать на 1 смещение каждого параметра для получения нужной ячейки. Да и смещает на указанное количество строк и столбцов весь диапазон, а не одну ячейку. Это, конечно, тоже не проблема - можно вдобавок к этому использовать метод Resize - но запись получится несколько длиннее и менее наглядной:

Range("D5:F56").Offset(2, 1).Resize(1, 1).Select

И неплохо бы теперь понять, как значение диапазона присвоить переменной. Для начала переменная должна быть объявлена с типом Range. А т.к. Range относится к глобальному типу Object, то присвоение значения такой переменной должно быть обязательно с применением оператора Set:

Dim rR as Range Set rR = Range("D5")

если оператор Set не применять, то в лучшем случае получите ошибку, а в худшем(он возможен, если переменной rR не назначать тип) переменной будет назначено значение Null или значение ячейки по умолчанию. Почему это хуже? Потому что в таком случае код продолжит выполняться, но логика кода будет неверной, т.к. эта самая переменная будет содержать значение неверного типа и применение её в коде в дальнейшем все равно приведет к ошибке. Только ошибку эту отловить будет уже сложнее.
Использовать же такую переменную в дальнейшем можно так же, как и прямое обращение к диапазону:

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

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

'так выглядит запись слова Test в ячейку А1 Range("A1").Select Selection.Value = "Test"

Но как правило выделение - действие лишнее. Можно записать значение и без него:

'запишем слово Test в ячейку A1 на активном листе Range("A1").Value = "Test"

Теперь чуть подробнее разберем, как обратиться к диапазону не выделяя его и при этом сделать все правильно. Диапазон и ячейка - это объекты листа. У каждого объекта есть родитель - грубо говоря это другой объект, который является управляющим для дочернего объекта. Для ячейки родительский объект - Лист, для Листа - Книга, для Книги - Приложение Excel. Если смотреть на иерархию зависимости объектов, то от старшего к младшему получится так:
Applicaton => Workbooks => Sheets => Range
По умолчанию для всех диапазонов и ячеек родительским объектом является текущий(активный) лист. Т.е. если для диапазона(ячейки) не указать явно лист, к которому он относится, в качестве родительского листа для него будет использован текущий - ActiveSheet:

'запишем слово Test в ячейку A1 на активном листе Range("A1").Value = "Test"

Т.е. если в данный момент активен Лист1 - то слово Test будет записано в ячейку А1 Лист1. Если активен Лист3 - в А1 Лист3. Иначе говоря такая запись равносильна записи:

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

'активируем Лист2 Worksheets("Лист2").Select 'записываем слово Test в ячейку A1 Range("A1").Value = "Test"

Чтобы не активируя другой лист записать в него данные, необходимо явно указать принадлежность объекта Range именно этому листу:

'запишем слово Test в ячейку A1 на Лист2 независимо от того, какой лист активен Worksheets("Лист2").Range("A1").Value = "Test"

Таким же образом происходит считывание данных с ячеек - если не указывать лист, данные ячеек которого необходимо считать - считаны будут данные с ячейки активного листа. Чтобы считать данные с Лист2 независимо от того, какой лист активен применяется такой код:

'считываем значение ячейки A1 с Лист2 независимо от того, какой лист активен MsgBox Worksheets("Лист2").Range("A1").Value

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

'запишем слово Test в ячейку A1 на Лист2 книги Книга2.xlsx независимо от того, какая книга и какой лист активен Workbooks("Книга2.xlsx").Worksheets("Лист2").Range("A1").Value = "Test" 'считываем значение ячейки A1 с Лист2 книги Книга3.xlsx независимо от того, какой лист активен MsgBox Workbooks("Книга3.xlsx").Worksheets("Лист2").Range("A1").Value

Очень часто ошибки обращения к ячейкам листов и книг делают начинающие, особенно в циклах по листам. Вот пример неправильного цикла:

Dim wsSh As Worksheet For Each wsSh In ActiveWorkbook.Worksheets Range("A1").Value = wsSh.Name 'записываем в ячейку А1 имя листа MsgBox Range("A1").Value 'проверяем, то ли имя записалось Next wsSh

MsgBox будет выдавать правильные значения, но сами имена листов будут записываться не на каждый лист, а последовательно в ячейку активного листа. Поэтому на активном листе в ячейке А1 будет имя последнего листа.
А вот так выглядит правильный цикл:
Вариант 1 - активация листа (медленный)

Dim wsSh As Worksheet For Each wsSh In ActiveWorkbook.Worksheets wsSh.Activate 'активируем каждый лист Range("A1").Value = wsSh.Name 'записываем в ячейку А1 имя листа MsgBox Range("A1").Value 'проверяем, то ли имя записалось Next wsSh

Вариант 2 - без активации листа (быстрый и более правильный)

Dim wsSh As Worksheet For Each wsSh In ActiveWorkbook.Worksheets wsSh.Range("A1").Value = wsSh.Name 'записываем в ячейку А1 имя листа MsgBox wsSh.Range("A1").Value 'проверяем, то ли имя записалось Next wsSh

Важно: если код записан в модуле листа(правая кнопка мыши на листе-Исходный текст) и для объекта Range или Cells родитель явно не указан(т.е. нет имени листа и книги) - тогда в качестве родителя будет использован именно тот лист, в котором записан код, независимо от того какой лист активный. Иными словами - если в модуле листа записать обращение вроде Range("A1").Value = "привет" , то слово привет всегда будет записывать в ячейку A1 именно того листа, в котором записан сам код. Это следует учитывать, когда располагаете свои коды внутри модулей листов.

В конструкциях типа Range(Cells(,),Cells(,)) Range является контейнером, в котором указываются ссылки на объекты, из которых и будет создана ссылка на непосредственно конечный объект.
Предположим, что активен "Лист1" , а код запущен с листа "Итог" .
Если запись будет вида

Sheets("Итог").Range(Cells(1, 1), Cells(10, 1))

это вызовет ошибку "Run-time error '1004': Application-defined or object-defined error". А ошибка появляется потому, что контейнер и объекты внутри него не могут располагаться на разных листах, равно как и:

Sheets("Итог").Range(Cells(1, 1), Sheets("Итог").Cells(10, 1)) 'запись ниже так же неверна Range(Cells(1, 1), Sheets("Итог").Cells(10, 1))

т.к. ссылки на объекты внутри контейнера относятся к разным листам. Cells(1, 1) - к активному листу, а Sheets( "Итог" ).Cells(10, 1) - к листу Итог.
А вот такие записи будут правильными:

Sheets("Итог").Range(Sheets("Итог").Cells(1, 1), Sheets("Итог").Cells(10, 1)) Range(Sheets("Итог").Cells(1, 1), Sheets("Итог").Cells(10, 1))

Вторая запись не содержит ссылки на родителя для Range, но ошибки это в большинстве случаев не вызовет - т.к. если для контейнера ссылка не указана, а для двух объектов внутри контейнера родитель один - он будет применен и для самого контейнера. Однако лучше делать как в первой строке - т.е. с обязательным указанием родителя для контейнера и для его составляющих. Т.к. при определенных обстоятельствах(например, если в момент обращения к диапазону активной является книга, открытая в режиме защищенного просмотра) обращение к Range без родителя может вызывать ошибку выполнения.
Если запись будет вида Range( "A1" , "A10" ), то указывать ссылку на родителя внутри Range не обязательно - достаточно будет указать эту ссылку перед самим Range - Sheets( "Итог" ).Range( "A1" , "A10" ), т.к. текстовое представление адреса внутри Range не является объектом(у которого может быть какой-то родительский объект), что обязывает создать ссылку именно на родителя контейнера.

Разберем пример, приближенный к жизненной ситуации. Необходимо на лист Итог занести формулу вычитания, начиная с ячейки А2 и до последней заполненной. На момент записи активен Лист1. Очень часто начинающие записывают так:

Sheets("Итог").Range("A2:A" & Cells(Rows.Count, 1).End(xlUp).Row) _ .FormulaR1C1 = "=RC2-RC11"

Запись смешанная - и текстовое представление адреса ячейки( "A2:A" ) и ссылка на объект Cells. В данном случае явную ошибку код не вызовет, но и работать будет не всегда так, как хотелось бы. А это самое плохое, что может случиться при разработке.
Sheets("Итог").Range("A2:A" - создается ссылка на столбец " A " листа Итог. Но далее идет вычисление последней строки первого столбца. И вот как раз это вычисление происходит на основе объекта Cells, который не содержит в себе ссылки на родительский объект. А значит он будет вычислять последнюю строку исключительно для текущего листа(если код записан в стандартном модуле, а не модуле листа) - т.е. для Лист1. Правильно было бы записать так:

Sheets("Итог").Range("A2:A" & Sheets("Итог").Cells(Rows.Count, 1).End(xlUp).Row) _ .FormulaR1C1 = "=RC2-RC11"

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

lLastRow = Workbooks("Книга3.xls").Sheets("Лист1").Cells(Rows.Count, 1).End(xlUp).Row

с виду все нормально, но есть нюанс. Rows.Count по умолчанию будет относится к активной книге, если записано в стандартном модуле. Приведенный выше код должен работать с книгой формата 97-2003 и вычислить последнюю заполненную ячейку на листе1. В книгах формата Excel 97-2003(.xls) всего 65536 строк. Если в момент выполнения приведенной строки активна книга формата 2007 и выше(форматы .xlsx, .xlsm, .xlsb и пр) - то Rows.Count вернет 1048576, т.к. именно такое количество строк в листах книг версий Excel, начиная с 2007. И т.к. в книге, в которой мы пытаемся вычислить последнюю строку всего 65536 строк - получим ошибку 1004, т.к. не может быть номера строки 1048576 на листе с количеством строк 65536. Поэтому имеет смысл указывать явно откуда считывать Rows.Count:

lLastRow = Workbooks("Книга3.xls").Sheets("Лист1").Cells(Workbooks("Книга3.xls").Sheets("Лист1").Rows.Count, 1).End(xlUp).Row

или применить конструкцию With

With Workbooks("Книга3.xls").Sheets("Лист1") lLastRow = .Cells(.Rows.Count, 1).End(xlUp).Row End With

Также не мешало бы упомянуть возможность выделения несмежного диапазона(часто его называют "рваным"). Это диапазон, который обычно привыкли выделять на листе при помощи зажатой клавиши Ctrl. Что это дает? Это дает возможность выделить одновременно ячейки A1 и B10 и записать значения только в них. Для этого есть несколько способов. Самый очевидный и описанный в справке - метод Union:

Однако существует и другой метод:

В чем отличие(я бы даже сказал преимущество) Union: можно применять в цикле по условию. Например, выделить в диапазоне A1:F50 только те ячейки, значение которых больше 10 и меньше 20:

Sub SelOne() Dim rCell As Range, rSel As Range For Each rCell In Range("A1:F50") If rCell.Value > 10 And rCell.Value < 20 Then If rSel Is Nothing Then Set rSel = rCell Else Set rSel = Union(rSel, rCell) End If End If Next rCell If Not rSel Is Nothing Then rSel.Select End Sub

Конечно, можно и просто в Range через запятую передать все эти ячейки, сформировав предварительно строку. Но в случае со строкой действует ограничение: длина строки не должна превышать 255 символов.

Надеюсь, что после прочтения данной статьи проблем с обращением к диапазонам и ячейкам у Вас будет гораздо меньше.

Статья помогла? Поделись ссылкой с друзьями!

Видеоуроки

Поиск по меткам

Доброго всем дня,коллеги! Подскажите чайнику простейшее.. Есть макрос,который вставляет в активную ячейку текущее время+текст. Необходимо,что бы текст возможно было вставить только в определенном диапазоне (н-р пару столбцов), т.к. при вставке "не туда" данные,записанные ранее удаляются,и откатиться назад уже нельзя. Буду благодарен за помощь! Девочек с наступающим.

Добрый день всем! В очередной раз за помощью! Простой макрос по кнопке вставляет дату + N дней. Но часто полученная дата попадает на выходной. Что нужно дописать,или изменить, что бы полученная дата "проскакивала" вперед на ближайший рабочий день?

Sub Через_10д()
If Not Intersect(ActiveCell, Range("J14:M350")) Is Nothing Then ActiveCell = Date + 10
End Sub

1. Что бы записать "привет" в ячейку А1 не надо объявлять переменную как диапазон и присваивать ей значение из ячейки D5. Самое начало статьи сразу с ошибки начинаете.
2. Диапазон - это диапазон, я не ячейка с номером типа Cell(х,y). Если уж начали писать про диапазоны - пишите про диапазоны! У меня задача - обратиться к именованному диапазону и вытащить оттуда через ВБА значения в массив для дальнейшей обработки. А вот теперь посмотрите что из написанного может помочь это сделать. Ничего.
Спасибо, бесполезная статья с намеком на гениальность и уводящая постоянно в сторону от озвученной темы

Артем,
1. Спасибо. Вообще в самом начале статьи написан другой код:

Range("A1").Value = "Привет"
Тоже самое можно сделать сразу для нескольких ячеек:
Range("A1:C10").Value = "Привет"

Просто не так давно сменил скрипт подсветки синтаксиса кода и он почему-то отобразил дважды один и тот же код из этой статьи, вместо других. В общем поправил.
2. Прежде чем критиковать, изучите хотя бы мат.часть. Ячейка - это тот же диапазон технически. И обращение Range("A1") равносильно обращению Cells(1,1). И свойства и методы у них идентичны. Только Range может содержать более одной ячейки, Cells нет.
Цель данной статьи - научить правильно обращаться к диапазонам и понимать отличие обращения к диапазону в активном листе или в других листах и книгах. И научить обращаться как через Range, так и через Cells. И никаких намеков на гениальность, просто описание технической части и её нюансов. Впрочем, об этом я тоже упоминаю:

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

И в сторону статья уводит лишь от ВАШЕЙ проблемы, но не от темы. Ваша проблема - это работа не столько с диапазонами, сколько с массивами. Различайте понятия - вся статья про обращение к диапазонам, но описать в одной статье ответы на вопросы по диапазонам каждого проходящего нереально. Ведь само обращение к диапазону может использоваться в любой задаче: отобрать уникальные, загнать в массив, покрасить, подсчитать ячейки с тем-то и тем-то и т.д. и т.п. И все это будет подходить под определение диапазона - ведь мы к нему обращаемся :) Поэтому вменяемые люди пишут комментарии со своим вопросом, а не жалуются, что именно их вопрос здесь не озвучен.
А тем не менее Ваша задача решается элементарно и без всякого выпендрежа вроде "статья бесполезна". Надо было чуть пошерстить хотя бы этот же сайт - я приводил и такие примеры. Хотя бы в этой статье: Как ускорить и оптимизировать код VBA . Там есть советы по оптимизации для чуть более опытных, в том числе использование массивов, вместо прямого обращения к ячейкам.
И решается Ваша задача одной строкой кода:

Dim arr 'объявляем переменную, в которую помещать массив arr = Range("A1:F10").Value 'дальше делаем с массивом все, что надо

Есть еще один забавный способ адресоваться в VBA к ячейке.
[a2] = "Привет!" ' Занесет в ячейку А2 текущей книги текущего листа "Привет!"
Работает при способе адресации А1. При адресации RC будет работать такой способ:
[r1c2] = "Привет!"

Подскажите, пожалуйста, можно ли так же обращаться к динамическим диапазонам, нижняя граница которых записана через ИНДЕКС(ПОИСКПОЗ. У меня всякие ошибки вылезают при попытке обращения к такому диапазону.

Матвей, можно. Но не зная как и что Вы там задаете и какие лезут ошибки помочь нечем :( Попробуйте создать тему на форуме с приложенным файлом и подробным описанием проблемы.

I've heard much about the understandable abhorrence of using .Select in Excel VBA, but I am unsure of how to avoid using it. I am finding that my code would be more re-usable if I were able to use variables instead of Select functions. However, I am not sure how to refer to things (like the ActiveCell , etc.) if not using Select .


29.1k 21 21 gold badges 97 97 silver badges 124 124 bronze badges 6,544 8 8 gold badges 21 21 silver badges 25 25 bronze badges And there are occasions - editing chart data in ppt with an underlying excel file being one - where activate or select are required.

16 Answers 16

Some examples of how to avoid select

Use Dim 'd variables

Set the variable to the required range. There are many ways to refer to a single-cell range:

Or a multi-cell range:

You can use the shortcut to the Evaluate method, but this is less efficient and should generally be avoided in production code.

All the above examples refer to cells on the active sheet. Unless you specifically want to work only with the active sheet, it is better to Dim a Worksheet variable too:

If you do want to work with the ActiveSheet , for clarity it's best to be explicit. But take care, as some Worksheet methods change the active sheet.

Again, this refers to the active workbook. Unless you specifically want to work only with the ActiveWorkbook or ThisWorkbook , it is better to Dim a Workbook variable too.

If you do want to work with the ActiveWorkbook , for clarity it's best to be explicit. But take care, as many WorkBook methods change the active book.

You can also use the ThisWorkbook object to refer to the book containing the running code.

A common (bad) piece of code is to open a book, get some data then close again

And it would be better like:

Pass ranges to your Sub s and Function s as Range variables:

You should also apply Methods (such as Find and Copy ) to variables:

If you are looping over a range of cells it is often better (faster) to copy the range values to a variant array first and loop over that:

This is a small taster for what's possible.


29.1k 21 21 gold badges 97 97 silver badges 124 124 bronze badges 49.6k 10 10 gold badges 80 80 silver badges 116 116 bronze badges @chrisneilsen Chris, I believe you can also use worksheet prefix before shorthand cell reference notation to save you from typing Range like this: ActiveSheet.[a1:a4] or ws.[b6] .

Two main reasons why .Select , .Activate , Selection , Activecell , Activesheet , Activeworkbook , etc. should be avoided

  1. It slows down your code.
  2. It is usually the main cause of runtime errors.

How do we avoid it?

1) Directly work with the relevant objects

Consider this code

This code can also be written as

2) If required declare your variables. The same code above can be written as

That's a good answer, but what I am missing on this topic is when we actually need Activate. Everyone says it is bad, but no one explains any cases where it makes sense to use it.

Situation when you can't avoid using .Activate/.Select . (Will add more links as and when I come across them)

  1. When you want to present a worksheet to a user so that the user can see it.
  2. Scenarios like Working macro returns error when run from form control where you are forced to use .Activate
  3. When usual methods of Text To Columns / .Formula = .Formula doesn't work then you may have to resort to .Select


141k 16 16 gold badges 193 193 silver badges 242 242 bronze badges I find that you may sometimes need to activate a sheet first if you need to paste or filter data on it. I would say its best to avoid activating as much as possible but there are instances where you need to do it. So keep activating and selecting to an absolute minimum as per the answer above. i think the point is not to completely avoid using them, but just as much as possible. if you want to save a workbook, so that when someone opens it a certain cell in a certain sheet is selected, then you have to select that sheet and cell. copy/paste is a bad example, at least in the case of values, it can be done faster by a code such as Sheets(2).[C10:D12].Value = Sheets(1).[A1:B3].Value

One small point of emphasis I'll add to all the excellent answers given previously:

Probably the biggest thing you can do to avoid using Select is to as much as possible, use named ranges (combined with meaningful variable names) in your VBA code. This point was mentioned above, but it was glossed over a bit; however, it deserves special attention.

Here are a couple of additional reasons to make liberal use of named ranges, though I am sure I could think of more.

Named ranges make your code easier to read and understand.

It is pretty obvious what the named ranges Months and MonthlySales contain, and what the procedure is doing.

Why is this important? Partially because it is easier for other people to understand it, but even if you are the only person who will ever see or use your code, you should still use named ranges and good variable names because you will forget what you meant to do with it a year later, and you will waste 30 minutes just figuring out what your code is doing.

Named ranges ensure that your macros do not break when (not if!) the configuration of the spreadsheet changes.

Consider, if the above example had been written like this:

This code will work just fine at first - that is until you or a future user decides "gee wiz, I think I'm going to add a new column with the year in Column A !", or put an expenses column between the months and sales columns, or add a header to each column. Now, your code is broken. And because you used terrible variable names, it will take you a lot more time to figure out how to fix it than it should take.

If you had used named ranges to begin with, the Months and Sales columns could be moved around all you like, and your code would continue working just fine.


29.1k 21 21 gold badges 97 97 silver badges 124 124 bronze badges


36k 12 12 gold badges 61 61 silver badges 108 108 bronze badges I agree with your development philosophy; however I think the paper is nonsense. It talks about how range names can confuse novices who are debugging spreadsheets, but anyone who uses novices to look at complex spreadsheets gets what they deserve! I used to work for a firm who reviewed financial spreadsheets, and I can tell you that it is not the sort of job you give to a novice. There is no meaningful debate. Anyone who argues against defined names has not taken the time to fully understand their ramifications. Named formulas may be the single most profound and useful construct in all of Excel. @brettdj: Your citation is correct, but you forgot to mention that it is followed by six "Except. " phrases. One of them being: "Except as a substitute for cell references in macro coding Always use Excel Names as a substitute for cell references when constructing macros. This is to avoid errors arising from the insertion of additional rows or columns whereby the macro coding no longer points to the intended source data."

I'm going to give the short answer since everyone else gave the long one.

You'll get .select and .activate whenever you record macros and reuse them. When you .select a cell or sheet it just makes it active. From that point on whenever you use unqualified references like Range.Value they just use the active cell and sheet. This can also be problematic if you don't watch where your code is placed or a user clicks on the workbook.

So, you can eliminate these issues by directly referencing your cells. Which goes:

There are various combinations of these methods, but that would be the general idea expressed as shortly as possible for impatient people like me.


8,562 5 5 gold badges 34 34 silver badges 51 51 bronze badges 2,063 5 5 gold badges 22 22 silver badges 46 46 bronze badges

". and am finding that my code would be more re-usable if I were able to use variables instead of Select functions."

While I cannot think of any more than an isolated handful of situations where .Select would be a better choice than direct cell referencing, I would rise to the defense of Selection and point out that it should not be thrown out for the same reasons that .Select should be avoided.

There are times when having short, time-saving macro sub routines assigned to hot-key combinations available with the tap of a couple of keys saves a lot of time. Being able to select a group of cells to enact the operational code on works wonders when dealing with pocketed data that does not conform to a worksheet-wide data format. Much in the same way that you might select a group of cells and apply a format change, selecting a group of cells to run special macro code against can be a major time saver.

Examples of Selection-based sub framework:

The actual code to process could be anything from a single line to multiple modules. I have used this method to initiate long running routines on a ragged selection of cells containing the filenames of external workbooks.

In short, don't discard Selection due to its close association with .Select and ActiveCell . As a worksheet property it has many other purposes.

(Yes, I know this question was about .Select , not Selection but I wanted to remove any misconceptions that novice VBA coders might infer.)

Читайте также: