La mayoría de las veces, cuando ejecutamos un macro, lo hacemos de forma consciente, previa solicitud, es decir, bajo petición, ya sea pulsando un botón que tiene asociado el macro, o bien desde los menús seleccionando el macro de la lista de macros disponibles.
Otras veces, ejecutamos una macro, cuando cambia cualquier celda de cualquier hoja de cálculo del libro (a través del evento SheetChange), o bien cuando cambia cualquier celda de una hoja de cálculo determinada (a través del evento Change).
Pero, ¿podemos ejecutar una macro, no solo a petición, o cuando cambia cualquier celda de la hoja, sino también cuando cambia una celda específica de la hoja de cálculo?. Es decir, ¿podemos ejecutar un macro solo si cambia una celda (o varias), impidiendo que se ejecute el macro, si se cambian otras celdas de la hoja?. Pues la respuesta, como debéis intuir, es sí. Por supuesto que se puede ejecutar un macro bajo esas condiciones.
Lo primero que tenemos que pensar es que tiene que cambiar "algo", para que se ejecute el macro. Ese "algo" será una celda de la hoja de cálculo. Y más concretamente esa celda será una que habremos elegido nosotros, es decir, no valdrá que cambie cualquier celda, sino solo la elegida por nosotros.
Para ver como funciona este macro, lo haremos con un ejemplo. Supongamos que tenemos la Hoja1 de un libro de excel, y queremos que nos muestre un mensaje (Msgbox), cada vez que alguien cambie el dato que tenemos en la celda B5. Por tanto, el mensaje solo se mostrará si alguien cambia la celda B5, y no se mostrará nada, si se cambia la celda B4, la B6, la N55, LA J677, o cualquier otra que no sea expresamente la celda B5.
Tenemos que pensar que lo primero que debe ocurrir es que debe cambiar algo, por tanto, debe producirse el evento Change (si es que lo aplicamos a la Hoja1 en concreto). Por tanto, deberemos poner algo dentro de la Hoja1, es decir, algo como esto:
Lo que irá dentro de ese evento Change, es un condicional, que evaluará si cambia o no la celda B5, para que en ese caso, se dispare el mensaje. La propia Microsoft nos propone hacer algo como esto (los comentarios del código son míos, no de Microsoft):
Private Sub Worksheet_Change(ByVal Target As Range)
'pasamos a una variable, la celda o celdas
'que queremos evaluar si cambian o no
datos = "B5"
'como estamos dentro del evento "Change", algo tiene
'que estar cambiando... Pues bien, si la celda activa
'es la misma que la celda que hemos puesto en
'la variable llamada "datos", entonces
'que muestre un mensaje (recordemos que una doble
'negación es una afirmación)
If Not Application.Intersect(ActiveCell, Range(datos)) Is Nothing Then
'mostramos un mensaje
MsgBox ("Oyeeeee, sé que estás cambiando la celda " & datos & ".")
End If
End Sub
|
Y efectivamente, ese código funciona correctamente si cambiamos la celda B5 y pulsamos intro. Pero ¿qué ocurre si en lugar de pulsar intro, una vez editada la celda B5, pulsamos cualquier tecla de desplazamiento?. Pues que no funciona la
solución propuesta por Microsoft. ¿Y qué pasa si editamos el contenido de la celda B4 (la que está encima de B5), y en lugar de pulsar intro, una vez cambiado el valor de esa celda, pulsamos la telcla de desplazamiento hacia abajo?. Pues que se ejecuta el macro, con lo cual, estamos en las mismas, ...no funciona correctamente el macro.
Es decir, la solución propuesta por Microsoft funciona, siempre y cuando utilicemos la tecla intro (la tecla enter), para editar (para cambiar) el contenido de las celdas, pero los usuarios medianamente avezados, suelen utilizar las teclas de desplazamiento, en lugar de la tecla intro, para finalizar la edición de las celdas, ...y en ese caso, la solución de Microsoft puede no funcionar (no siempre falla, evidentemente, pues para que falle, la celda activa debe ser la celda B5, o cualquier de sus celdas contiguas vertical u horizontalmente).
Para solucionar ese contratiempo, podemos cambiar la solución propuesta por Microsoft, y utilizar esta otra que es parecidísima:
Private Sub Worksheet_Change(ByVal Target As Range)
'pasamos a una variable, la celda o celdas
'que queremos evaluar si cambian o no
datos = "B5"
'como estamos dentro del evento "Change", algo tiene
'que estar cambiando... Pues bien, si la celda activa
'es la misma que la celda que hemos puesto en
'la variable llamada "datos", entonces
'que muestre un mensaje (recordemos que una doble
'negación es una afirmación)
If Not Application.Intersect(Target, Range(datos)) Is Nothing Then
'mostramos un mensaje
MsgBox ("Oyeeeee, sé que estás cambiando la celda " & datos & ".")
End If
End Sub
|
Si observamos bien, la diferencia está en que Microsoft nos propone incluir
Activecell, y en esta nueva versión lo cambiamos, y ponemos
Target.
Si quisiéramos mostrar el mensaje al cambiar varias celdas contiguas, por ejemplo cuando cambiamos B5, B6, o B7, entonces haríamos esto:
Private Sub Worksheet_Change(ByVal Target As Range)
'pasamos a una variable, la celda o celdas
'que queremos evaluar si cambian o no
datos = "B5:B7"
'como estamos dentro del evento "Change", algo tiene
'que estar cambiando... Pues bien, si la celda activa
'es la misma que la celda que hemos puesto en
'la variable llamada "datos", entonces
'que muestre un mensaje (recordemos que una doble
'negación es una afirmación)
If Not Application.Intersect(Target, Range(datos)) Is Nothing Then
'mostramos un mensaje
MsgBox ("Oyeeeee, sé que estás cambiando alguna celda del rango " & datos & ".")
End If
End Sub
|
Si por el contrario, lo que queremos es mostrar el mensaje al evaluar un rango discontinuo de celdas, por ejemplo las celdas B5, B7, y B12, entonces haríamos esto:
Private Sub Worksheet_Change(ByVal Target As Range)
'pasamos a una variable, la celda o celdas
'que queremos evaluar si cambian o no
datos1 = "B5"
datos2 = "B7"
datos3 = "B12"
'como estamos dentro del evento "Change", algo tiene
'que estar cambiando... Pues bien, si la celda activa
'es la misma que la celda que hemos puesto en
'la variable llamada "datos", entonces
'que muestre un mensaje (recordemos que una doble
'negación es una afirmación)
If Not Application.Intersect(Target, Range(datos1)) Is Nothing Or _
Not Application.Intersect(Target, Range(datos2)) Is Nothing Or _
Not Application.Intersect(Target, Range(datos3)) Is Nothing Then
'mostramos un mensaje
MsgBox ("Oyeeeee, sé que estás cambiando alguna de estas celdas " & _
datos1 & ", " & datos2 & ", " & datos3 & ".")
End If
End Sub
|
Bueno, como veis, es bastante sencillo. El truco consiste en incluir dentro del evento Change de la hoja que queramos evaluar (aunque también puede ser en el libro), un condicional que evalúe si cambia determinada celda, y que será la que dispare el macro. En nuestro caso, en lugar de disparar un macro, lo que hemos hecho, ha sido mostrar un mensaje (mediante un Msgbox), aunque el mensaje, bien podría haber estado en un macro aparte, y de igual forma podríamos haberlo ejecutado. Tan solo habríamos tenido que llamar al macro desde el condicional del
Intersect.