martes, marzo 25, 2008

Generar hojas con nombre a partir de una lista

Una de las consultas que recibo con bastante frecuencia es cómo generar hojas en un cuaderno a partir de una lista.
Supongamos que tenemos una hoja en un cuaderno con la lista de los meses del año.



Queremos que una macro genere 12 hojas en el cuaderno, un para cada mes, y les ponga el nombre del mes



Esto podemos hacerlo con una macro bastante sencilla

Sub crear_hojas()
Dim Lista As Range
Dim iX As Long

Set Lista = Application.InputBox(prompt:="Señalar rango de la lista", _
Title:="Lista de nombres", Type:=8)


Application.ScreenUpdating = False

For iX = Lista.Count To 1 Step -1
Sheets.Add.Name = Lista(iX)
Next iX

Sheets(1).Select

Application.ScreenUpdating = True

End Sub


Al correr esta macro, se abre un diálogo donde ponemos el rango que contiene la lista (pueden ser meses, días de semana o cualquier otra cosa); al pulsar el botón Aceptar



se generarán las hojas en el orden de la lista.

Si queremos usar esta macro con cierta frecuencia o pasársela a un compañero del trabajo, descubriremos que tenemos que hacer algunas mejoras.
Por ejemplo, si en el diálogo de elegir rango pulsamos Cancelar, se abrirá el editor de Vba y veremos este mensaje de error



Para evitar esto usamos la sentencia On Error

Sub crear_hojas()
Dim Lista As Range
Dim iX As Long


On Error GoTo Cancelar

Set Lista = Application.InputBox(prompt:="Señalar rango de la lista", _
Title:="Lista de nombres", Type:=8)


Application.ScreenUpdating = False

For iX = Lista.Count To 1 Step -1
Sheets.Add.Name = Lista(iX)
Next iX

Sheets(1).Select

Application.ScreenUpdating = True

Cancelar:
End Sub

Otro problema puede generarse cuando ya existe en el cuaderno una hoja con uno de los nombres que aparecen en la lista. Por ejemplo, si la hoja Enero existe antes de correr la macro, obtenemos este resultado



Para evitar este problema tendremos que hacer algunas modificaciones a nuestra macro. Primero creamos una función para verificar si una hoja a crear ya existe


Function chequear_hoja(sheetName As String) As Boolean

Dim wkb As Worksheet

On Error Resume Next
Set wkb = Sheets(sheetName)
On Error GoTo 0

chequear_hoja = IIf(Not wkb Is Nothing, True, False)
End Function

Esta función da como resultado FALSE si la hoja no existe, y TRUE si la hoja ya existe en el cuaderno.
Lo que hacemos es usar esta función (adaptada de la propuesta por Colo) en nuestra macro para crear una condición. Si la hoja no existe, entonces creamos una nueva con el nombre correspondiente; de existir, pasamos a verificar el próximo nombre en la lista.

Sub crear_hojas2()
Dim Lista As Range
Dim iX As Long


On Error GoTo Cancelar

Set Lista = Application.InputBox(prompt:="Señalar rango de la lista", _
Title:="Lista de nombres", Type:=8)


Application.ScreenUpdating = False

For iX = Lista.Count To 1 Step -1
If chequear_hoja(Lista(iX)) = False Then
Sheets.Add.Name = Lista(iX)
End If
Next iX

Sheets("Hoja1").Activate

Application.ScreenUpdating = True

Cancelar:
End Sub

El cuaderno con las macros se puede descargar aquí

Actualización del 27.03.08: archivo con la macro corregida, la hoja con la lista queda en primer lugar

Technorati Tags:

9 comentarios:

Palel dijo...

Excelente...
¿Se podría conseguir que la hoja que contiene los nombres de las hojas a generar quedase en primer o último lugar?

Jorge L. Dunkelman dijo...

En la versión original es lo que hacía. Luego fui "mejorándola" y veo que ahora la hoja con la lista no queda al principio. Veré de corregir el código en cuanto tengo un poco de tiempo.

Direccion de Obra dijo...

Hay una aplicacion que siempre he estado buscando y es precisamente la inversa de la del ejemplo aqui desarrollado. ¿Como hacer para generar un listado de los nombres de las diferentes hojas que se han venido creando y quisiera resumirlas en una sola hoja para crear hipervinculos como un indice de contenido?
Gracias jorge

Jorge L. Dunkelman dijo...

El tema ha sido tratado en la nota sobre como crear un índice de las hojas del cuaderno.

Anónimo dijo...

Hola Jorge, como se puede hacer para que a partir de una hoja modelo, que contenga algunos cuadros que sean necesarios replicarlos para utilizar su ejemplo mes a mes.
Al momento de ejecutar la macro cada hoja nueva ya contenga los cuadros que tengo como modelo.

Jorge L. Dunkelman dijo...

Tendrías que modificar la macro de manera que:

- copie los cuadros de la hoja modelo a la hoja nueva, es decir, agregar un sentencia que realice el copiado de los rangos con los cuadros

o

- en lugar de crear hojas nuevas, copiar la hoja modelo y cambiar el nombre. Este me parece la opción más práctica.

Anónimo dijo...

Buenisimo lo tuyo. Siempre uso tus enseñanzas. En este caso me vino perfecto, le hice un retoque que me resulta muy util: las hojas nuevas salen ya con el nombre en A1.

Anónimo dijo...

Mi estimado, estoy trabajando en una variación y me gustaria saber si tiene alguna idea de la solución; tengo una hoja que alimenta una serie de plantillas, la idea es que en la hoja 1 se ingresan los datos y segun el número de filas que tengan información se van creando plantillas a partir de la que esta creada en la hoja 2 es decir a tantas filas llenas en la hoja 1 se creen tantas hojas con información y un formato preestablecido..

Jorge L. Dunkelman dijo...

Si te refieres a ir creando las hojas a medida que se ingresan los nombres, tienes que programar un evento (puede fijarte en esta nota).