Programación de eventos en Excel – Segunda Nota

domingo, enero 27, 2008

En la primera nota sobre programación de eventos en Excel vimos la importancia y el poder de esta herramienta. En esta nota daremos algunos ejemplos, poniendo el énfasis al aspecto práctico. Pero empecemos por señalar algunas características importantes de los eventos.
Existe una jerarquía de eventos:


  • Eventos de la aplicación (Application events)


  • Eventos del cuaderno (Workbook events)


  • Eventos de la hoja (Worksheets events)


  • 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:

  • Workbook_SheetDeactivate

  • Workbook_SheetActivate

  • Workbook_NewSheet


  • 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:

    9 comments:

    Anónimo,  16 febrero, 2010 20:42  

    Hola Jorge,

    Quiero 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

    Jorge L. Dunkelman 17 febrero, 2010 12:27  

    Sergio,
    la 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.

    AFAA84 08 septiembre, 2010 17:39  

    Jorge, tengo el siguiente procedimiento:

    Sub 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

    Jorge L. Dunkelman 08 septiembre, 2010 18:05  

    Álvaro,
    no 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).

    Claudio,  26 enero, 2012 17:00  

    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.

    Rossy Vargas 22 abril, 2016 04:26  

    Hola 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.
    en espera de tu respuesta, Rossy Vargas

    Jorge Dunkelman 22 abril, 2016 06:44  

    Tienes que usar la propiedad Application.DisplayAlerts=False.
    Y por supuesto, volver a establecer el valor de la propiedad a True al finalizar la rutina.

    Rossy Vargas 04 junio, 2016 01:41  

    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.

    Jorge Dunkelman 05 junio, 2016 10:09  

    Fijate en el enlace "Ayuda" en la parte superior del blog.

    Publicar un comentario

    Google+ Followers

    Seguidores

    Google+ Badge

    Términos Legales

      © Blogger template On The Road by Ourblogtemplates.com 2009

    Back to TOP