Как я могу запускать код VBA каждый раз, когда значение ячейки изменяется по формуле? - PullRequest
5 голосов
/ 08 декабря 2010

Я хотел бы знать, как я могу запускать код VBA каждый раз, когда значение ячейки изменяется по формуле ??Мне удалось запустить код, когда ячейка получает значение, измененное пользователем, но это не работает w

Ответы [ 4 ]

12 голосов
/ 08 декабря 2010

Если у меня есть формула в ячейке A1 (например, = B1 * C1), и я хочу запускать некоторый код VBA при каждом изменении A1 из-за обновлений в ячейке B1 или C1, тогда я могу использовать следующее:

Private Sub Worksheet_Calculate()
    Dim target As Range
    Set target = Range("A1")

    If Not Intersect(target, Range("A1")) Is Nothing Then
    //Run my VBA code
    End If
End Sub

Обновление

Насколько я знаю, проблема с Worksheet_Calculate заключается в том, что она запускается для всех ячеек, содержащих формулы в электронной таблице, и вы не можете определить, какая ячейка была пересчитана (т. Е. Worksheet_Calculate не предоставляет объект Target )

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

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim updatedCell As Range
    Set updatedCell = Range(Target.Dependents.Address)

    If Not Intersect(updatedCell, Range("A:A")) Is Nothing Then
       updatedCell.AddComment ("My Comments")
    End If

End Sub

Чтобы пояснить, для обновления формулы одна из входных ячеек в эту формулу должна измениться, например, если формула в A1 равна =B1 * C1, то либо B1, либо C1 должны измениться, чтобы обновить A1.

Мы можем использовать событие Worksheet_Change, чтобы обнаружить изменение ячейки на листе / листе, а затем использовать функцию аудита Excel для отслеживания зависимостей, например. Ячейка A1 зависит от B1 и C1, и в этом случае код Target.Dependents.Address вернет $A$1 для любого изменения B1 или C1.

Учитывая это, все, что нам теперь нужно сделать, это проверить, находится ли зависимый адрес в столбце A (используя Intersect). Если он находится в столбце А, мы можем добавить комментарии в соответствующую ячейку.

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

2 голосов
/ 19 декабря 2014

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

Вот что вы должны добавить в модуль рабочего листа:

(Дата обновления: строка "Set rDependents = Target.Dependents" выдаст ошибку, если нет зависимых. Это обновление позаботится об этом.)

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim rDependents As Range

    On Error Resume Next
    Set rDependents = Target.Dependents
    If Err.Number > 0 Then
        Exit Sub
    End If
    ' If the cell with the formula is "F160", for example...
    If Not Application.Intersect(rDependents, Range("F160")) Is Nothing Then
        Call abc
    End If
End Sub

Private Sub abc()
    MsgBox """abc()"" is running now"
End Sub

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

1 голос
/ 04 ноября 2014

Вот еще один способ использования классов. Класс может хранить начальное значение ячейки и адрес ячейки. При вычислении события он сравнивает текущее значение адреса с сохраненным начальным значением. Пример ниже сделан для прослушивания только одной ячейки («A2»), но вы можете инициировать прослушивание большего количества ячеек в модуле или изменить класс для работы с более широкими диапазонами.

Модуль класса под названием "Class1":

Public WithEvents MySheet As Worksheet
Public MyRange As Range
Public MyIniVal As Variant

Public Sub Initialize_MySheet(Sh As Worksheet, Ran As Range)
    Set MySheet = Sh
    Set MyRange = Ran
    MyIniVal = Ran.Value
End Sub
Private Sub MySheet_Calculate()

If MyRange.Value <> MyIniVal Then
    Debug.Print MyRange.Address & " was changed from " & MyIniVal & " to " & MyRange.Value
    StartClass
End If

End Sub

Инициализировать класс в модуле normall.

Dim MyClass As Class1

Sub StartClass()
Set MyClass = Nothing
Set MyClass = New Class1
MyClass.Initialize_MySheet ActiveSheet, Range("A2")
End Sub
0 голосов
/ 07 ноября 2014

Вот мой код:

Я знаю, это выглядит ужасно, но это работает!Конечно, есть решения, которые намного лучше.

Описание кода:

Когда книга открывается, значения ячеек с B15 по N15 сохраняются в переменной PrevValb до PrevValn.Если происходит событие Worksheet_Calculate (), предыдущие значения сравниваются с фактическими значениями ячеек.При изменении значения ячейка помечается красным цветом.Этот код может быть написан с функциями, так что он намного короче и легче для чтения.Есть кнопка сброса цвета (Seenchanges), которая сбрасывает цвет к предыдущему цвету.

Рабочая книга:

Private Sub Workbook_Open()
PrevValb = Tabelle1.Range("B15").Value
PrevValc = Tabelle1.Range("C15").Value
PrevVald = Tabelle1.Range("D15").Value
PrevVale = Tabelle1.Range("E15").Value
PrevValf = Tabelle1.Range("F15").Value
PrevValg = Tabelle1.Range("G15").Value
PrevValh = Tabelle1.Range("H15").Value
PrevVali = Tabelle1.Range("I15").Value
PrevValj = Tabelle1.Range("J15").Value
PrevValk = Tabelle1.Range("K15").Value
PrevVall = Tabelle1.Range("L15").Value
PrevValm = Tabelle1.Range("M15").Value
PrevValn = Tabelle1.Range("N15").Value
End Sub

Модуль:

Sub Seenchanges_Klicken()
Range("B15:N15").Interior.Color = RGB(252, 213, 180)
End Sub

Лист1:

Private Sub Worksheet_Calculate()
If Range("B15").Value <> PrevValb Then
    Range("B15").Interior.Color = RGB(255, 0, 0)
    PrevValb = Range("B15").Value
End If
If Range("C15").Value <> PrevValc Then
    Range("C15").Interior.Color = RGB(255, 0, 0)
    PrevValc = Range("C15").Value
End If
If Range("D15").Value <> PrevVald Then
    Range("D15").Interior.Color = RGB(255, 0, 0)
    PrevVald = Range("D15").Value
End If
If Range("E15").Value <> PrevVale Then
    Range("E15").Interior.Color = RGB(255, 0, 0)
    PrevVale = Range("E15").Value
End If
If Range("F15").Value <> PrevValf Then
    Range("F15").Interior.Color = RGB(255, 0, 0)
    PrevValf = Range("F15").Value
End If
If Range("G15").Value <> PrevValg Then
    Range("G15").Interior.Color = RGB(255, 0, 0)
    PrevValg = Range("G15").Value
End If
If Range("H15").Value <> PrevValh Then
    Range("H15").Interior.Color = RGB(255, 0, 0)
    PrevValh = Range("H15").Value
End If
If Range("I15").Value <> PrevVali Then
    Range("I15").Interior.Color = RGB(255, 0, 0)
    PrevVali = Range("I15").Value
End If
If Range("J15").Value <> PrevValj Then
    Range("J15").Interior.Color = RGB(255, 0, 0)
    PrevValj = Range("J15").Value
End If
If Range("K15").Value <> PrevValk Then
    Range("K15").Interior.Color = RGB(255, 0, 0)
    PrevValk = Range("K15").Value
End If
If Range("L15").Value <> PrevVall Then
    Range("L15").Interior.Color = RGB(255, 0, 0)
    PrevVall = Range("L15").Value
End If
If Range("M15").Value <> PrevValm Then
    Range("M15").Interior.Color = RGB(255, 0, 0)
    PrevValm = Range("M15").Value
End If
If Range("N15").Value <> PrevValn Then
    Range("N15").Interior.Color = RGB(255, 0, 0)
    PrevValn = Range("N15").Value
End If
End Sub
...