VBA en Excel: ejecutar el código de una hoja desde un módulo
En Excel con VBA es muy común tener un procedimiento escrito dentro del módulo de una hoja (por ejemplo, Hoja1) y necesitar ejecutarlo desde un módulo estándar, desde un botón o desde otra macro. En este post te muestro cómo hacerlo con un ejemplo real, por qué a veces aparece el error "No se ha definido Sub o Function" y qué buenas prácticas conviene seguir.
El caso: el código está en la Hoja1
En la siguiente imagen se ve el editor de VBA (se abre con Alt + F11). El procedimiento VALOR está escrito en el módulo de la Hoja1:
Ese procedimiento recorre las filas 20 a 34 y, según el valor de la columna I, copia el dato en la columna H o en la G. Este es el mismo código escrito de forma un poco más ordenada:
' Código en el módulo de la Hoja1
Public Sub VALOR()
Dim i As Long
For i = 20 To 34
If Me.Range("I" & i).Value >= 0.7 Then
Me.Range("H" & i).Value = Me.Range("I" & i).Value
Me.Range("G" & i).Value = ""
Else
Me.Range("G" & i).Value = Me.Range("I" & i).Value
Me.Range("H" & i).Value = ""
End If
Next i
End Sub
Dentro del módulo de una hoja, Me hace referencia a esa misma hoja. Así el código siempre trabaja sobre la Hoja1, aunque en ese momento el usuario esté viendo otra hoja.
La solución: llamar al procedimiento desde un módulo
En un módulo estándar (Insertar → Módulo) basta con escribir el nombre de la hoja, un punto y el nombre del procedimiento:
' Código en Módulo3
Sub ACTUALIZARGRAFICAS()
Call Hoja1.VALOR
End Sub
Al ejecutar ACTUALIZARGRAFICAS (con F5, desde un botón o desde Programador → Macros), VBA busca el objeto Hoja1 y ejecuta su procedimiento VALOR.
Paso a paso
- Abre el editor de VBA con Alt + F11.
- En el Explorador de proyectos, haz doble clic sobre la hoja donde está el código y verifica que el procedimiento sea Public Sub (si no dice nada, por defecto también es público).
- Inserta un módulo: menú Insertar → Módulo.
- Escribe una macro que llame a
Hoja1.NombreDelProcedimiento. - Guarda el libro como .xlsm (libro habilitado para macros); si lo guardas como .xlsx, las macros se pierden.
Hoja1 no es lo mismo que "el nombre de la pestaña"
Este es el detalle que más confunde. Cada hoja tiene dos nombres:
- Nombre de código (CodeName): el que aparece primero en el Explorador de proyectos, por ejemplo
Hoja1. Es el que usamos enCall Hoja1.VALOR. No cambia aunque el usuario renombre la pestaña. - Nombre de la pestaña: el que aparece entre paréntesis, por ejemplo "(COMITE DE VIGILANCIA)". Es el que se usa con
Worksheets("COMITE DE VIGILANCIA").
Por eso es más robusto llamar por el nombre de código. Si tu Excel está en inglés, el nombre de código por defecto será Sheet1 en lugar de Hoja1. Puedes cambiarlo en la ventana Propiedades (F4), en el campo (Name).
Otras formas de ejecutar el código de una hoja
' 1) Llamada directa por nombre de código (la recomendada)
Call Hoja1.VALOR
' 2) Sin la palabra Call (equivalente)
Hoja1.VALOR
' 3) Usando el nombre de la pestaña
Worksheets("COMITE DE VIGILANCIA").VALOR
' 4) Con Application.Run, útil si el nombre viene en una variable
Application.Run "Hoja1.VALOR"
La opción 3 depende de que nadie cambie el nombre de la pestaña. La opción 4 es útil cuando el nombre de la macro se arma dinámicamente, pero si escribes mal el nombre el error solo aparece al ejecutar.
Buena práctica: ¿código en la hoja o en un módulo?
El módulo de una hoja está pensado para los eventos de esa hoja: Worksheet_Change, Worksheet_Activate, Worksheet_SelectionChange, etc. La lógica que quieres reutilizar desde varios lugares suele quedar mejor en un módulo estándar, recibiendo la hoja como parámetro:
' En un módulo estándar
Public Sub ClasificarValores(ws As Worksheet, filaIni As Long, filaFin As Long)
Dim i As Long
For i = filaIni To filaFin
If ws.Range("I" & i).Value >= 0.7 Then
ws.Range("H" & i).Value = ws.Range("I" & i).Value
ws.Range("G" & i).ClearContents
Else
ws.Range("G" & i).Value = ws.Range("I" & i).Value
ws.Range("H" & i).ClearContents
End If
Next i
End Sub
Sub Ejemplo()
ClasificarValores Hoja1, 20, 34
End Sub
Así el mismo procedimiento funciona para cualquier hoja y rango, y el módulo de la hoja queda solo con sus eventos.
Errores comunes
- "No se ha definido Sub o Function": escribiste solo
Call VALOR. Como el procedimiento está en una hoja, debes anteponer el objeto:Call Hoja1.VALOR. - "Se requiere un objeto": el nombre de código no es
Hoja1(puede serSheet1u otro). Revísalo en el Explorador de proyectos. - El procedimiento no aparece en la lista de macros: los procedimientos de las hojas sí aparecen, pero con el prefijo de la hoja; los
Private Subno aparecen. - Las macros no se ejecutan: el libro está guardado como .xlsx o las macros están deshabilitadas en el Centro de confianza.
Preguntas frecuentes
¿Puedo llamar a un procedimiento de una hoja que está en otro libro?
Sí, con Application.Run "'Otro libro.xlsm'!Hoja1.VALOR", siempre que ese libro esté abierto.
¿Puedo pasarle parámetros?
Sí. Si el procedimiento es Public Sub VALOR(filaFin As Long), lo llamas con Hoja1.VALOR 34.
¿Funciona igual en Excel 365?
Sí. Esta forma de llamar procedimientos funciona igual en las versiones de escritorio de Excel para Windows, incluida Microsoft 365.
Si te interesa automatizar tareas con VBA, mira también la macro para crear y borrar carpetas desde Excel, y si estás empezando con fórmulas, el post BUSCARV vs BUSCARX en Excel.
Conclusión
Para ejecutar desde un módulo el código que está en una hoja, usa Call Hoja1.NombreProcedimiento, verifica el nombre de código de la hoja y guarda el libro como .xlsm. Y como buena práctica, deja en las hojas solo los eventos y lleva la lógica reutilizable a módulos estándar.


Comentarios