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í



Technorati Tags:

51 comentarios:

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

    ResponderBorrar
  2. 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.

    ResponderBorrar
  3. 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

    ResponderBorrar
  4. 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.

    ResponderBorrar
  5. 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.

    ResponderBorrar
  6. 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.

    ResponderBorrar
  7. 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..

    ResponderBorrar
  8. 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).

    ResponderBorrar
  9. Estimado Jorge, de antemano muchas gracias por sus útiles consejos me han ayudado bastante.. quisiera saber si hay alguna formar de hacer lo mismo pero con libros.. es decir crear una serie de libros o cuadernos a partir de una lista con nombres...

    ResponderBorrar
  10. Si, de manera similar. Para crear un cuaderno con VB usamos el método Add

    Workbooks.Add

    ResponderBorrar
  11. Estimado Jorge, he intentado hacer el cambio en el codigo para generar libros pero me bota error constantemente.. exactamente en que parte hay q poner el Workbooks.Add???

    ResponderBorrar
  12. Andres, lamentablemente el sitio donde estaban almacenados cerro y no tengo las copias a mano. Espero poder subirlas en los próximos días.

    ResponderBorrar
  13. Hola, yo tengo una consulta. Recién estoy aprendiendo a usar macros y he hecho este comando tan sencillo

    Sub Einführen()
    'Abrir hoja Projekte

    Projekte.Visible = True

    End Sub

    Y ya me sale el mensaje de Error 424. A que se puede deber este problema?

    Muchas Gracias

    ResponderBorrar
  14. Te falta indicar cuál es el objeto (la hoja en tu caso). El código tiene que ser

    Sheets("Projekte").Visible = True

    ResponderBorrar
  15. Hola buen día

    Necesito realizar esta misma macro, pero la unica observacion es que debe manterse un mismo formato cada vez que se genere

    ResponderBorrar
  16. Suponiendo que tengas un rango con los nombres de las hojas que quieres crear (lstMeses, por ejemplo)
    y una hoja que sea la plantilla (el formato, si es que entendí tu consulta), puedes usar esta macro

    Sub copy_sheets()
    Dim rngCell As Range

    For Each rngCell In Range("lstMeses")
    Sheets("plantilla").Copy after:=Sheets(Sheets.Count)
    ActiveSheet.Name = rngCell
    Next rngCell

    End Sub

    ResponderBorrar
  17. Gracias, yo tamben necesitaba esto último, le voy a poder scar mucho provecho! idolo Jorge!

    ResponderBorrar
  18. HOLA JORGE DUNKELMAN
    COMO PUEDO CREAR HOJAS CON EL MISMO FORMATO (SUPONGAMOS UNA PORTADA) A PARTIR DE UNA LISTA DE NOMBRE PERO CON DIFERENTE NOMBRE Y QUE LAS HOJAS SE LES NOMBRE COMO A MI LISTA.

    ResponderBorrar
  19. Eso es exactamente lo que se explica en la nota.

    ResponderBorrar
  20. Jorge como estas, oye al parece no se publico mi comentario pero ahí va de nuevo mi planteamiento.
    1.- TENGO UN LIBRO DE EXCEL CON 4 HOJAS LA HOJA1 ES MI BASE DE DATOS, HOJA2 ENCABEZADO (PARTE Y/O DATOS MODIFICABLES CADA SEMANA), HOJA3 UN CONSOLIDADO DE TRABAJADORES CON ID Y HOJA4 FORMATO DE CAPTURA DE TIEMPO EXTRA; ahora lo que necesito y tu macro me ha ayudado mucho, es que de acuerdo al numero de trabajadores capturados en la hoja3 me genere por cada uno la hoja4 ej. si capturo 3 en consolidado que me genere 3 hojas4 pero que se les asigne el nombre a la celda que contiene su id. ingrese tu macro y lo hace pero me crea una hoja en blanco con el nombre de los id seleccionados, modifique la macro para copiar la hoja4 y ahora copia la hoja4 pero les asigna el nombre hoja4 (2), hoja4 (3) y asi sucesivamente, como hacerle para que cambie por el nombre del rango seleccionado de id abajo pego mi código te agradezco eres excelente en tus explicaciones.

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


    On Error GoTo Cancelar
    Set Lista = Application.InputBox(prompt:="Selecciona el rango de FICHAS", _
    Title:="Lista de Fichas", Type:=8)
    Application.ScreenUpdating = False
    For iX = Lista.Count To 1 Step -1
    If checar_hoja(Lista(iX)) = False Then
    Sheets("04 Formato_Blanco").Copy after:=ActiveWorkbook.Sheets(Sheets.Count)
    'Sheets.Add.Name = Lista(iX)
    End If
    Next iX

    Sheets("03 Consolidado").Activate
    Sheets("03 Consolidado").Select
    Sheets("03 Consolidado").Move Before:=Sheets(3)
    Application.ScreenUpdating = True

    Cancelar:
    End Sub

    ResponderBorrar
  21. Orlando, me parece que tu problema reside en que por un lado estás generando una nueva hoja con

    Sheets("04 Formato_Blanco").Copy after

    y también generando otra hoja con

    Sheets.Add.Name = Lista(iX)

    Para cambiar el nombre te basta con Activesheet.Name=...

    Tengo un pedido: por favor, usa las mayúsculas y los signos de puntuación. Se hace muy difícil leer lo que escribes.

    ResponderBorrar
  22. Estimado, existe alguna macro u otra forma, de que pueda cambiar simultaneamente los nombres de las hojas en un libro de excel.

    Sucede que tengo varios libros con unas 300 hojas cada uno de registros diarios y deseo que cada libro tenga una hoja resumen en la que muestre los valores de esos registros. Por esto, necesito cambiar los nombres de las hojas, estas se encuentra en orden por lo tanto me serviria que la primera hoja se llame 001, la segunda hoja 002, la hoja número cien se llame 100, etc.

    Como verá es mucho trabajo hacerlo una por una, por lo que si me puede ayudar se lo agradecería, he buscado arduamente en la red y no he encontrado como hacerlo.

    ResponderBorrar
  23. Hola,

    puedes hacerlo con esta macro

    Sub renameSheets()
    Dim iX As Integer


    For iX = 1 To ActiveWorkbook.Sheets.Count
    Sheets(iX).Name = Format(iX, "000")
    Next iX

    End Sub

    Esta macro cambia los nombres de todas las hojas del cuaderno, por lo que te sugiero que hagas un backp del original antes de usarlo.

    ResponderBorrar
  24. Muchas gracias! si funciono!!!

    Te molesto nuevamente. Hay unos libros que tienen algunas hojas A-1, B-1, A-2, A-3, B-2, A-4, A-5, A-6, A-7, B-3, etc....

    Cómo podria hacer para que elimine automáticamente las hojas que empiezan con una determinada letra, como en el ejemplo que señale, eliminar todas las hojas que empiezan con letra B o eliminar todo excepto las hojas que empiezan con letra A.

    Gracias nuevamente!!!!

    ResponderBorrar
  25. Seba, no es molestia pero el lugar más indicado para ese tipo de consultas son los foros (de Excel y de Vba), ya que esto es un blog y los comentarios se deben referir al contenido y tener algún interés general, no partidular.
    En cuanto al código es sencilloÑ

    Sub eliminar_hojas()
    Dim sh As Worksheet

    Application.DisplayAlerts = False
    For Each sh In ActiveWorkbook.Worksheets
    If Left(sh.Name, 1) = "A" Then
    sh.Delete
    End If
    Next sh
    Application.DisplayAlerts = True

    End Sub

    ResponderBorrar
  26. Hola Jorge,

    Un favor quiero utilizar tu macro para crear hojas nueva, funciona perfectamente, pero además de crear las hojas yo necesito que se copien renglones a las nuevas hojas, quiero aprovechar el bucle agregando el comando de:
    ActiveCell.EntireRow.Copy Destination:=Sheets("x1").Range("a:65536").End(xlUp).Offset(1), pero termina la macro saliéndose de la macro.

    me podrias ayudar de Favor

    ResponderBorrar
  27. Hola, viendo tu código no me queda claro que es lo que querés hacer. Te sugiero que te pongas en contacto conmigo por mail privado (fijate en el enlace Ayuda, en la parte superior del blog).

    ResponderBorrar
  28. Hola. Me parece muy util el post. Si puede ayudarme estaría muy agradecida.

    Tengo una tabla en la cual hay una lista de personas y en cada columnas tienen sus datos. Me explico, en la columna 1 nombre, en la segunda numero de telefono, en la tercera direccion etc. Ya cree una hoja por cada persona y el nombre de cada hoja es la primera columna (nombre), pero quisiera copiar dentro de cada hoja los datos de cada persona. Es decir algo como una ficha independiente por cada persona que hay en la lista.


    Espero ser clara. Muchas gracias de Antemano.

    Saludos

    ResponderBorrar
  29. Estimada, se hace agregando código a la macro. Te sugiero que veas lo que pongo en el enlace Ayuda (en la parte superior del blog) y uqe me consultes por mail privado.

    ResponderBorrar
  30. Buenas, como habria que modificar este codigo para que al eliminar un elemento de la lista tambien elimine la hoja correspondiente? gracias por tu ayuda

    ResponderBorrar
  31. La idea es generar las hojas a partir de la lista, no manejar las hojas a partir de ella. Es mucho más sencillo eliminar la hoja manualmente.

    ResponderBorrar
  32. estimado, es posible que al agregar las hojas sean con hipervinculos, ingresando a cada hoja haciendo click en el nombre de la lista. saludos de antemano.

    ResponderBorrar
  33. Buenas Jorge, gracias por tu post me ha salvado, pero ahora tengo una duda, si quisiera predefinir el rango de las celdas por ejemplo (B3:B30) (sino me equivoco) por supuesto ignorando los espacios en blanco, y tambien que creara las nuevas hojas al final de la misma. Gracias de antemano!

    ResponderBorrar
  34. Ramón, para poner un rango predefinido usas la variable "Lista" con el rango, por ejemplo Lista=Range("B3:B30"). Si hay celdas en blanco tendrías que crear un loop que compruebe si al celda está en blanco y en ese caso ignorarla.

    ResponderBorrar
  35. Hola Jorge, favor una consulta:
    Tengo 3 hojas, la hoja1 es alimentada por la hoja2 y hoja3, un rango de filas de las hojas 1 y 2 alimentan a otro rango de filas de la hoja1 respectivamente.
    Lo que quiero es crear otras hojas con el mismo formato de la hoja2 u la hoja3 segun se requiera y que estas nuevas hojas alimenten a la hoja 1 en el siguiente rango de filas.

    ResponderBorrar
  36. Lo lamento pero no puedo responder a tu consulta. Es muy general, no se refiere a un problema específico. Por favor, fijate en los lineamentos que puuse en el enlace Ayuda (en la barra superior del blog).

    ResponderBorrar
  37. Hola Jorge!

    Gracias por compartir tu conocimiento! me a ayudado mucho basicamente tengo la misma pregunta que un usuario que ya comento que fue esta
    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.

    Estuvo haciendo pruebas para realizar alguna de estas soluciones pero me fue imposible. Me podrias ayudar como quedaria el codigo?

    ResponderBorrar
  38. ¿Te fijaste en mi comentario del 28/8/2013?

    ResponderBorrar
  39. Hola Jorge como se modificaria esta macro para que copie una hoja en particular y las renombre en base a una lista. saludos

    ResponderBorrar
  40. Para copiar una hoja en particular basta con Sheets("nombre").Copy, pero no entiendo la segunda parte. Si estás copiando una hoja sólo hay una hoja para renombrar.

    ResponderBorrar
  41. Hola Jorge perdón por no explicar bien lo que sucede es que tengo un libro con hoja a la llamo molde y otra que se llama lista y en la hoja lista contiene una lista de conceptos, me gustaría saber como modificar la macro para que copie la hoja molde y le asigne el nombre de conceptos de la lista, espero que me puedas orientar.
    saludos desde mexico

    ResponderBorrar
  42. Creo haber enetendido. Tendrias que usar un código como este

    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("molde").Copy after:=Sheets(Sheets.Count)
    ActiveSheet.Name = Lista(iX)
    Next iX

    Sheets(1).Select

    Application.ScreenUpdating = True

    Cancelar:
    End Sub

    ResponderBorrar
  43. Hola Jorge,

    encuentro este trabajo muy interesante. Gracias por tantas explicaciones.

    Mi formación en Macros es más que básica por lo que te pido ayuda para ver si me puedes echar una mano con lo siguiente:
    -tengo un listado de datos de herramientas en una sola hoja de MS Excel
    -entre cada herramienta hay una fila vacía para separarlas visualmente
    -el primer dato de cada herramienta es su nombre entre corchetes(Tool232)
    -los siguientes datos se repiten en todas las herramientas: diámetro, largo, velocidad, etc., hasta 44 datos
    -quería crear un documento de MS Excel en el que por cada herramienta se creara una hoja distinta y que el nombre de la hoja fuese el nombre de la herramienta (primer dato)

    ¿Crees que puede ser factible hacer con una Macro como la que propones en el título de esta entrada?

    Salu2,

    Jordi

    ResponderBorrar
  44. Reemplazando Step -1 en

    For iX = Lista.Count To 1 Step -1

    por Step -2

    ResponderBorrar
  45. Hola Jorge,

    probé lo que me dijiste en el post anterior pero no funcionó como yo deseaba que fuera. Es muy probable que no me explicara bien. A ver si ahora puedo hacerlo mejor.

    A continuación transcribo los datos de las dos primeras herramientas de la hoja de MS Excel que tengo:

    [Tool4]
    Caption=cecs 8mm
    Hint=cecs 8mm tipus 1
    Glyph=SACK_BO.BMP
    Identifier=0
    Desc=cecs 8mm tipus 1
    Tooltype=0
    Type=1
    TurnLeft=1
    TurnRight=1
    Length=72
    UseLength=35.3
    Diameter=8
    WearLength=0
    WearDiameter=0
    CorrectionX=0
    CorrectionY=0
    CorrectionZ=0
    OffsetC=0
    SecurityX=50
    SecurityY=0
    SecurityZ=10
    Raeumbreite=0
    Zustellung=0
    Schneiden=0
    Schnittspeed=0
    Speed=5000
    MinSpeed=0
    MaxSpeed=5000
    ZahnFeed=0
    Feed=3
    MinFeed=0.5
    MaxFeed=3
    Aufmass=0
    Overlap=0
    Schlichten=0
    Feed_Z=5
    F_Factor2=1
    PosDustControl=-2
    TurnTypes=
    EdgeAngle=0
    EdgeOverlap=0

    [Tool29]
    Caption=Recorta
    Hint=fresa 10mm tipus 10
    Glyph=SCHRIFT.bmp
    Identifier=0
    Desc=fresa 10mm tipus 10
    Tooltype=1
    Type=10
    TurnLeft=0
    TurnRight=1
    Length=120.9
    UseLength=33
    Diameter=10
    WearLength=0
    WearDiameter=0.5
    CorrectionX=0
    CorrectionY=0
    CorrectionZ=0
    OffsetC=0
    SecurityX=0
    SecurityY=52
    SecurityZ=2
    Raeumbreite=0
    Zustellung=0
    Schneiden=0
    Schnittspeed=0
    Speed=18000
    MinSpeed=0
    MaxSpeed=18000
    ZahnFeed=0
    Feed=3
    MinFeed=1
    MaxFeed=5
    Aufmass=0
    Overlap=0
    Schlichten=0
    Feed_Z=1
    F_Factor2=100
    PosDustControl=-1
    EdgeAngle=0
    EdgeOverlap=0
    EdgeOverlap=0

    -entre cada herramienta hay una fila vacía para separar las herramientas visualmente
    -el primer dato de cada herramienta es su nombre entre corchetes [Tool...]
    -los siguientes datos se repiten en todas las herramientas: diámetro, largo, velocidad, etc., hasta 44 datos

    Lo que me gustaría sería poder crear un documento de MS Excel en el que por cada herramienta se creara una hoja distinta y que el nombre de la hoja fuese el nombre de la herramienta [Tool...]

    A ver si es posible echarme una mano con esto. Me servirá para plantear un ejercicio de bdd para mis alumnos de FP. Gracias de antemano.

    Jordi



    ResponderBorrar
  46. Jordi, inentendible, por lo menos para mí, lo que me comentas. Te sugiero que te pongas en contacto conmigo por mail directo (fijaate en el enlace Ayuda, en la parte superior del blog).

    ResponderBorrar
  47. Excelente tu blog, en el 2019 lo estoy leyendo y veo que año tras año ayudas y resuelves dudas, te agradezco las atenciones. Espero con tu macro me ayude a realizar mi proyecto.

    ResponderBorrar

Nota: sólo los miembros de este blog pueden publicar comentarios.