ejecutar automáticamente una macro de Excel en un cambio de celda

91

¿Cómo puedo ejecutar automáticamente una macro de Excel cada vez que cambia un valor en una celda en particular?

En este momento, mi código de trabajo es:

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

donde "H5"es la celda particular que se está monitoreando y Macroes el nombre de la macro.

¿Existe una forma mejor?

namin
fuente
¿El UDF RunMacroWhenValueChanges en FormulaDesk satisface sus requisitos? formuladesk.com
Gareth Hayter

Respuestas:

107

Tu código se ve bastante bien.

Sin embargo, tenga cuidado porque su llamada a Range("H5")es un comando de acceso directo a Application.Range("H5"), que es equivalente a Application.ActiveSheet.Range("H5"). Esto podría estar bien, si los únicos cambios son cambios de usuario, que es el más típico, pero es posible que los valores de celda de la hoja de trabajo cambien cuando no es la hoja activa a través de cambios programáticos, por ejemplo, VBA.

Con esto en mente, utilizaría 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

O puede usar Me.Range("H5"), si el controlador de eventos está en la página de códigos de la hoja de trabajo en cuestión (generalmente lo está):

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

Espero que esto ayude...

Mike Rosenblum
fuente
4
¿Qué H5pasa si la celda se cambia de otra hoja, digamos que sheet2 la función anterior no funciona? por favor ayuda en esto.
dhpratik
2
Para cualquiera que venga aquí desde una búsqueda en Google, asegúrese de pegar este código en la hoja en vba, no en un módulo como lo hice yo. mira stackoverflow.com/questions/15337008/…
hammythepig
Application.ActiveSheet.Range ("H5"). ==> target.parent.range ("H5") es aún más seguro
Pierre
1
@WillEdiger Siempre que no especifica explícitamente una referencia de hoja, Excel asume el ActiveSheety siempre que no especifica explícitamente que es Excel con el que está trabajando, Excel asume Application.
Scott Marcus
1
Tenga en cuenta que, en un módulo de código de hoja de trabajo (que es donde Worksheet_Changedebe ubicarse un evento), un Rangeno calificado no seActiveSheet refiere por defecto a la hoja que contiene el código, sino que se refiere a ella. Por lo tanto, el código de esta respuesta es efectivamente el mismo que el código de la pregunta. (Nota: en 2009, cuando se escribió esta respuesta, puede haber sido diferente, pero estoy bastante seguro de que no lo fue).
YowE3K
7

Maneja el Worksheet_Changeevento o el Workbook_SheetChangeevento.

Los controladores de eventos toman un argumento "Objetivo como rango", por lo que puede verificar si el rango que está cambiando incluye la celda que le interesa.

Joe
fuente
Gracias, funciona. Compruebo la gama con, por ejemplo, Target.Address = Range("H5").Address. hay una manera mas facil?
namin
Una alternativa: Not (Intersect(Target, Range("H5")) Is Nothing) . ¿Es así como lo harías?
namin
2
El primer comentario ( Target.Address = Range("H5").Address) no funcionaría si su celda fuera solo una parte del rango cambiado. El segundo comentario aún adolece de los problemas descritos por Mike Rosenblum.
Ant
5

Pasé mucho tiempo investigando esto y aprendiendo cómo funciona todo, después de realmente estropear los desencadenantes del evento. Como había tanta información dispersa, decidí compartir todo lo que encontré que funciona en un solo lugar, paso a paso, de la siguiente manera:

1) Abra el Editor de VBA, en Proyecto VBA (YourWorkBookName.xlsm) abra el Objeto de Microsoft Excel y seleccione la Hoja a la que pertenecerá el evento de cambio.

2) La vista de código predeterminada es "General". En la lista desplegable en la parte superior central, seleccione "Hoja de trabajo".

3) Private Sub Worksheet_SelectionChange ya está allí como debería estar, déjelo en paz. Copie / pegue el código de Mike Rosenblum de arriba y cambie la referencia .Range a la celda para la que está esperando un cambio (B3, en mi caso). Sin embargo, no coloque su macro todavía (eliminé la palabra "Macro" después de "Entonces"):

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

o en la lista desplegable en la parte superior izquierda, seleccione "Cambiar" y en el espacio entre Private Sub y End Sub, pegue If Not Intersect(Target, Me.Range("H5")) Is Nothing Then

4) En la línea después de "Entonces", apague los eventos para que cuando llame a su macro, no active eventos e intente ejecutar este Worksheet_Change nuevamente en un ciclo interminable que bloquea Excel y / o estropea todo:

Application.EnableEvents = False

5) Llame a su macro

Call YourMacroName

6) Vuelva a activar los eventos para que se active el siguiente cambio (y todos los demás eventos):

Application.EnableEvents = True

7) Finalice el bloque If y el Sub:

    End If
End Sub

El código completo:

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

Esto elimina la activación / desactivación de eventos de los módulos, lo que crea problemas y simplemente permite que el cambio se active, apague eventos, ejecute su macro y vuelva a activar los eventos.

Eric Vaughn-Shobey
fuente
3

Prefiero esta forma, no usando una celda sino un rango

    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
fuente
Es lo mismo que una celda. Puede establecer un rango como una celda, rango de celdas continuas o incluso celdas dispersas (todas separadas por comas).
Shai Alon
0

Tengo una celda que está vinculada a la base de datos de existencias en línea y se actualiza con frecuencia. Quiero activar una macro cada vez que se actualiza el valor de la celda.

Creo que esto es similar al cambio de valor de celda por un programa o cualquier actualización de datos externos, pero los ejemplos anteriores de alguna manera no funcionan para mí. Creo que el problema es porque los eventos internos de Excel no se activan, pero esa es mi suposición.

Hice lo siguiente,

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
fuente
1
No puedo hacer que esto funcione por alguna razón. Cuando le digo al código que se ejecute en VBA, aparece un menú emergente y me pregunta si quiero ejecutar la macro en lugar de ejecutar la macro automáticamente.
David Van der Vieren