Trabajando con controles de formulario
Desliza para mostrar el menú
TextBoxes y ComboBoxes cubren la mayoría de las entradas de datos, pero algunos otros controles expresan ciertos tipos de elecciones de manera más natural, y leer sus valores correctamente tiene algunos detalles importantes que conviene conocer antes de confiar en ellos.
CheckBoxes
La propiedad Value de un CheckBox es un valor Booleano simple: True cuando está seleccionado, False cuando no lo está:
If chkWelcomeEmail.Value = True Then
MsgBox "A welcome email would be sent here."
End If
Cada CheckBox en un formulario es completamente independiente de los demás; seleccionar chkWelcomeEmail no afecta a chkNewsletter, lo cual es exactamente el comportamiento deseado cuando las opciones no son mutuamente excluyentes.
OptionButtons
Los OptionButtons funcionan de manera opuesta: dentro del mismo grupo, seleccionar uno deselecciona automáticamente todos los demás, exactamente lo que necesitan las opciones de Estado de la captura de pantalla, ya que un cliente no puede ser Activo e Inactivo al mismo tiempo. Para saber cuál está seleccionado, hay que comprobar el valor de cada uno individualmente:
Dim status As String
If optActive.Value = True Then
status = "Active"
ElseIf optInactive.Value = True Then
status = "Inactive"
ElseIf optProspect.Value = True Then
status = "Prospect"
End If
La exclusividad mutua es automática y está gestionada completamente por VBA; nunca es necesario escribir código para desmarcar los otros dos cuando uno es seleccionado. Sin embargo, la agrupación es importante: los OptionButtons solo se excluyen entre sí dentro del mismo contenedor (el propio formulario o un control Frame colocado en él), por lo que dos grupos separados de OptionButtons en el mismo formulario —por ejemplo, Estado y Prioridad— deben estar dentro de dos Frames diferentes, o VBA trataría a todos como un solo grupo mutuamente excluyente.
ListBoxes
Un ListBox muestra varias opciones a la vez sin necesidad de desplegarse, como la lista de City en la Figura 5.5. Se llena de la misma manera que un ComboBox, con .AddItem, y se lee la selección mediante .Value o .ListIndex:
Private Sub UserForm_Initialize()
lstCities.AddItem "Chicago"
lstCities.AddItem "Boston"
lstCities.AddItem "Austin"
End Sub
Private Sub cmdAssign_Click()
If lstCities.ListIndex = -1 Then
MsgBox "Please select a city first."
Exit Sub
End If
MsgBox "Assigning to: " & lstCities.Value
End Sub
ListIndex es la posición del elemento seleccionado, contando desde 0 para el primer elemento, y es -1 cuando aún no se ha seleccionado nada, lo cual es la comprobación que utiliza cmdAssign_Click para detectar si el usuario hace clic en el botón sin elegir una ciudad primero. .Value proporciona directamente el texto seleccionado, que suele ser más útil que la posición numérica que da .ListIndex.
Formularios Multi-Page
Un control MultiPage (las pestañas Details / Preferences en la parte superior de la Figura 5.5) agrupa controles relacionados en páginas separadas dentro del mismo formulario físico, útil cuando un formulario tiene demasiados campos para caber cómodamente en una sola pantalla. Cada página se identifica por su posición, y solo los controles de la página visible son relevantes para el usuario, aunque todos siguen existiendo y pueden leerse desde el código sin importar qué página esté mostrando:
Private Sub MultiPage1_Change()
If MultiPage1.Value = 1 Then
MsgBox "Now viewing Preferences"
End If
End Sub
MultiPage1.Value sigue la misma numeración desde 0 que ListIndex: la primera página es 0, la segunda (Preferences, en la Figura 5.5) es 1, y el evento Change se activa automáticamente cada vez que el usuario hace clic en una pestaña diferente.
Tarea
- Agregar un Frame que contenga tres OptionButtons (optActive, optInactive, optProspect) a frmAddCustomer, reemplazando el anterior ComboBox cboStatus, y escribir el bloque If...ElseIf mostrado arriba para leer la selección.
- Agregar dos CheckBoxes independientes (chkWelcomeEmail, chkNewsletter) y confirmar en las pruebas que marcar uno nunca afecta al otro.
- Agregar un ListBox (lstCities) que se llene en UserForm_Initialize, y escribir una validación que muestre un error si el usuario intenta continuar sin seleccionar nada (ListIndex = -1).
- Desafío: agrupar los campos Company Name, Contact y Email en una página de MultiPage llamada "Details", y los CheckBoxes y OptionButtons en una segunda página llamada "Preferences".
1. Reemplazo de cboStatus por un Frame con OptionButtons
- Elimina primero
cboStatusy su etiqueta del formulario — lo estás reemplazando, no agregando junto a él. - Arrastra un control Frame al formulario, luego arrastra los tres OptionButtons dentro de los límites del Frame — este contenedor es lo que los hace mutuamente excluyentes como un solo grupo.
- Renombra cada OptionButton individualmente en la ventana de Propiedades; el Frame puede mantener un Caption sencillo como "Status" y no necesita un nombre para código a menos que planees referenciarlo directamente.
- Leer la selección significa comprobar el
.Valuede cada OptionButton individualmente conIf...ElseIf— no existe una propiedad única que indique "cuál del grupo está seleccionado". - Como
cboStatus.Valueya no existe,cmdSave_Clicknecesita una variablestatusconstruida a partir de los OptionButtons, que se escribirá ennewRowen su lugar.
2. Agregar dos CheckBoxes independientes
- Estos se colocan directamente en el formulario (no dentro del Frame) — los CheckBoxes fuera de un contenedor compartido nunca se afectan entre sí, sin importar el agrupamiento.
- Para "confirmar en pruebas", simplemente marca uno, luego el otro, y verifica que ninguno desmarca el primero.
3. Agregar y validar un ListBox
- Llénalo de la misma manera que se llenaba
cboCity— llamadas repetidas a.AddItemenUserForm_Initialize. ListIndex = -1significa específicamente aún no se ha hecho clic en nada — esa es la condición exacta que debes comprobar antes de permitir guardar.- Esta validación debe estar en el mismo bloque de validación que las otras comprobaciones de campos obligatorios, agregando al mismo string
errors.
4. Desafío MultiPage
- Arrastra un control MultiPage al formulario — viene con dos páginas por defecto, que es exactamente lo que necesitas.
- Renombra cada página mediante clic derecho → Page Order, o seleccionando la pestaña de la página y usando el campo Caption en la ventana de Propiedades (Caption controla el texto visible de la pestaña; hay un campo (Name) separado si quieres referenciar una página por nombre en el código).
- Mover controles existentes a una página significa arrastrarlos físicamente al área visible de esa página en la vista de diseño — las referencias de código a ellos no cambian, ya que el nombre del control no depende de en qué página esté ubicado.
Private Sub UserForm_Initialize()
cboCity.AddItem "Chicago"
cboCity.AddItem "Boston"
cboCity.AddItem "Austin"
cboCity.AddItem "Seattle"
cboCity.AddItem "Denver"
lstCities.AddItem "Chicago"
lstCities.AddItem "Boston"
lstCities.AddItem "Austin"
lstCities.AddItem "Seattle"
lstCities.AddItem "Denver"
End Sub
Private Sub cmdCancel_Click()
Unload Me
End Sub
Private Sub cmdSave_Click()
Dim tbl As ListObject
Dim newRow As ListRow
Dim errors As String
Dim status As String
' --- Reset field colors ---
txtCompanyName.BackColor = vbWhite
txtContact.BackColor = vbWhite
txtEmail.BackColor = vbWhite
' --- Required field checks ---
If Trim(txtCompanyName.Value) = "" Then
errors = errors & "- Company Name is required" & vbNewLine
txtCompanyName.BackColor = RGB(255, 199, 206)
End If
If Trim(txtContact.Value) = "" Then
errors = errors & "- Contact is required" & vbNewLine
txtContact.BackColor = RGB(255, 199, 206)
End If
If Trim(txtEmail.Value) = "" Then
errors = errors & "- Email is required" & vbNewLine
txtEmail.BackColor = RGB(255, 199, 206)
End If
' --- Status via OptionButtons ---
If optActive.Value = True Then
status = "Active"
ElseIf optInactive.Value = True Then
status = "Inactive"
ElseIf optProspect.Value = True Then
status = "Prospect"
Else
errors = errors & "- Please select a Status" & vbNewLine
End If
' --- ListBox check ---
If lstCities.ListIndex = -1 Then
errors = errors & "- Please select a city from the list" & vbNewLine
End If
If errors <> "" Then
MsgBox "Please fix the following:" & vbNewLine & errors, vbExclamation
Exit Sub
End If
' --- All checks passed — safe to save now ---
Set tbl = ThisWorkbook.Worksheets("Customers").ListObjects("tblCustomers")
Set newRow = tbl.ListRows.Add
newRow.Range(1, 1).Value = "C0" & (tbl.ListRows.Count + 100)
newRow.Range(1, 2).Value = txtCompanyName.Value
newRow.Range(1, 3).Value = txtContact.Value
newRow.Range(1, 4).Value = txtEmail.Value
newRow.Range(1, 5).Value = cboCity.Value
newRow.Range(1, 6).Value = status
If chkWelcomeEmail.Value = True Then
MsgBox "A welcome email would be sent to " & txtEmail.Value & "."
End If
MsgBox txtCompanyName.Value & " was added successfully."
Unload Me
End Sub
Notas de prueba:
- El punto 2 (CheckBoxes) no tiene validación dedicada — simplemente haz clic en
chkWelcomeEmailychkNewsletterde forma independiente y confirma que cada uno se activa sin afectar al otro. - El punto 4 (MultiPage) es solo un cambio de diseño — no se requieren cambios de código más allá de lo que ya está aquí, ya que cada control mantiene su propio nombre sin importar en qué página se coloque.
- Observa que
cboCity.Valuetodavía se usa para el guardado real (newRow.Range(1, 5)), mientras quelstCitiesexiste únicamente como un control independiente validado por separado según la tarea — ambos no están conectados a menos que decidas ampliarlo por tu cuenta.
¡Gracias por tus comentarios!
Pregunte a AI
Pregunte a AI
Pregunte lo que quiera o pruebe una de las preguntas sugeridas para comenzar nuestra charla