17/04/2013 - La versión final está disponible.
Después de un largo proceso de preparación, acabo de completar el primer borrador de la primer guía de la serie "Cajas de Herramientas Excel JLD".
Esta primer guía desarrolla en forma sistemática y didáctica las técnicas para crear listas desplegables en Excel.
Los temas tratados van desde la creación de listas desplegables sencillas con validación de datos hasta el uso de Vba (macros) para la creación de listas desplegables dependientes con autocompletado de valores. Cada tema va acompañado por archivos con los ejemplos.
El índice de los temas tratados
Como en el pasado, recurro a mis lectores en búsqueda de editores/correctores. Los primeros cinco lectores que me envíen su dirección de mail (por favor, no ponerla en un comentario; enviarlo a la dirección que aparece en el enlace Ayuda), recibirán como recompensa la versión final en forma gratuita.
Desde ya muchas gracias.
Sugerencias y ayuda para Excel en español. Ejemplos de funciones y fórmulas, gráficos, automatización con Vba, Power Query y PowerPivot
martes, abril 02, 2013
jueves, marzo 28, 2013
Listas desplegables dependientes múltiples con Vba
Esta es una extensión de mi nota anterior sobre listas desplegables dependientes. Uno de mis lectores pregunta
Podemos extender nuestro modelo a casi todo número de niveles de dependencia introduciendo ciertos cambios. A los efectos del ejemplo extenderemos el modelo a tres niveles: continente – país – ciudad.
El modelo extendido puede descargarse aquí.
Como en el modelo de la nota anterior, creamos una lista de continentes a partir de la base de datos, usando el objeto Collection e insertando la lista de valores únicos en un rango auxiliar. Este rango es el origen de la lista desplegable creada con Validación de datos
La lista la creamos con este código
Sub insertarContinentes()
Dim arrListaContinentes As New Collection, continente
Dim iR As Long
On Error Resume Next
Range("lstContinentes").ClearContents
On Error GoTo 0
With Sheets("lista")
On Error Resume Next
For Each continente In Range("tblContinentes")
arrListaContinentes.Add continente, continente
Next continente
On Error GoTo 0
For iR = 1 To arrListaContinentes.Count
.Cells(iR + 1, 6) = arrListaContinentes(iR)
Next iR
End With
End Sub
Para que esta lista esté permanentemente actualizada, programamos un evento Worksheet_Deactivate de la hoja que contiene los datos (la hoja “lista”)
Private Sub Worksheet_Deactivate()
Call insertarContinentes
End Sub
Para crear la lista de los países correspondientes a los continentes, creamos un código similar al de los continentes, pero con una condición para que los países agregados a la colección sean los que corresponden al continente
Sub insertarPaises()
Dim rngCell As Range
Dim arrListaPaises As New Collection, pais
Dim iR As Long
On Error Resume Next
Range("lstPais").ClearContents
On Error GoTo 0
With Sheets("lista")
On Error Resume Next
For Each pais In Range("tblPaises")
If pais.Offset(0, -1).Value = Range("Continente_Elegido") Then
arrListaPaises.Add pais, pais
End If
Next pais
On Error GoTo 0
For iR = 1 To arrListaPaises.Count
.Cells(iR + 1, 8) = arrListaPaises(iR)
Next iR
End With
End Sub
El código de la rutina para generar la lista de ciudades queda igual a la del modelo anterior.
El último toque es agregar código en el evento Worksheet_Change de la hoja “reporte” para disparar las rutinas que crean las listas de países y ciudades
Private Sub Worksheet_Change(ByVal Target As Range)
If Union(Target, Range("Continente_Elegido")).Address = Range("Continente_Elegido").Address Then
Range("Pais_elegido").ClearContents
Range("Ciudad_Elegida").ClearContents
Call insertarPaises
End If
If Union(Target, Range("Pais_elegido")).Address = Range("Pais_elegido").Address Then
Range("Ciudad_Elegida").ClearContents
Call insertarCiudades
End If
End Sub
Por supuesto, hemos creados nombres definidos que se refieren a los rangos del modelo.
Como se haría para que tenga más niveles, por ejemplo 5 listas desplegables dependientes
Podemos extender nuestro modelo a casi todo número de niveles de dependencia introduciendo ciertos cambios. A los efectos del ejemplo extenderemos el modelo a tres niveles: continente – país – ciudad.
El modelo extendido puede descargarse aquí.
Como en el modelo de la nota anterior, creamos una lista de continentes a partir de la base de datos, usando el objeto Collection e insertando la lista de valores únicos en un rango auxiliar. Este rango es el origen de la lista desplegable creada con Validación de datos
La lista la creamos con este código
Sub insertarContinentes()
Dim arrListaContinentes As New Collection, continente
Dim iR As Long
On Error Resume Next
Range("lstContinentes").ClearContents
On Error GoTo 0
With Sheets("lista")
On Error Resume Next
For Each continente In Range("tblContinentes")
arrListaContinentes.Add continente, continente
Next continente
On Error GoTo 0
For iR = 1 To arrListaContinentes.Count
.Cells(iR + 1, 6) = arrListaContinentes(iR)
Next iR
End With
End Sub
Para que esta lista esté permanentemente actualizada, programamos un evento Worksheet_Deactivate de la hoja que contiene los datos (la hoja “lista”)
Private Sub Worksheet_Deactivate()
Call insertarContinentes
End Sub
Para crear la lista de los países correspondientes a los continentes, creamos un código similar al de los continentes, pero con una condición para que los países agregados a la colección sean los que corresponden al continente
Sub insertarPaises()
Dim rngCell As Range
Dim arrListaPaises As New Collection, pais
Dim iR As Long
On Error Resume Next
Range("lstPais").ClearContents
On Error GoTo 0
With Sheets("lista")
On Error Resume Next
For Each pais In Range("tblPaises")
If pais.Offset(0, -1).Value = Range("Continente_Elegido") Then
arrListaPaises.Add pais, pais
End If
Next pais
On Error GoTo 0
For iR = 1 To arrListaPaises.Count
.Cells(iR + 1, 8) = arrListaPaises(iR)
Next iR
End With
End Sub
El código de la rutina para generar la lista de ciudades queda igual a la del modelo anterior.
El último toque es agregar código en el evento Worksheet_Change de la hoja “reporte” para disparar las rutinas que crean las listas de países y ciudades
Private Sub Worksheet_Change(ByVal Target As Range)
If Union(Target, Range("Continente_Elegido")).Address = Range("Continente_Elegido").Address Then
Range("Pais_elegido").ClearContents
Range("Ciudad_Elegida").ClearContents
Call insertarPaises
End If
If Union(Target, Range("Pais_elegido")).Address = Range("Pais_elegido").Address Then
Range("Ciudad_Elegida").ClearContents
Call insertarCiudades
End If
End Sub
Por supuesto, hemos creados nombres definidos que se refieren a los rangos del modelo.
Todo sobre listas desplegables en Excel, técnicas avanzadas y descarga gratuita de ejemplos en la Caja de Herramientas Excel - Listas Desplegables de JLD. Ver la nota o ir a la página de descarga de la guía.
viernes, marzo 22, 2013
Listas desplegables dependientes – otra versión (Vba)
Uno de los temas más populares en este blog es el de las listas desplegables, en particular el de las listas desplegables dependientes (ver esta nota y también esta otra).
Las técnicas que mostrado hasta ahora se basan en la creación de nombres definidos que se refieren a rangos dinámicos. La ventaja de esta técnica es que no requiere conocimientos de Vba (el lenguaje de programación de Excel); todo lo hacemos usando rangos en hojas y fórmulas. La desventaja es que a medida que nuestro modelo va creciendo en variables debemos agregar nombres y definir nuevos rangos dinámicos.
Por ejemplo, en la nota mencionada manejamos nombres de ciudades para cinco países
Para lo que debemos crear seis nombres definidos. Si decidimos agregar otro país, debemos crear el nombre correspondiente. Esto nos limita si creamos un modelo que debe ser usado por un usuario común o si no queremos que nuestros usuarios modifiquen el modelo.
La solución es usar Vba para crear las listas que alimentan las listas desplegables.
A los efectos supongamos que queremos crear un modelo donde el usuario elige un país, de acuerdo a su elección una lista desplegable le muestra sólo las ciudades de ese país y en una tercera celda se muestra la población de esa ciudad
El modelo funciona de la siguiente manera:
En la hoja “lista” tenemos una tabla de Países-Ciudades-Población
En la columna E de la hoja ponemos los países que aparecen en la tabla Países-Ciudades-Población. Esta lista debe contener valores únicos, cosa que podemos hacer con Filtro Avanzado. Pero en este modelo usaremos un poco de código Vba con el objeto Collection
Sub insertarPaises()
Dim arrListaPaises As New Collection, pais
Dim iR As Long
On Error Resume Next
Range("lstPais").ClearContents
On Error GoTo 0
With Sheets("lista")
On Error Resume Next
For Each pais In Range("tblPaises")
arrListaPaises.Add pais, pais
Next pais
On Error GoTo 0
For iR = 1 To arrListaPaises.Count
.Cells(iR + 1, 5) = arrListaPaises(iR)
Next iR
End With
End Sub
No entraremos en los detalles técnicos, pero podemos ver que usamos un rango definido por el nombre “tblPaises”. Este es un rango dinámico que se refiere al rango en uso en la columna A de la hoja “lista”
tblPaises=lista!$A$2:INDICE(lista!$A:$A,CONTARA(lista!$A:$A))
Con este código creamos una nueva “colección” de valores (países) haciendo un rizo a lo largo del rango de los países. Como no se puede agregar un valor ya existente en la colección, usamos On Error Resume Next para que el código no se interrumpa al tratar de agregar un país existente. De esta manera obtenemos una lista de valores únicos. Luego la copiamos al rango lstPais con el loop For…Next
La celda D3 de la hoja “reporte” contiene una validación de datos con la opción Lista usando el nombre definido “lstPais”
El nombre definido “lstPais” se refiere a al fórmula =DESREF(lista!$E$1,1,0,CONTARA(lista!$E:$E)-1,1), que es el rango donde hemos puesto los países con el código mostrado anteriormente.
Para que este rango se actualice automáticamente cuando agregamos o quitamos países y ciudades en la tabla, usamos un evento Deactivate de la hoja “lista”. De esta manera, cuando el usuario vuelve a la hoja reporte luego de efectuar un cambio en la tabla, el evento dispara el código de actualización
En la celda D5 de la hoja “reporte” creamos una lista desplegable con la opción Lista y el nombre
“lstCiudad”
El nombre “lstCiudad” se refiere al rango usado en la columna G que contiene las ciudades del país elegido
Para agregar los nombres de las ciudades del país elegido a este rango, usamos este código
Sub insertarCiudades()
Dim lCounter As Long
Dim rngCel As Range
On Error Resume Next
Range("lstCiudad").ClearContents
On Error GoTo 0
lCounter = 2
With Sheets("lista")
For Each rngCel In Range("tblPaises")
If rngCel.Value = Range("Pais_Elegido").Value Then
.Cells(lCounter, 7) = rngCel.Offset(0, 1)
lCounter = lCounter + 1
End If
Next rngCel
End With
End Sub
En este código usamos nuevamente el rango “tblPaises” para comparar el país elegido (la celda D3 de la hoja “reporte” a la que le hemos definido el nomber “Pais_Elegido”); cuando el país de la tabla Paises-Ciudades-Población coincide con el país elegido, la ciudad es agregada al rango de la columna G.
Este código es disparado por un evento Worksheet_Change de la hoja “reporte”, de manera que cuando se produce un cambio en D3, se dispara el código y la lista de ciudades es actualizada.
El código del evento es el siguiente:
Private Sub Worksheet_Change(ByVal Target As Range)
If Union(Target, Range("Pais_Elegido")).Address = Range("Pais_Elegido").Address Then
Range("Ciudad_Elegida").ClearContents
Call insertarCiudades
End If
End Sub
Finalmente, en la celda D7 usamos una función BUSCARV combinada con SI.ERROR para extraer la población de la ciudad elegida.
El archivo con el ejemplo se puede descargar aquí.
Actualización: nota que explica cómo crear un modelo ampliado (continente-país-ciudad)
Las técnicas que mostrado hasta ahora se basan en la creación de nombres definidos que se refieren a rangos dinámicos. La ventaja de esta técnica es que no requiere conocimientos de Vba (el lenguaje de programación de Excel); todo lo hacemos usando rangos en hojas y fórmulas. La desventaja es que a medida que nuestro modelo va creciendo en variables debemos agregar nombres y definir nuevos rangos dinámicos.
Por ejemplo, en la nota mencionada manejamos nombres de ciudades para cinco países
Para lo que debemos crear seis nombres definidos. Si decidimos agregar otro país, debemos crear el nombre correspondiente. Esto nos limita si creamos un modelo que debe ser usado por un usuario común o si no queremos que nuestros usuarios modifiquen el modelo.
La solución es usar Vba para crear las listas que alimentan las listas desplegables.
A los efectos supongamos que queremos crear un modelo donde el usuario elige un país, de acuerdo a su elección una lista desplegable le muestra sólo las ciudades de ese país y en una tercera celda se muestra la población de esa ciudad
El modelo funciona de la siguiente manera:
En la hoja “lista” tenemos una tabla de Países-Ciudades-Población
En la columna E de la hoja ponemos los países que aparecen en la tabla Países-Ciudades-Población. Esta lista debe contener valores únicos, cosa que podemos hacer con Filtro Avanzado. Pero en este modelo usaremos un poco de código Vba con el objeto Collection
Sub insertarPaises()
Dim arrListaPaises As New Collection, pais
Dim iR As Long
On Error Resume Next
Range("lstPais").ClearContents
On Error GoTo 0
With Sheets("lista")
On Error Resume Next
For Each pais In Range("tblPaises")
arrListaPaises.Add pais, pais
Next pais
On Error GoTo 0
For iR = 1 To arrListaPaises.Count
.Cells(iR + 1, 5) = arrListaPaises(iR)
Next iR
End With
End Sub
No entraremos en los detalles técnicos, pero podemos ver que usamos un rango definido por el nombre “tblPaises”. Este es un rango dinámico que se refiere al rango en uso en la columna A de la hoja “lista”
tblPaises=lista!$A$2:INDICE(lista!$A:$A,CONTARA(lista!$A:$A))
Con este código creamos una nueva “colección” de valores (países) haciendo un rizo a lo largo del rango de los países. Como no se puede agregar un valor ya existente en la colección, usamos On Error Resume Next para que el código no se interrumpa al tratar de agregar un país existente. De esta manera obtenemos una lista de valores únicos. Luego la copiamos al rango lstPais con el loop For…Next
La celda D3 de la hoja “reporte” contiene una validación de datos con la opción Lista usando el nombre definido “lstPais”
El nombre definido “lstPais” se refiere a al fórmula =DESREF(lista!$E$1,1,0,CONTARA(lista!$E:$E)-1,1), que es el rango donde hemos puesto los países con el código mostrado anteriormente.
Para que este rango se actualice automáticamente cuando agregamos o quitamos países y ciudades en la tabla, usamos un evento Deactivate de la hoja “lista”. De esta manera, cuando el usuario vuelve a la hoja reporte luego de efectuar un cambio en la tabla, el evento dispara el código de actualización
En la celda D5 de la hoja “reporte” creamos una lista desplegable con la opción Lista y el nombre
“lstCiudad”
El nombre “lstCiudad” se refiere al rango usado en la columna G que contiene las ciudades del país elegido
Para agregar los nombres de las ciudades del país elegido a este rango, usamos este código
Sub insertarCiudades()
Dim lCounter As Long
Dim rngCel As Range
On Error Resume Next
Range("lstCiudad").ClearContents
On Error GoTo 0
lCounter = 2
With Sheets("lista")
For Each rngCel In Range("tblPaises")
If rngCel.Value = Range("Pais_Elegido").Value Then
.Cells(lCounter, 7) = rngCel.Offset(0, 1)
lCounter = lCounter + 1
End If
Next rngCel
End With
End Sub
En este código usamos nuevamente el rango “tblPaises” para comparar el país elegido (la celda D3 de la hoja “reporte” a la que le hemos definido el nomber “Pais_Elegido”); cuando el país de la tabla Paises-Ciudades-Población coincide con el país elegido, la ciudad es agregada al rango de la columna G.
Este código es disparado por un evento Worksheet_Change de la hoja “reporte”, de manera que cuando se produce un cambio en D3, se dispara el código y la lista de ciudades es actualizada.
El código del evento es el siguiente:
Private Sub Worksheet_Change(ByVal Target As Range)
If Union(Target, Range("Pais_Elegido")).Address = Range("Pais_Elegido").Address Then
Range("Ciudad_Elegida").ClearContents
Call insertarCiudades
End If
End Sub
Finalmente, en la celda D7 usamos una función BUSCARV combinada con SI.ERROR para extraer la población de la ciudad elegida.
El archivo con el ejemplo se puede descargar aquí.
Actualización: nota que explica cómo crear un modelo ampliado (continente-país-ciudad)
Todo sobre listas desplegables en Excel, técnicas avanzadas y descarga gratuita de ejemplos en la Caja de Herramientas Excel - Listas Desplegables de JLD. Ver la nota o ir a la página de descarga de la guía.
Suscribirse a:
Entradas (Atom)