TOP
VBA-Lección 9. Procedimientos y funciones
En cualquier lenguaje de programación existen conceptos tales como procedimientos y funciones. También se incluyeron en el lenguaje de programación incorporado VBA para Excel.
Una función es una rutina que devuelve un resultado. Una llamada de función es una expresión y se puede usar en otras expresiones o en el lado derecho de una instrucción de asignación (indicada en VBA como "Función");
Un procedimiento es cualquier rutina que no es una función. Marcado en VBA como "Sub" (de la palabra "subrutina").
Procedimientos (Public - Private)
En este punto, todos los procedimientos que hemos creado son del tipo Public, lo que significa que son accesibles desde cualquier módulo.
- Sub example()
-
-
- Public Sub example()
Sub example()
'Idéntico a:
Public Sub example()
Para que el procedimiento esté disponible solo en un determinado módulo, se utiliza la palabra clave Private:
Private Sub example()
Ejecutar un procedimiento desde la mitad de otro procedimiento
Para ejecutar un procedimiento desde dentro de otro procedimiento, simplemente ingrese su nombre.
Aquí hay un ejemplo muy simple de esto:
- Private Sub warning()
- MsgBox "Caution !!!"
- End Sub
-
- Sub macro_test()
- If Range("A1") = "" Then
- warning
- End If
-
- End Sub
Private Sub warning()
MsgBox "Caution !!!"
End Sub
Sub macro_test()
If Range("A1") = "" Then
warning '=> ejecutar procedimiento "warning"
End If
'etc...
End Sub
Argumentos
Los argumentos permiten utilizar valores de un procedimiento en un subprocedimiento (recuerde que, por defecto, las variables solo están disponibles desde el procedimiento en el que fueron declaradas).
- Private Sub warning(var_text As String)
- MsgBox "Caution : " & var_text & " !"
- End Sub
-
- Sub macro_test()
- If Range("A1") = "" Then
- warning "celda vacia"
- ElseIf Not IsNumeric(Range("A1")) Then
- warning "valor no numérico"
- End If
- End Sub
Private Sub warning(var_text As String)
MsgBox "Caution : " & var_text & " !"
End Sub
Sub macro_test()
If Range("A1") = "" Then
warning "celda vacia"
ElseIf Not IsNumeric(Range("A1")) Then
warning "valor no numérico"
End If
End Sub
Se ha agregado un argumento al procedimiento "warning", en este caso es una variable "var_text" de tipo "String" (cinta):
- Private Sub warning(var_text As String)
Private Sub warning(var_text As String)
Esta rutina toma un argumento, por lo que debemos poner un valor después de "warning" para ejecutarla:
warning "celda vacia"
Cuando queremos escribir varios argumentos, entonces deben estar separados por comas.
Argumentos opcionales
De forma predeterminada, si el procedimiento tiene argumentos, se deben proporcionar y, si no se proporcionan, el procedimiento no se ejecutará.
Se puede agregar un argumento opcional después de uno obligatorio, usando la palabra clave Optional. Ejemplo:
- Private Sub dialog_boxes(last_name As String, Optional first_name, Optional age)
Private Sub dialog_boxes(last_name As String, Optional first_name, Optional age)
Este procedimiento ahora se puede ejecutar con o sin un argumento opcional, como aquí:
-
- dialog_boxes last_name1
-
-
- dialog_boxes last_name1, first_name1
-
-
- dialog_boxes last_name1, , age1
-
-
- dialog_boxes last_name1, first_name1, age1
'Ejemplo 1: mostrar el apellido:
dialog_boxes last_name1
'Ejemplo 2: mostramos el apellido y el nombre:
dialog_boxes last_name1, first_name1
'Ejemplo 3: mostrar el apellido y la edad:
dialog_boxes last_name1, , age1
'Ejemplo 4: mostrar apellido, nombre y edad:
dialog_boxes last_name1, first_name1, age1
Los argumentos deben introducirse en el orden correcto.
Para probar si un argumento opcional está presente en un procedimiento, usamos la función IsMissing. Esta función solo es compatible con algunos tipos de funciones (del tipo Variant) y esto es fundamental porque no se declaró el tipo de los argumentos opcionales (tipo no declarado = Variant).
Aquí hay un ejemplo que usa los dos fragmentos de código discutidos anteriormente:
- Sub macro_test()
-
- Dim last_name1 As String, first_name1 As String, age1 As Integer
-
- last_name1 = Range("A1")
- first_name1 = Range("B1")
- age1 = Range("C1")
-
-
- dialog_boxes last_name1
-
-
- dialog_boxes last_name1, first_name1
-
-
- dialog_boxes last_name1, , age1
-
-
- dialog_boxes last_name1, first_name1, age1
-
- End Sub
-
- Private Sub dialog_boxes(last_name As String, Optional first_name, Optional age)
-
- If IsMissing(age) Then
-
- If IsMissing(first_name) Then
-
- MsgBox last_name
- Else
- MsgBox last_name & " " & first_name
- End If
-
- Else
-
- If IsMissing(first_name) Then
-
- MsgBox last_name & ", " & age & "años"
- Else
- MsgBox last_name & " " & first_name & ", " & age & "años"
- End If
-
- End If
-
- End Sub
Sub macro_test()
Dim last_name1 As String, first_name1 As String, age1 As Integer
last_name1 = Range("A1")
first_name1 = Range("B1")
age1 = Range("C1")
'Ejemplo 1: mostrar el apellido:
dialog_boxes last_name1
'Ejemplo 2: mostramos el apellido y el nombre:
dialog_boxes last_name1, first_name1
'Ejemplo 3: mostrar el apellido y la edad:
dialog_boxes last_name1, , age1
'Ejemplo 4: mostrar apellido, nombre y edad:
dialog_boxes last_name1, first_name1, age1
End Sub
Private Sub dialog_boxes(last_name As String, Optional first_name, Optional age)
If IsMissing(age) Then 'Si falta la variable edad...
If IsMissing(first_name) Then 'Si falta la variable first_name, entonces
'solo se mostrará el apellido
MsgBox last_name
Else 'De lo contrario, se mostrarán el apellido y el nombre.
MsgBox last_name & " " & first_name
End If
Else 'Si la variable edad está presente...
If IsMissing(first_name) Then 'Si falta la variable first_name, entonces
'se mostrará el apellido y la edad
MsgBox last_name & ", " & age & "años"
Else 'De lo contrario, se mostrarán el apellido, el nombre y la edad.
MsgBox last_name & " " & first_name & ", " & age & "años"
End If
End If
End Sub
Ver imagen de abajo (ejemplo 1):
ByRef - ByVal
De forma predeterminada, los argumentos son del tipo ByRef, lo que significa que si se pasa una variable como argumento, también se pasará una referencia a ella. En otras palabras, si otro subprocedimiento ha cambiado una variable, también se cambiará en el procedimiento externo que llama a ese subprocedimiento.
Ejemplo:
- Sub macro_test()
- Dim var_number As Integer
-
- var_number = 30
- calcul_square var_number
-
- MsgBox var_number
- End Sub
-
- Private Sub calcul_square(ByRef var_value As Integer)
-
- var_value = var_value * var_value
- End Sub
Sub macro_test()
Dim var_number As Integer
var_number = 30
calcul_square var_number
MsgBox var_number
End Sub
Private Sub calcul_square(ByRef var_value As Integer) 'ByRef es opcional
'(es el valor predeterminado)
var_value = var_value * var_value
End Sub
Para que quede claro, a continuación se muestra un ejemplo de lo que sucederá si se inicia la ejecución de la macro:
- var_number = 30
-
-
- calcul_square var_number
-
-
- Private Sub calcul_square(ByRef var_value As Integer)
-
-
-
- var_value = var_value * var_value
-
-
- End Sub
-
-
- MsgBox var_number
-
var_number = 30
'El valor inicial de la variable "var_number" es 30
calcul_square var_number
'El subprocedimiento se ejecuta con "var_number" como argumento
Private Sub calcul_square(ByRef var_value As Integer)
'La variable "var_value" sirve hasta cierto punto para un acceso rápido a la variable "var_number",
'lo que significa que si se cambia la variable "var_value", la variable "var_number" también cambiará
'(y no tienen que tener el mismo nombre)
var_value = var_value * var_value
'Se cambia el valor de la variable "var_value" (y por lo tanto "var_number" también se cambia al mismo tiempo)
End Sub
'Fin del subprocedimiento
MsgBox var_number
'La variable "var_number" se ha cambiado, por lo que ahora se mostrará 900 en el cuadro de diálogo.
El segundo método es usar ByVal.
A diferencia de ByRef, que pasa una referencia (etiqueta), ByVal pasa un valor, lo que significa que el valor pasado como argumento no ha sido modificado.
A continuación puedes ver cómo funciona el código anterior y ByVal:
- var_number = 30
-
-
- calcul_square var_number
-
-
- Private Sub calcul_square(ByVal var_value As Integer)
-
-
- var_value = var_value * var_value
-
-
- End Sub
-
-
- MsgBox var_number
-
var_number = 30
'El valor inicial de la variable "var_number" es 30
calcul_square var_number
'El subprocedimiento se ejecuta con "var_number" como argumento
Private Sub calcul_square(ByVal var_value As Integer)
'La variable "var_value" copia el valor de la variable "var_number" (las segundas variables no están relacionadas)
var_value = var_value * var_value
'Se ha cambiado el valor de la variable "var_value"
End Sub
'Fin del subprocedimiento (en este ejemplo, el subprocedimiento no tiene ningún efecto sobre nada)
MsgBox var_number
'La variable "var_number" no se ha cambiado, por lo que se mostrará 30 en el cuadro de diálogo
Lo que debe recordar: use ByVal cuando no se deba cambiar la variable.
Funciones
La principal diferencia entre un procedimiento y una función es que una función devuelve un valor.
Aquí hay un ejemplo simple:
- Function square(var_number)
- square = var_number ^ 2
- End Function
-
- Sub macro_test()
- Dim result As Double
- result = square(9.876)
- MsgBox result
- End Sub
Function square(var_number)
square = var_number ^ 2 'La función "cuadrado" devuelve el valor de "raíz cuadrada"
End Function
Sub macro_test()
Dim result As Double
result = square(9.876) 'A la variable resultado se le asigna el valor que fue calculado por la función
MsgBox result 'Se muestra el resultado (en este caso el cuadrado de 9.876)
End Sub
La función se puede usar en una hoja de trabajo como cualquier otra función en Excel.
Por ejemplo, para obtener el cuadrado del valor ingresado en la celda A1: