Existe una jerarquía de eventos:
En el tope de la jerarquía están los eventos de la aplicación, luego los del cuaderno y finalmente los de la hoja. Cada objeto contiene sus propios eventos y los de de los objetos que se encuentran por debajo de él en la jerarquía. Por ejemplo el cuaderno tiene un evento Worksheet_Change que responde a cada cambio en una celda de la hoja. El cuaderno, a su vez, tiene un evento Workbook_SheetChange que responde a un cambio en una celda de cualquiera de las hojas del cuaderno. Ante un cambio en una celda, los eventos de los tres niveles entran en acción.
Ciertas acciones disparan más un evento, pero en cierto orden preestablecido. Por ejemplo, agregar una nueva hoja a un cuaderno (la acción) dispara una serie de eventos exactamente en este orden:
Un tercer punto, y el más importante del punto de vista práctico, es cómo evitar generar "loops" infinitos al programar eventos. Por ejemplo, consideremos este código
Private Sub Worksheet_Change(ByVal Target As Range)
Target.Value = Target.Value + 1
End Sub
Ante un cambio en la hoja, el valor de la celda activa (Target) aumenta en 1. Esta acción en sí misma constituye un cambio, lo que produce un evento Change que vuelva a agregar 1 al valor de la celda. Y así sucesivamente hasta el infinito (o hasta que pulsemos Ctrl+Break).
Si queremos ejecutar este código sin entrar en un "loop" infinito, debemos usar la propiedad EnableEvents de la Aplicación. En nuestro ejemplo:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Target.Value = Target.Value + 1
Application.EnableEvents = True
End Sub
Primero llevamos el valor de la propiedad a False, ejecutamos la (o las) línea y volvemos a poner el valor de EnableEvents a True. Esto es importante, ya que el valor de la propiedad no vuelve al valor de defecto (True) una vez concluido el código.
Ya hemos visto algunos ejemplos de eventos en la nota anterior y también en la nota sobre el numerador automático de facturas.
Ejemplos de eventos de cuaderno (Workbook events):
Seleccionar la celda A1 al activar una hoja
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
   [A1].Select
End Sub
Dado que usamos un evento a nivel de cuaderno, al seleccionar cualquier hoja, la celda A1 será la celda activa (excepto que seleccionemos una hoja de gráfico, en cuyo caso ocurrirá un error).
Al agregar una nueva hoja al cuaderno, le fecha y hora aparecen en la celda A1
Private Sub Workbook_NewSheet(ByVal Sh As Object)
If TypeName(Sh) = "Worksheet" Then
   [A1] = "La hoja fue agregada el " & Now
End If
End Sub
Ejemplos de eventos de hoja
En la nota anterior mostramos un ejemplo de Worksheet_Change. Otro ejemplo interesante de este evento es el siguiente que pone un fondo de color a la fila y la columna de la celda activa
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Cells.Interior.ColorIndex = xlNone
 With Target
   .EntireRow.Interior.ColorIndex = 35
   .EntireColumn.Interior.ColorIndex = 35
 End With
End Sub
Otros ejemplos pueden encontrarse en notas anteriores en este blog, como Limitar el área de trabajo en Excel o en cómo crear un menú en Excel.
Technorati Tags: MS Excel
Hola Jorge,
ResponderBorrarQuiero hacerte una consulta. ¿Qué evento sería necesario para actualizar automáticamente la fecha del sistema sólo en una hoja?
Tengo varias hojas donde quiero dejar registrada la fecha de la modificación en una celda concreta de cada hoja, por ejemplo A1, sólo de esa hoja y únicamente si ha habido algún cambio.
Lo que tengo es esto:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Range("A1").Select
ActiveCell.FormulaR1C1 = "=Today()"
Selection.NumberFormat = "dd/mmm/yyyy"
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
End Sub
Sé que no es el evento Workbook_BeforeSave el que tengo que utilizar pero con Workbook_SheetChange no lo he conseguido.
Gracias por tu ayuda y como siempre, por todo el Blog.
Un saludo,
Sergio
Sergio,
ResponderBorrarla explicación requiere más espacio del que es razonable para un comentario.
Estaré publicando una nota sobre el tema en lls próximos días.
Jorge, tengo el siguiente procedimiento:
ResponderBorrarSub Aviso()
Range("E10").Select
While ActiveCell.Value <> Empty
If IsNumeric(ActiveCell.Value) Then
If ActiveCell.Value > 2.8 Then MsgBox "Celulas muertas,
Aseo, Vuelta Vieja, Falta de Nutrientes, Prefil de Temperatura"
End If
ActiveCell.Offset(1, 0).Select
Wend
End Sub
El cual hace que cada vez que un parametro anotado en la columna E se salga de cierto rango me tire un aviso de los posibles por qué de esa falla, ahora mi duda es: ¿Cómo puedo hacer para que estos avisos salgan cada vez que ingreso el valor en cada celda, una opción es que se ejecute cada vez que apriete "enter"?
Me sería de mucha ayuda solucionar este problema.
Gracias
ATTE
Álvaro Aguayo Almendra
Álvaro,
ResponderBorrarno me queda clara tu consulta. EN primer lugar, para que la rutina trabaje como evento tenés que ponerla en un módulo de la hoja correspondiente y tenés que usar algunos de los eventos de la hoja, En tu caso el apropiado sería el evento Change.
Te sugiero que sigamos la consulta por mail privado. Por favor, lee lo que pongo en el enlace Ayuda (en la parte superior del blog).
Espectacular tu ayuda, me sirvió mucho con la programación luego de un refresh de un data table, ya que no encontré el evento en vba, así que apliqué el enable events. Gracias Master.
ResponderBorrarHola Jorge que evento tengo hacer y como para que no me marque mensaje de error cuando quiero hacer una consulta externa a una pagina y esta no esta disponible, ya que al enviarme msg de error se queda en espera de un aceptar y esto me impide que cuando ya puede conectarse a la pagina lo pueda hacer, ya que primero tengo que quitar el msg de error dando aceptar. El detalle que el archivo que hace esto esta en un servidor y va y toma datos de una pagina y los va guardando en un historia. me podras ayudar con esto.
ResponderBorraren espera de tu respuesta, Rossy Vargas
Tienes que usar la propiedad Application.DisplayAlerts=False.
ResponderBorrarY por supuesto, volver a establecer el valor de la propiedad a True al finalizar la rutina.
Hola Jorge.. no me funciono la propiedad Application.DisplayAlerts=False ya que Excel me sigue enviando msg cuando no puede refrescar una hoja con un vinculo a una pagina web. como te puedo mandar mas detalles de las pantallas para que me ayudes ?? he buscado mucho en internet y no encuentro una solución.
ResponderBorrarFijate en el enlace "Ayuda" en la parte superior del blog.
ResponderBorrar