Определить, действительно ли значение ячейки было изменено путем редактирования
Worksheet_Change
триггеры, когда значение ячейки изменяется (это то, что я хочу), но оно также запускается, когда вы вводите ячейку, как если бы ее редактировать, но на самом деле не изменяете значение ячейки (и это то, что я не хотят этого делать).
Скажем, я хочу добавить штриховку в ячейки, значение которых было изменено. Поэтому я кодирую это:
Private Sub Worksheet_Change(ByVal Target As Range)
Target.Interior.ColorIndex = 36
End Sub
Теперь, чтобы проверить мою работу: измените ячейку A1 и ячейка подсвечивается. Это желаемое поведение. Все идет нормально. Затем дважды щелкните B1, но не изменяйте значение там, а затем нажмите C1. Вы заметите, что B1 подсвечивается! И это не желаемое поведение.
Нужно ли мне переходить к рассмотренным здесь методам сбора старого значения, а затем сравнивать старые с новыми, прежде чем выделять ячейку? Я, конечно, надеюсь, что там что-то мне не хватает.
Ответы
Ответ 1
Я предлагаю автоматически сохранять "зеркальную копию" вашего листа на другом листе для сравнения с измененным значением ячейки.
@brettdj и @JohnLBevan по существу предлагают делать то же самое, но они хранят значения ячеек в комментариях или словаре соответственно (и +1 для этих идей). Мое чувство, однако, состоит в том, что концептуально гораздо проще создавать резервные копии ячеек в ячейках, а не в других объектах (особенно комментарии, которые вы или пользователь может захотеть использовать для других целей).
Итак, скажем, у меня есть Sheet1
, чьи ячейки пользователь может изменить. Я создал этот другой лист под названием Sheet1_Mirror
(который вы могли бы создать в Workbook_Open
и мог бы быть скрытым, если вы этого захотите - до вас). Начнем с того, что содержимое Sheet1_Mirror
будет идентично содержимому Sheet1
(опять же, вы можете применить это в Workbook_Open
).
Каждый раз, когда срабатывает Sheet1
Worksheet_Change
, код проверяет, действительно ли значение "измененной" ячейки в Sheet1
отличается от значения в Sheet1_Mirror
. Если это так, оно выполняет требуемое действие и обновляет зеркальный лист. Если нет, то ничего.
Это должно привести вас к правильному пути:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim r As Range
For Each r In Target.Cells
'Has the value actually changed?
If r.Value <> Sheet1_Mirror.Range(r.Address).Value Then
'Yes it has. Do whatever needs to be done.
MsgBox "Value of cell " & r.Address & " was changed. " & vbCrLf _
& "Was: " & vbTab & Sheet1_Mirror.Range(r.Address).Value & vbCrLf _
& "Is now: " & vbTab & r.Value
'Mirror this new value.
Sheet1_Mirror.Range(r.Address).Value = r.Value
Else
'It hasn't really changed. Do nothing.
End If
Next
End Sub
Ответ 2
Попробуйте этот код. Когда вы вводите диапазон, он сохраняет исходные значения ячейки в объекте словаря. Когда происходит изменение рабочего листа, он сравнивает сохраненные значения с действиями и выделяет любые изменения.
NB: чтобы повысить эффективность эталонных сценариев сценариев Microsoft, заменив As Object на As Scripting.Dictionary и CreateObject ( "Scripting.Dictionary" ) с New Scripting.Dictionary.
Option Explicit
Private previousRange As Object 'reference microsoft scripting runtime & use scripting.dictionary for better performance
'I've gone with late binding to avoid references from confusing the example
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cell As Variant
For Each cell In Target
If previousRange.Exists(cell.Address) Then
If previousRange.Item(cell.Address) <> cell.FormulaR1C1 Then
cell.Interior.ColorIndex = 36
End If
End If
Next
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim cell As Variant
Set previousRange = Nothing 'not really needed but I like to kill off old references
Set previousRange = CreateObject("Scripting.Dictionary")
For Each cell In Target.Cells
previousRange.Add cell.Address, cell.FormulaR1C1
Next
End Sub
пс. любой код vba для обновления ячеек (даже просто цвет) остановит работу excel undo от работы! Чтобы обойти это, вы можете перепрограммировать функциональность отмены, но она может быть достаточно интенсивной. Примеры решений: http://www.jkp-ads.com/Articles/UndoWithVBA00.asp/http://www.j-walk.com/ss/excel/tips/tip23.htm
Ответ 3
Этот код использует комментарии для хранения предыдущего значения (обратите внимание, если вам нужны комментарии для других целей, этот метод удалит их)
- Ячейки, которые не имеют значения, имеют цвет reset до
xlNone
- Целое значение, введенное в ячейку, является синим (ColorIndex 34)
- Если значение изменено, ячейка переходит от синего цвета к желтому.
![enter image description here]()
Обычный модуль - отключить отображение комментариев
Sub SetCom()
Application.DisplayCommentIndicator = xlNoIndicator
End Sub
Листовой код для внесения изменений
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng1 As Range
Dim shCmt As Comment
For Each rng1 In Target.Cells
If Len(rng1.Value) = 0 Then
rng1.Interior.ColorIndex = xlNone
On Error Resume Next
rng1.Comment.Delete
On Error GoTo 0
Else
On Error Resume Next
Set shCmt = rng1.Comment
On Error GoTo 0
If shCmt Is Nothing Then
Set shCmt = rng1.AddComment
shCmt.Text Text:=CStr(rng1.Value)
rng1.Interior.ColorIndex = 34
Else
If shCmt.Text <> rng1.Value Then
rng1.Interior.ColorIndex = 36
shCmt.Text Text:=CStr(rng1.Value)
End If
End If
End If
Next
End Sub
Ответ 4
Я знаю, что это старый поток, но у меня была такая же проблема: "Смените ячейку A1, и ячейка подсвечивается. Это то, что я ожидаю. Дважды щелкните B1, но не меняйте значение там, а затем щелкните C1. Вы заметите, что B1 подсвечивается!"
Я не хотел выделять ячейку, если она была только двойным щелчком без значения внутри.
Я решил легко. Возможно, это поможет кому-то в будущем.
Я только что добавил это в начале события:
If Target.Value = "" Then
Exit Sub
End If