Trucos y Tretas en Excel VBA para Programadores
Trucos y Tretas en Excel VBA para Programadores
Trucos y Tretas en Excel VBA para Programadores
programadores
Comstar
(13/12/2011)17 comentarios
Este post no está hecho para novatos que no sepan nada del macros de Excel,
sino aquellos que saben algo de programación de Visual Basic. Si eres neófito en
macros de Excel en Visual Basic, deberías ver mi post Excel VBA y macros: Una
herramienta muy útil para trabajar hojas de cálculo (1). Me han de perdonar la
manera en que aparece el código, pero es un problema en la manera en que
aparece el código HTML para desplegar código con indentación en este sitio.
Especialmente en finanzas o en bolsa, pero también en negocios de todo tipo,
programar macros de Excel suele ser sumemante útil y por eso he querido deicar
este post a transmitir algunos trucos para ahorrarte tiempo. Cuando programamos
código para macros de Excel VBA a menudo nos encontramos con que los
detalles de cómo invocar tal o cual cosa de Excel termina siendo muy críptica y
debes navegar por foros, tutoriales o incontables páginas ininteligibles de
Microsoft que no te responden lo que andas buscando.
X
by Counterflix
Si sabes Visual Basic, lo más lógico es que para elaborar macros, trates de grabar
una macro primero, y luego empiezas a ver el código de muestra para ver cómo
hacer determinadas cosas. En este post se pretende proveer trucos de
programación en Excel VBA para efectuar tareas que no se pueden derivar del
código grabado en una macro en Excel. Estos trucos son el resultado de resolver
una serie de problemas que en su momento significaron un dolor de cabeza.
Range("A5:B8").Select
Como has visto, lo que está procesando la función Range() entre comillas es una
hilera de caracteres. Para efectos de escribir código, podemos usar esta expresión
equivalente:
Range(Cells(5,1),Cells(8,2)).Select
Convertir números en letras (pasar de la notación fila 5 columna 1 a "A5") suele
ser sumamente incómodo. Para ello he construido una función que hace el trabajo.
GetColumnLetter = ""
LL = (index - 1) Mod 26 + 65
If LL > 63 Then GetColumnLetter = Chr(LL)
If index > 26 Then
FL = Int((index - 1) / 26) + 64
GetColumnLetter = Chr(FL) & GetColumnLetter
End If
End Function
La función convierte el número en letras, en caracteres. Cabe anotar que sólo
sirve para llegar hasta columna ZZ, de modo que si se pasa de esa columna, esta
función no te servirá. Para llamar esta función con las mismas coordenadas (5,1) y
(8,2) harías algo como esto para convertir en hilera:
Si quieres que aparezca una ventana emergente con la cual puedas pedir al
usuario que seleccione un rango de datos, puedes usar el código que se muestra
a continuación. Lo que se hace es declarar un objeto de
tipo Range llamado celdasSeleccionadas. A ese objeto se le asigna el resultado
de la función Application.InputBox que despliega la ventana emergente que solicita
la información al usuario. Si el usuario no ingresa ningún rango, el valor que
tendrá el objeto es Nothing.
El comando On Error Resume Next indica que si ocurre un error, entonces ignore
el error y proceda conla siguiente instrucción. El comando On Error Goto 0 indica
que se cancela la detección de errores. El comando Msgbox despliega
información en una ventana emergente.
He aquí el código:
Como habrás notado en este código lo que se hace si el usuario digita un código
es desplegar el valor de la suma de todos los valores del rango usando la
función Application.WorksheetFunction.Sum, pero tú puedes hacer que haga algo
distinto.
Si quisieras obtener el valor contenido en el rango seleccionado puedes usar este
código.
MiVariable = celdasSeleccionadas.Value
Application.ScreenUpdating = False
Application.DisplayStatusBar = True
Application.StatusBar = "Iniciando..."
Y este código al final.
Application.ScreenUpdating = True
Application.StatusBar = "Ejecución terminada."
Application.ScreenUpdating se encarga de encender y apagar la actualización de
video. Application.DisplayStatusBar = True habilita la barra de estado que está en
la parte inferior de la ventana de Excel, y allí despliegas mensajes asignando una
hilera a Application.StatusBar. La idea de usar la barra de estado es que si la
ejecución de la macro tarda mucho, es bueno que el usuario sepa que la macro
está trabajando, y que no se ha quedado atascada.
No hay nada que fastidie más que tener un programa atascado frente a uno. Por
eso sería bueno que dentro de la macro agregues otros mensajes donde el
usuario pueda ver que la macro va caminando, pero si pones mensajes con
demasiada frecuencia eso ralentizará la ejecución, porque como dijimos, la
actualización de video consume mucho tiempo de la máquina.
X
by Counterflix
Esto es especialmente útil cuando vas a correr una macro que pasa de un libro de
Excel a otro o que se mueve mucho a lo largo de las páginas o celdas de manera
muy intensiva.
ActiveCell.SpecialCells(xlLastCell).Select
UltimaFila = ActiveCell.Row
UltimaColumna = ActiveCell.Column
Si buscas en Internet acerca de cómo obtener posición de la última celda,
encontrarás maneras muy diversas. Sin embargo, esta es la mejor que he
encontrado. Si agregas valores más allá de la última celda, el valor se
actualiza. El único problema es que si borras filas o columnas, este número no
cambiará, sino hasta que abras de nuevo el archivo de Excel. Sin embargo eso es
mejor que nada, y puedes verificar si encuentras celdas en blanco, así que eso no
debería ser problema.
Redim NombreDeArchivo(Workbooks.Count-1)
For i = 1 To Workbooks.Count
NombreDeArchivo(i-1) = Workbooks.Item(i).Name
Next i
El arreglo NombreDeArchivo almacenará los nombres de los archivos de Excel
que están abiertos en un momento dado.
Obtener la lista de páginas del libro de
Excel
Puedes usar el siguiente código.
Dim NombreDePagina()
Dim Cantidad as Long
Cantidad = Sheets.Count
redim NombreDePagina(n)
For i = 1 To Cantidad
NombreDePagina(i) = Sheets(i).Name
Next i
Los nombres se almacenan en el arreglo NombreDePagina.
Obtener los nombres de las gráficas
(charts) que hay en una página de Excel
Hay ocasiones en que ocupas buscar todas las gráficas contenidas en una página
de Excel. para ello te vales de ActiveSheet.ChartObjects
Dim NombreDeChart()
Redim NombreDeChart(ActiveSheet.ChartObjects.Count-1)
For i = 1 To ActiveSheet.ChartObjects.Count
NombreDeChart(i-1) = ActiveSheet.ChartObjects(i).Name
Next i
El arreglo NombreDeChart contendrá los nombres de las gráficas de la hoja de
Excel en que nos encontramos.
Obtener el nombre del libro de Excel en
que te encuentras actualmente
Existen algunas situaciones donde ocupas saber el nombre del libro de Excel en
que te encuentras actualmente.
LibroActual = ActiveWorkbook.Name
El nombre de la hoja actual será guardado en la variable LibroActual.
Cambiar de libro o de hoja
Si deseas pasarte a otro libro abierto u otra hoja, puedes usar el siguiente código.
Workbooks("MiLibro.xls").Activate
Sheets("Sheet1").Select
Este código hará que te pases al libro de Excel MiLibro.xls y a la página Sheet1 de
ese libro. Como ves, el valor entre comillas puede ser reemplazado por una
variable tipo String si lo deseas.
Cómo lidiar con libros de
Excel protegidos por password
If ActiveSheet.ProtectContents Then
ActiveSheet.Unprotect Password:="XYZ"
End If
Este código se encargará de eliminar la protección contra password. En este caso
el password es XYZ. Cuando trabajas con hojas protegidas con password,
obtendrás errores al tratar de acceder a material protegido y por eso debes
desproteger la hoja para trabajar en ella.
Si no aparece Microsoft Forms 2.0 Object Library en la lista, quizás quieras usar el
botón Browse para buscar el archivo FM20.DLL que se encuentra en la ubicación
en disco duro que se muestra en la imagen.
Ahora que ya configuramos todo, veamos el código.
Primero deberías declarar el objeto de portapapeles (en este caso le llamaremos
doClip)
Dim doClip As DataObject
Este sería el método para crear el portapapeles en memoria.
Sub CrearClipboard()
Set doClip = New DataObject
End Sub
Con este método puedes destruir el objeto portapapeles en memoria para liberar
espacio.
Sub DestruirClipboard()
Set doClip = Nothing
End Sub
ActiveSheet.PageSetup.Orientation = xlPortrait
ActiveSheet.PageSetup.Orientation = xlLandscape
ActiveSheet.PageSetup.Zoom = False
ActiveSheet.PageSetup.FitToPagesWide = 1
ActiveSheet.PageSetup.FitToPagesTall = 1
ActiveSheet.PageSetup.PrintArea = "A1:H25"
Como sabemos las propiedades son datos que nos describe una cualidad del
objeto, y como tal, tendremos que declarar variables a nivel de módulo. Estas
variables serán la que almacenarán la información de propiedades internamente
dentro del módulo. Son variables privadas, pues desde afuera no podrán ser
accedidas.
Private pNombre As String
Private pDireccion As String
Private pSalario As Double
Si desde afuera no podemos acceder a estas variables privadas, ¿cómo vamos a
leer o asignar valores al objeto? Usamos un tipo de procedimiento especial para
extraer (Property Get) o para insertar valores (Property Let) dentro del objeto.
Programa principal -> Property Let -> Variable interna del objeto
Variable interna del objeto -> Property Get -> Programa principal
Y estos procedimientos son públicos, lo cual significa que pueden accederse
desde afuera. Así, los procedimientos Property Let y Property Get tienen la única
función de insertar o extraer datos en las variables privadas que se manejan
dentro del objeto. ¿Por qué no simplemente hacer públicas las variables
internas? Porque estos procedimientos permiten incorporar funciones adicionales
de validación de información, o entregar sólo valores determinados a partir del
contenido de las variables internas. A estas variables internas le he agregado una
"p", de modo que pNombre es la variable interna para la propiedad Nombre.
''''''''''''''''''''''
' Propiedad Nombre
''''''''''''''''''''''
Public Property Get Nombre() As String
Nombre = pNombre
End Property
Public Property Let Nombre(Valor As String)
pNombre = Valor
End Property
''''''''''''''''''''''
' Propiedad Direccion
''''''''''''''''''''''
Public Property Get Direccion() As String
Direccion= pDireccion
End Property
Public Property Let Direccion(Valor As String)
pDireccion = Valor
End Property
''''''''''''''''''''''
' Propiedad Salario
''''''''''''''''''''''
Public Property Get Salario() As Double
Salario = pSalario
End Property
Public Property Let Salario(Valor As Double)
pSalario = Valor
End Property
Ahora bien, imaginemos que el usuario ingresa un número negativo. Tendrías que
validar que el salario sea un número positivo.
Sub CrearClipboard()
Set doClip = New DataObject
End Sub
Sub DestruirClipboard()
Set doClip = Nothing
End Sub
HojaDeMacros.NombreDeLibro = HojaDeMacros.NombreDeLibroActual
Transacciones.NombreDeLibro = "Transacciones.xlsx"
Reporte.NombreDeLibro = "Reporte_Anual.xlsx"
HojaDeMacros CargarArchivoTransacciones
Transacciones.CrearReporte Reporte.NombreDeLibro
Reporte.ImpuestoDeRenta = HojaDeMacros.ParámetroImpuestos
Reporte.ImprimirReporte
Transacciones.CerrarArchivo
HojaDeMacros.CerrarArchivo
Empresas