#vba #excel
#vba #excel
Вопрос:
У меня есть рабочий лист с несколькими событиями изменения рабочего листа. К сожалению, из-за них я получаю некоторые ошибки памяти. Мне было интересно, может ли кто-нибудь взглянуть на этот фрагмент кода и сообщить мне, можно ли его написать более эффективно?
Это событие изменения рабочего листа вызывает другой макрос тогда и только тогда, когда ячейка K4 = «Основана на событии» и в каждой из следующих ячеек что-то есть: J12: J15, M12: M14. Я могу вызвать макрос, если ячейки J12: J15, M12: M14 уже заполнены, а K4 изменен на «Основанный на событиях»
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("J12") <> "" And _
Range("J13") <> "" And _
Range("J14") <> "" And _
Range("J15") <> "" And _
Range("M12") <> "" And _
Range("M13") <> "" And _
Range("M14") <> "" Then
Dim ZRange As Range
Set ZRange = Range("K4")
If ZRange = "Event Based" Then
If Union(Target, ZRange).Address = ZRange.Address Then
Application.EnableEvents = False
Call EventBasedYes
Application.EnableEvents = True
End If
End If
End If
Моя проблема в том, что я написал другое событие изменения рабочего листа для каждой отдельной ячейки. Следующее срабатывает, если K4 =»Основано на событиях» и J13: J15 содержат что-то в себе, а затем данные добавляются в J12
If Range("K4") = "Event Based" And _
Range("J13") <> "" And _
Range("J14") <> "" And _
Range("J15") <> "" And _
Range("M12") <> "" And _
Range("M13") <> "" And _
Range("M14") <> "" Then
Dim FRange As Range
Set FRange = Range("J12")
If FRange <> "" Then
If Union(Target, FRange).Address = FRange.Address Then
Application.EnableEvents = False
Call EventBasedYes
Application.EnableEvents = True
End If
End If
End If
Я не знаю, как написать ОДНО событие таким образом, чтобы, если все ячейки были заполнены, вызывался макрос, и таким образом, чтобы, если какая-либо ячейка была очищена, макрос с именем EventBasedNo. Извините, я не очень разбираюсь в коде VBA. Я уверен, что есть способ сделать это.
Комментарии:
1. Какую ошибку вы получаете и в какой строке? Вы сказали «ошибка памяти», но я не вижу в коде ничего, что могло бы вызвать «ошибку нехватки памяти» (которая является единственной известной мне ошибкой памяти). Каков фактический код ошибки?
2.
I have written a different worksheet change event for each individual cell
— как вы это сделали? На листе может быть только один обработчик.3. Извините, GSerg, возможно, я был неясен. Я просто имел в виду, что включил код для каждого изменения в основное событие изменения рабочего листа.
Ответ №1:
Что касается улучшения скорости:
Одна вещь, которую вы могли бы сделать, — это не выполнять много тестов для значений ячеек, если вы не знаете, что существует вероятность того, что вам понадобится выполнить этот тест.
Итак, ваш текущий код гласит:
If Range("J12") <> "" And _
Range("J13") <> "" And _
Range("J14") <> "" And _
Range("J15") <> "" And _
Range("M12") <> "" And _
Range("M13") <> "" And _
Range("M14") <> "" Then
Dim ZRange As Range
Set ZRange = Range("K4")
If ZRange = "Event Based" Then
If Union(Target, ZRange).Address = ZRange.Address Then
Application.EnableEvents = False
Call EventBasedYes
Application.EnableEvents = True
End If
End If
End If
это означает, что вы просматриваете значения J12
, J13
, J14
J15
, M12
M13
M14
K4
и , а затем,, решаете, произошло ли изменение листа в интересующей вас ячейке.
Переместив тест относительно Target
местоположения ранее, вы можете сохранить эти поисковые запросы:
If Not Application.Intersect(Target, Range("K4")) Is Nothing Then
If Range("J12") <> "" And _
Range("J13") <> "" And _
Range("J14") <> "" And _
Range("J15") <> "" And _
Range("M12") <> "" And _
Range("M13") <> "" And _
Range("M14") <> "" Then
Dim ZRange As Range
Set ZRange = Range("K4")
If ZRange = "Event Based" Then
Application.EnableEvents = False
Call EventBasedYes
Application.EnableEvents = True
End If
End If
End If
Если многие ячейки, которые вы проверяете, скорее всего, являются частью Target
одного события Worksheet_Change, то, возможно, вам лучше сначала протестировать все интересующие вас ячейки, т. Е. использовать что-то вроде:
If Not Application.Intersect(Target, Range("K4,J12,X47")) Is Nothing Then
а затем сохраните значения ячеек, на которые вы часто ссылаетесь, в переменных (или в массиве вариантов, если они находятся в непрерывном блоке?), чтобы вы могли ссылаться на переменные несколько раз, а не обращаться к самой ячейке несколько раз.
PS Union(Target, ZRange).Address = ZRange.Address
эквивалентно Target.Address = ZRange.Address
. Намеренно ли ваш код запускается только при изменении одной ячейки (т. Е. Вы не хотите, чтобы код выполнялся, если ячейки K2: K6 изменены в одном событии, только если K4 изменен сам по себе)? В предлагаемом мной изменении используется Intersect
, которое будет выполняться, если измененный диапазон включает интересующую вас ячейку, поэтому вам следует изменить это обратно, если вы не хотите, чтобы это произошло.
Возможная перезапись
Я думаю, что понимаю, что вы пытаетесь сделать. Возможно, следующий код выполнит все ваши тесты сразу:
If Not Application.Intersect(Target, Range("K4,J12:J15,M12:M14")) Is Nothing Then
Application.EnableEvents = False
If Range("J12").Value <> "" And _
Range("J13").Value <> "" And _
Range("J14").Value <> "" And _
Range("J15").Value <> "" And _
Range("M12").Value <> "" And _
Range("M13").Value <> "" And _
Range("M14").Value <> "" And _
Range("K4").Value = "Event Based" Then
Call EventBasedYes
Else
Call EventBasedNo
End If
Application.EnableEvents = True
End If