автоматически выполнять макрос Excel при изменении ячейки

91

Как я могу автоматически запускать макрос Excel каждый раз, когда изменяется значение в определенной ячейке?

Прямо сейчас мой рабочий код:

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Range("H5")) Is Nothing Then Macro
End Sub

где "H5"- конкретная отслеживаемая ячейка и Macroимя макроса.

Есть ли способ лучше?

намин
источник
Удовлетворяет ли UDF RunMacroWhenValueChanges в FormulaDesk вашим требованиям? Formuladesk.com
Гарет Хейтер

Ответы:

108

Ваш код выглядит неплохо.

Однако будьте осторожны, потому что ваш вызов Range("H5")- это команда быстрого доступа Application.Range("H5"), которая эквивалентна Application.ActiveSheet.Range("H5"). Это может быть хорошо, если единственными изменениями являются изменения пользователя, что является наиболее типичным, но значения ячеек рабочего листа могут измениться, когда он не является активным, посредством программных изменений, например VBA.

Имея это в виду, я бы использовал Target.Worksheet.Range("H5"):

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Target.Worksheet.Range("H5")) Is Nothing Then Macro
End Sub

Или вы можете использовать Me.Range("H5"), если обработчик событий находится на кодовой странице для рассматриваемого рабочего листа (обычно это так):

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Me.Range("H5")) Is Nothing Then Macro
End Sub

Надеюсь это поможет...

Майк Розенблюм
источник
4
что, если ячейка H5изменена с другого листа, допустим, указанная sheet2 выше функция не работает. Помогите плз в этом.
dhpratik
2
Для всех, кто пришел сюда из поиска Google, убедитесь, что вы вставили этот код в таблицу в vba, а не в модуль, как я. посмотрите stackoverflow.com/questions/15337008/…
hammythepig
Application.ActiveSheet.Range ("H5"). ==> target.parent.range ("H5") еще безопаснее
Пьер
1
@WillEdiger Всякий раз, когда вы явно не указываете ссылку на лист, Excel предполагает, ActiveSheetи всякий раз, когда вы явно не указываете, что вы работаете с Excel, предполагает Excel Application.
Скотт Маркус
1
Следует отметить, что в модуле рабочего листа кода (который где Worksheet_Changeсобытие должно быть расположено), неквалифицированный Rangeвовсе не по умолчанию , ActiveSheetно вместо этого относится к листу , содержащий код. Таким образом, код в этом ответе фактически совпадает с кодом в вопросе. (Примечание: еще в 2009 году, когда был написан этот ответ, он мог быть другим, но я почти уверен, что это не так.)
YowE3K,
7

Обработайте Worksheet_Changeсобытие или Workbook_SheetChangeсобытие.

Обработчики событий принимают аргумент «Target As Range», поэтому вы можете проверить, включает ли изменяемый диапазон интересующую вас ячейку.

Джо
источник
Спасибо, это работает. Я проверяю диапазон, скажем, с Target.Address = Range("H5").Address. Есть способ попроще?
namin 03
Альтернатива: Not (Intersect(Target, Range("H5")) Is Nothing) . Как бы вы это сделали?
namin 03
2
Первый комментарий ( Target.Address = Range("H5").Address) не сработал бы, если бы ваша ячейка была только частью измененного диапазона. Второй комментарий по-прежнему страдает проблемами, описанными Майком Розенблюмом.
Ant
5

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

1) Откройте редактор VBA, в разделе VBA Project (YourWorkBookName.xlsm) откройте объект Microsoft Excel и выберите лист, к которому будет относиться событие изменения.

2) Вид кода по умолчанию - «Общее». В раскрывающемся списке вверху по центру выберите «Рабочий лист».

3) Private Sub Worksheet_SelectionChange уже там, как и должно быть, оставьте его в покое. Скопируйте / вставьте приведенный выше код Майка Розенблюма и измените ссылку .Range на ячейку, для которой вы наблюдаете изменение (B3, в моем случае). Однако пока не размещайте свой макрос (я убрал слово «Макрос» после «Тогда»):

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Me.Range("H5")) Is Nothing Then
End Sub

или из раскрывающегося списка в левом верхнем углу выберите «Изменить» и в пространство между частным подпиской и конечной подпиской вставьте If Not Intersect(Target, Me.Range("H5")) Is Nothing Then

4) В строке после «Then» отключите события, чтобы при вызове макроса он не запускал события и не пытался запустить этот Worksheet_Change снова в бесконечном цикле, который приводит к сбою Excel и / или иным образом все портит:

Application.EnableEvents = False

5) Назовите свой макрос

Call YourMacroName

6) Включите события, чтобы сработало следующее изменение (и любые / все другие события):

Application.EnableEvents = True

7) Завершите блок If и Sub:

    End If
End Sub

Весь код:

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Me.Range("B3")) Is Nothing Then
        Application.EnableEvents = False
        Call UpdateAndViewOnly
        Application.EnableEvents = True
    End If
End Sub

Это позволяет включать / выключать события из модулей, что создает проблемы, и просто позволяет запускать изменение, отключает события, запускает ваш макрос и снова включает события.

Эрик Вон-Шоби
источник
3

Я предпочитаю использовать не ячейку, а диапазон

    Dim cell_to_test As Range, cells_changed As Range

    Set cells_changed = Target(1, 1)
    Set cell_to_test = Range( RANGE_OF_CELLS_TO_DETECT )

    If Not Intersect(cells_changed, cell_to_test) Is Nothing Then 
       Macro
    End If
Хавьер Торон
источник
Это то же самое, что и одна клетка. Вы можете установить диапазон как одну ячейку, диапазон непрерывных ячеек или даже разбросанные ячейки (все разделенные запятой).
Шай Алон
0

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

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

Я сделал следующее,

Private Sub Worksheet_Change(ByVal Target As Range) 
  If Not Intersect(Target, Target.Worksheets("Symbols").Range("$C$3")) Is Nothing Then
   'Run Macro
End Sub
Хуан Гарсия
источник
1
По какой-то причине я не могу заставить это работать. Когда я говорю, что код запускается в VBA, он открывает всплывающее меню и спрашивает меня, хочу ли я запустить макрос вместо автоматического запуска макроса?
David Van der Vieren