En esta página irán apareciendo ejemplos del uso de eventos en Excel, aunque lo normal es que los eventos se usen en situaciones muy específicas, lo que hace difícil que el código de un evento que sirve a alguien pueda interesar a otras personas. Sin embargo, sí puede servir como ejemplo para situaciones similares y para ver las posibilidades que ofrecen los eventos.
El siguiente código, situado en el módulo del libro (ThisWorkbook) se encargaría de preguntar el número de copias a imprimir de Hoja1 y pondría en la celda D1, empezando a numerar a partir del valor de dicha celda.
Private Sub Workbook_BeforePrint(Cancel As Boolean) If ActiveSheet.Name <> "Hoja1" Then Exit Sub Dim intNúmCopias As Integer, n As Integer intNúmCopias = Application.InputBox(prompt:="Número de copias a imprimir:", Type:=1) For n = 1 To intNúmCopias ActiveSheet.PrintOut copies:=1 ActiveSheet.Range("D1").Value = ActiveSheet.Range("D1").Value + 1 Next n End Sub
Normalmente esto se usa en libros situados en una unidad de red, si se necesita conocer qué usuario accedió al libro y a qué hora se produjo el acceso.
En el módulo del libro iría este código:
Private Sub Workbook_Open() ActualizarRegistro End Sub
Y en un módulo vacío iría lo siguiente:
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long Sub ActualizarRegistro() Dim strUserName As String, Cadena As String * 46 Dim intNúmArchivo As Integer, lngNúmRegistro As Long strUserName = String(100, Chr$(0)) GetUserName strUserName, 100 strUserName = Left$(strUserName, InStr(strUserName, Chr$(0)) - 1) intNúmArchivo = FreeFile(1) Cadena = Left(Left(strUserName, 25) & String(25, " "), 25) & Now() & Chr(13) & Chr(10) Open "P:\accesos.log" For Random Shared As intNúmArchivo Len = 46 lngNúmRegistro = (LOF(intNúmArchivo) / 46) + 1 Put intNúmArchivo, lngNúmRegistro, Cadena Close intNúmArchivo End Sub
(en este código, la unidad de red es P:, y el fichero Accesos.log se situaría en su directorio raíz)
El problema con este tipo de controles es que se pueden burlar si el usuario tiene establecida la seguridad de Excel en media o alta y decide no autorizar la ejecución de macros, aunque por otra parte lo habitual es que estos libros tengan funcionalidades que sólo se pueden obtener ejecutando código, por lo que no tendría demasiado sentido abrirlos sin autorizar su ejecución.
El siguiente código, situado en el módulo de una hoja se encargaría de poner en el rango B2:B10 la hora en que se ha editado por última vez la celda de la misma fila en la columna A:
Private Sub Worksheet_Change(ByVal Target As Range) If Application.Intersect(Target, Target.Parent.Range("A2:A10")) Is Nothing Then Exit Sub Application.EnableEvents = False Target.Offset(, 1) = Now Application.EnableEvents = True End Sub
En este ejemplo se necesita que al escribir un nombre de libro en la columna A de una hoja se actualizen las columnas B,C,D y E con el contenido de las mismas columnas de la Hoja1 del libro cuyo nombre se ha escrito.
Private Sub Worksheet_Change(ByVal Target As Range) If Target.Column <> 1 Then Exit Sub Dim n As Byte If Dir("C:\prueba\" & Target.Value & ".xls") = "" Then Exit Sub Application.EnableEvents = False For n = 2 To 5 'Número de columnas que se pondrán del libro seleccionado ActiveSheet.Cells(Target.Row, n).FormulaR1C1 = "='C:\prueba\[" & Target.Value & ".xls" & "]" & "Hoja1'!R" & Target.Row & "C" & n Next n Application.EnableEvents = True End Sub
En este caso, los ficheros están situados en C:\Pruebas
Si el libro cuyo nombre se ha tecleado no existe, el código no hace nada.
Suponiendo que en Hoja2 hubiera una tabla dinámica cuyo origen de datos estuvieran en Hoja1, si se necesita que al modificar cualquier celda de dicho origen de datos se actualice automáticamente la tabla dinámica se podría usar el siguiente código:
Private Sub Worksheet_Change(ByVal Target As Range)
With Worksheets("Hoja2").PivotTables(1).PivotCache
'Hoja donde se encuentre la tabla dinámica
If Not Intersect(Target,
Range(Application.ConvertFormula(Replace(.SourceData, "F", "R"), xlR1C1, xlA1)))
Is Nothing Then .Refresh
End With
End Sub
Para poder hacer uso de los eventos de los objetos QueryTable es necesario crear un objeto con eventos usando un módulo de clase.
En el ejemplo disponible aquí se puede ver cómo usar estos eventos, en el caso de una consulta web, para actualizarla en una hoja protegida.
El ejemplo no funcionará si se abre desde Internet Explorer. Para que funcione, hay que guardarlo en el disco duro (pero el código sí puede examinarse abriendo el libro desde IE).
Los eventos para los gráficos situados en hojas de gráfico están habilitados por defecto en Excel, pero los de los gráficos incrustados en una hoja de cálculo no lo están, por lo que para poder usarlos es necesario crear un objeto con eventos usando un módulo de clase.
En el ejemplo disponible aquí hay dos gráficos iguales, con la única diferencia de que uno se encuentra incrustado en Hoja1 y el otro en su propia hoja de gráfico.
El ejercicio consiste en usar el evento Calculate de ambos gráficos para que cada una de sus barras cambie de color dependiendo de su valor, en función de cuatro tramos que están definidos en el código VBA.
El ejemplo no funcionará bien si se abre desde Internet Explorer. Para que funcione, hay que guardarlo en el disco duro (pero el código sí puede examinarse abriendo el libro desde IE).
Si se necesita introducir y editar fechas, a veces puede convenir usar el objeto Calendar, el cual puede incrustarse en una hoja de cálculo desde Insertar->Objeto.
Vamos a suponer que interesa que se muestre el calendario siempre que se edite una celda situada en la columna A de una hoja. El código siguiente (que habría que situar en el módulo de la hoja haciendo click derecho sobre su etiqueta->Ver código), se encargaría del trabajo:
Private Sub Calendar1_Click()
ActiveCell = Calendar1
End Sub
Private Sub Calendar1_GotFocus()
If IsDate(ActiveCell) Then Calendar1 = ActiveCell
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
With Calendar1
.Visible = Target.Column = 1
If Target.Column = 1 And IsDate(Format(ActiveCell, "yyyy-mm-dd")) Then Calendar1 = ActiveCell Else .Value = Int(Now())
End With
End Sub
Con el código anterior, el calendario aparecería siempre en la posición en que se hubiera situado manualmente. Si se necesitara que, por ejemplo, el calendario apareciera justo a la derecha de la celda que se está editando, se podría usar:
Si el control Calendar no estuviera disponible, en el siguiente enlace hay información (en inglés, me temo):
http://www.microsoft.com/officedev/tips/regactx.htm
Si no se desea proteger una hoja pero sí evitar que se pueda modificar cualquier celda que afecte al resultado de una dada (en el ejemplo, A6), se podría usar el siguiente código, que tendría que situarse en el módulo de la hoja:
Private Sub Worksheet_Change(ByVal Target As Range) On Error GoTo Captura If Not Application.Intersect([$A$6], Target.Dependents.Cells) Is Nothing Then With Application .EnableEvents = False .Undo .EnableEvents = True MsgBox prompt:="La celda " & Target.Address & " no se puede modificar porque afecta al resultado de la celda $A$6.", Buttons:=vbOKOnly + vbInformation End With End If Exit Sub Captura: If Err.Number = 1004 Then Exit Sub Else MsgBox Err.Number & " - " & Err.Description End Sub
Si sólo se deseara impedir que se pudiesen modificar las celdas con precedencia directa sobre A6, habría que cambiar
Target.Dependents.Cells
por
Target.DirectDependents.Cells