Crear un formulario de usuario
Los formularios de usuario son cuadros de diálogo personalizados que se utilizan para recoger datos de entrada del usuario al inicio de una macro. El Constructor de Formularios de Usuario incluido en Code VBA crea automáticamente Formularios de Usuario. Los formularios de usuario generados tienen un código de validación de entrada añadido para asegurar que toda la entrada requerida es del tipo correcto. Esto hará que la macro sea más fiable. Tener los controles y el código de validación generados ahorra mucho tiempo que tendría que gastar para crear el formulario de usuario manualmente. El formulario de usuario puede modificarse tanto para hacer el diseño visualmente más atractivo moviendo y redimensionando los controles. Además se puede extender el código vba del userform para cumplir requisitos adicionales.
Uso del constructor de UserForm
El Constructor de UserForm se inicia desde el menú Código VBA:
Alt-CDUB | Menú: Code VBA " Dialog " UserForm " |

En el UserForm Builder especificará
- UserForm Name: dar un nombre al formulario que sea una abreviatura de los datos que se van a introducir. En el ejemplo el nombre era 'Pedido
-
La rejilla de controles es el área en la que se especifican los controles que se desean incluir en el formulario de usuario que se está creando.
Cada control se especifica en una línea separada con propiedades:
- Nombre: se utilizará como etiqueta para el control de entrada.
- Tipo de datos: si el usuario introduce un valor de tipo incorrecto en el control, al pulsar el botón Aceptar aparece un mensaje al usuario indicando que el valor de ese campo es incorrecto y devuelve el cursor a ese campo para que el usuario lo corrija.
- Tipo de control: permite especificar qué tipo de control se prefiere. Un booleano (sí/no) puede representarse de forma fácil de usar mediante un control
- Obligatorio: si el usuario no introduce un valor en el control, al pulsar el botón Aceptar aparece un mensaje para el usuario indicando que falta un valor para ese campo y coloca el cursor en ese campo.
- Seleccionar nombres...: abre una cuadro de entrada de selección de rango para permitirle seleccionar uno o más nombres de su hoja Excel. Esto es útil si su cuadro de diálogo se crea para rellenar un formulario o tabla de Excel existente.
- Create: crea el UserForm - imagen de abajo - e inserta el código para iniciar el userform.

UserForm Código VBA
Además del objeto UserForm, el constructor también añade tres piezas de código:
- Código para abrir / mostrar el formulario de usuario
- Tipo definido por el usuario
- Validación de la entrada del usuario
Código para abrir / mostrar el formulario de usuario
Asumiendo que el cursor estaba dentro del procedimiento Sub Demo
, después de presionar OK en el UserForm Builder el procedimiento se vería como se muestra a continuación.
Sub Demo()
Dim udtOrder As Order
With udtOrder
.Client = ""
.EntryDate = Date
.Product = ""
.Attention = True
End With
ufmOrder.FillList "cboProduct", Array("v1", "v2", "v3")
ufmOrder.SetValues udtOrder
ufmOrder.Show
If Not ufmOrder.IsCancelled Then
ufmOrder.GetValues udtOrder
''continue process after OK here
With udtOrder
End With
End If
Unload ufmOrder
End Sub
Para obtener una interfaz limpia se utiliza un Tipo Definido por el Usuario que comprende los controles de datos con sus definiciones de tipo en el formulario de usuario.
Se puede alterar el código entre el primer With
y End With
para cambiar los valores iniciales o por defecto.
El paso de los valores al formulario se realiza en el método SetValues
El procedimiento FillList se utiliza para pasar una matriz de valores al cuadro de lista Producto. Los valores del array ("v1",...) son sólo un ejemplo que tendrás que adaptar.
El método Show
es la forma estándar de abrir el UserForm.
El usuario puede pulsar OK o Cancelar el diálogo. Esto se determina comprobando la propiedad .IsCancelled
.
Si el usuario pulsó OK la macro continuará utilizando los datos que el usuario proporcionó en el formulario de usuario.
Para ello añadirá su propio código de proceso entre el segundo With
y End With
.
Tipo definido por el usuario para una interfaz limpia
El tipo definido por el usuario generado proporciona una interfaz limpia entre la macro y el formulario de usuario. Si el procedimiento desde el que llama al formulario de usuario está en un módulo estándar, el tipo definido por el usuario se colocará allí. Si no, se colocará en un módulo llamado 'modTypes'. En el ejemplo, la declaración del tipo tiene este aspecto:
Public Type Order
Client As String
EntryDate As Date
Product As String
Attention As Boolean
End Type
Validación de UserForm y otro código
Dentro del UserForm generado hay todavía bastante código que se utiliza para:
- Manejo de OK y Cancelar
- Pasar datos al formulario de usuario
- Validación de los datos introducidos
Manejo de OK y Cancelar
El siguiente código muestra el manejo de Ok y Cancelar. El botón Cerrar también se maneja adecuadamente como Cancelar sin necesidad de código adicional.
La variable pública IsCancelled
se utiliza para comunicar a la macro de llamada si el usuario ha pulsado Ok o Cancelar.
Public IsCancelled As Boolean
Private Sub UserForm_Initialize()
IsCancelled = True
End Sub
Private Sub btnCancel_Click()
Me.Hide
End Sub
Private Sub btnOk_Click()
If IsInputOk Then
IsCancelled = False
Me.Hide
End If
End Sub
Pasar datos al formulario de usuario
Los datos se pasan al formulario de usuario y se obtienen de él mediante SetValues
y GetValues
respectivamente.
Ambos utilizan la variable User Defined Type.
Public Sub SetValues(udtOrder As Order)
With udtOrder
SetValue Me.txtClient, .Client
SetValue Me.txtEntryDate, .EntryDate
SetValue Me.cboProduct, .Product
SetValue Me.cbxAttention, .Attention
End With
End Sub
Public Sub GetValues(ByRef udtOrder As Order)
With udtOrder
.Client = GetValue(Me.txtClient, TypeName(.Client))
.EntryDate = GetValue(Me.txtEntryDate, TypeName(.EntryDate))
.Product = GetValue(Me.cboProduct, TypeName(.Product))
.Attention = GetValue(Me.cbxAttention, TypeName(.Attention))
End With
End Sub
SetValues
y GetValues
se aplican mediante los procedimientos que se indican a continuación:
Private Sub SetValue(ctl As MSForms.Control, value As Variant)
On Error GoTo HandleError
ctl.value = value
HandleExit:
Exit Sub
HandleError:
Resume HandleExit
End Sub
Private Function GetValue(ctl As MSForms.Control, strTypeName As String) As Variant
On Error GoTo HandleError
Dim value As Variant
value = ctl.value
If IsNull(value) And strTypeName <> "Variant" Then
Select Case strTypeName
Case "String"
value = ""
Case Else
value = 0
End Select
End If
HandleExit:
GetValue = value
Exit Function
HandleError:
Resume HandleExit
End Function
Validación del formulario de usuario
Cuando el usuario pulsa OK, los datos del UserForm son validados por la función IsInputOk
.
Esto comprueba para cada control de entrada IsInputControl
si tiene un valor HasValue
en caso de que sea necesario IsRequired
.
A continuación, comprueba si el valor es del tipo correcto IsCorrectType
- como se especificó en UserForm Builder.
Si no se supera alguna de las dos pruebas, se envía un mensaje al usuario y se pone el foco en el control cuyo valor ha fallado ctl.SetFocus
.
Private Function IsInputOk() As Boolean
Dim ctl As MSForms.Control
Dim strMessage As String
IsInputOk = False
For Each ctl In Me.Controls
If IsInputControl(ctl) Then
If IsRequired(ctl) Then
If Not HasValue(ctl) Then
strMessage = ControlName(ctl) & " must have value"
End If
End If
If Not IsCorrectType(ctl) Then
strMessage = ControlName(ctl) & " is not correct"
End If
End If
If Len(strMessage) > 0 Then
ctl.SetFocus
GoTo HandleMessage
End If
Next
IsInputOk = True
HandleExit:
Exit Function
HandleMessage:
MsgBox strMessage
GoTo HandleExit
End Function
Observe que IsCorrectType
utiliza la función ControlDataType
que simplemente devuelve el tipo para el control dado utilizando las sentencias Select Case
insertadas por el UserForm Builder. Un enfoque similar pero más simple se sigue para IsRequired
.
Private Function IsCorrectType(ctl As MSForms.Control) As Boolean
Dim strControlDataType As String, strMessage As String
Dim dummy As Variant
strControlDataType = ControlDataType(ctl)
On Error GoTo HandleError
Select Case strControlDataType
Case "Boolean"
dummy = CBool(GetValue(ctl, strControlDataType))
Case "Byte"
dummy = CByte(GetValue(ctl, strControlDataType))
Case "Currency"
dummy = CCur(GetValue(ctl, strControlDataType))
Case "Date"
dummy = CDate(GetValue(ctl, strControlDataType))
Case "Double"
dummy = CDbl(GetValue(ctl, strControlDataType))
Case "Decimal"
dummy = CDec(GetValue(ctl, strControlDataType))
Case "Integer"
dummy = CInt(GetValue(ctl, strControlDataType))
Case "Long"
dummy = CLng(GetValue(ctl, strControlDataType))
Case "Single"
dummy = CSng(GetValue(ctl, strControlDataType))
Case "String"
dummy = CStr(GetValue(ctl, strControlDataType))
Case "Variant"
dummy = CVar(GetValue(ctl, strControlDataType))
End Select
IsCorrectType = True
HandleExit:
Exit Function
HandleError:
IsCorrectType = False
Resume HandleExit
End Function
Private Function ControlDataType(ctl As MSForms.Control) As String
Select Case ctl.Name
Case "txtClient": ControlDataType = "String"
Case "txtEntryDate": ControlDataType = "Date"
Case "cboProduct": ControlDataType = "String"
Case "cbxAttention": ControlDataType = "Boolean"
End Select
End Function
Private Function IsRequired(ctl As MSForms.Control) As Boolean
Select Case ctl.Name
Case "txtClient", "txtEntryDate", "cboProduct", "cbxAttention"
IsRequired = True
Case Else
IsRequired = False
End Select
End Function