automatycznie wykonuje makro programu Excel po zmianie komórki

91

Jak mogę automatycznie wykonać makro programu Excel za każdym razem, gdy zmienia się wartość w określonej komórce?

W tej chwili mój działający kod to:

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

gdzie "H5"jest konkretna monitorowana komórka i Macrojest nazwą makra.

Czy jest lepszy sposób?

namin
źródło
Czy UDF RunMacroWhenValueChanges w FormulaDesk spełnia Twoje wymagania? formuladesk.com
Gareth Hayter

Odpowiedzi:

108

Twój kod wygląda całkiem nieźle.

Uważaj jednak, ponieważ wywołanie to Range("H5")jest poleceniem skrótu do Application.Range("H5"), które jest równoważne z Application.ActiveSheet.Range("H5"). Może to być w porządku, jeśli jedynymi zmianami są zmiany użytkownika - co jest najbardziej typowe - ale wartości komórek arkusza roboczego mogą się zmieniać, gdy nie jest to aktywny arkusz poprzez zmiany programistyczne, np. VBA.

Mając to na uwadze, użyłbym 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

Lub możesz użyć Me.Range("H5"), jeśli program obsługi zdarzeń znajduje się na stronie kodowej dla danego arkusza roboczego (zwykle jest):

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

Mam nadzieję że to pomoże...

Mike Rosenblum
źródło
4
co, jeśli komórka H5zostanie zmieniona z innego arkusza, powiedzmy, że sheet2 powyższa funkcja nie działa. proszę o pomoc w tym.
dhpratik
2
Dla każdego, kto przychodzi tutaj z wyszukiwarki Google, pamiętaj, aby wkleić ten kod do arkusza w VBA, a nie moduł tak jak ja. spójrz na stackoverflow.com/questions/15337008/ ...
hammythepig
Application.ActiveSheet.Range („H5”). ==> target.parent.range ("H5") jest jeszcze bezpieczniejsze
Pierre
1
@WillEdiger Ilekroć nie określisz jawnie odniesienia do arkusza, program Excel zakłada, ActiveSheeta gdy nie określisz wyraźnie, że jest to program Excel, z którym pracujesz, zakłada program Excel Application.
Scott Marcus
1
Należy zauważyć, że w module kodu arkusza roboczego (czyli tam, gdzie Worksheet_Changezdarzenie musi być zlokalizowane), niekwalifikowany Rangenie jest domyślnie, ActiveSheetale zamiast tego odwołuje się do arkusza zawierającego kod. Kod w tej odpowiedzi jest zatem w rzeczywistości taki sam jak kod w pytaniu. (Uwaga: w 2009 roku, kiedy napisano tę odpowiedź, mogła być inna, ale jestem prawie pewien, że tak nie było).
YowE3K,
7

Obsługuj Worksheet_Changewydarzenie lub Workbook_SheetChangewydarzenie.

Procedury obsługi zdarzeń przyjmują argument „Docelowy jako zakres”, więc możesz sprawdzić, czy zmieniany zakres obejmuje komórkę, która Cię interesuje.

Joe
źródło
Dzięki, działa. I sprawdzić zakres, powiedzmy, Target.Address = Range("H5").Address. Czy istnieje prostszy sposób?
namin
Alternatywą: Not (Intersect(Target, Range("H5")) Is Nothing) . Czy tak byś to zrobił?
namin
2
Pierwszy komentarz ( Target.Address = Range("H5").Address) nie działałby, gdyby komórka była tylko częścią zmienionego zakresu. Drugi komentarz wciąż cierpi na problemy opisane przez Mike'a Rosenbluma.
Ant,
5

Spędziłem dużo czasu na badaniu tego i uczeniu się, jak to wszystko działa, po tym, jak naprawdę zepsułem wyzwalacze zdarzeń. Ponieważ było tak wiele rozproszonych informacji, postanowiłem podzielić się tym, co znalazłem, aby działać w jednym miejscu, krok po kroku w następujący sposób:

1) Otwórz Edytor VBA, pod Projektem VBA (NazwaTwojejKsiążki.xlsm) otwórz obiekt Microsoft Excel i wybierz arkusz, którego będzie dotyczyło zdarzenie zmiany.

2) Domyślny widok kodu to „Ogólne”. Z rozwijanej listy w górnej środkowej części wybierz „Arkusz”.

3) Private Sub Worksheet_SelectionChange już tam jest tak, jak powinno, zostaw to w spokoju. Skopiuj / Wklej kod Mike'a Rosenbluma z góry i zmień odwołanie .Range do komórki, dla której szukasz zmiany (B3, w moim przypadku). Nie umieszczaj jednak jeszcze swojego makra (usunąłem słowo „makro” po „to”):

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

lub z listy rozwijanej w lewym górnym rogu wybierz „Zmień” i w miejscu między Private Sub i End Sub wklej If Not Intersect(Target, Me.Range("H5")) Is Nothing Then

4) W wierszu po „Następnie” wyłącz zdarzenia, aby wywołanie makra nie wywoływało zdarzeń i spróbuj ponownie uruchomić ten arkusz roboczy_Zmień w niekończącym się cyklu, który powoduje awarię programu Excel i / lub w inny sposób wszystko psuje:

Application.EnableEvents = False

5) Wywołaj swoje makro

Call YourMacroName

6) Włącz wydarzenia z powrotem, aby następna zmiana (i wszystkie / wszystkie inne zdarzenia) zostały uruchomione:

Application.EnableEvents = True

7) Zakończ blok If i Sub:

    End If
End Sub

Cały kod:

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

Powoduje to włączanie / wyłączanie zdarzeń z modułów, co stwarza problemy i po prostu pozwala wyzwalaczowi zmiany, wyłącza zdarzenia, uruchamia makro i ponownie włącza zdarzenia.

Eric Vaughn-Shobey
źródło
3

Wolę ten sposób, nie używając komórki, ale zakresu

    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
Javier Torón
źródło
To to samo, co jedna komórka. Możesz ustawić zakres jako jedną komórkę, zakres komórek ciągłych lub nawet komórki rozproszone (wszystkie oddzielone przecinkami).
Shai Alon
0

Mam komórkę połączoną z bazą danych online i często aktualizowaną. Chcę wyzwalać makro za każdym razem, gdy wartość komórki jest aktualizowana.

Uważam, że jest to podobne do zmiany wartości komórki przez program lub jakąkolwiek aktualizację danych zewnętrznych, ale powyższe przykłady jakoś nie działają dla mnie. Myślę, że problem polega na tym, że wewnętrzne zdarzenia programu Excel nie są wyzwalane, ale tak przypuszczam.

Wykonałem następujące czynności,

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
Juan Garcia
źródło
1
Z jakiegoś powodu nie mogę zmusić tego do działania. Kiedy mówię kodowi, aby działał w VBA, pojawia się wyskakujące menu i pyta mnie, czy chcę uruchomić makro zamiast uruchamiać je automatycznie?
David Van der Vieren