VBA
Formularios de usuario
Buscar..
Mejores prácticas
Un UserForm
es un módulo de clase con un diseñador y una instancia predeterminada . Se puede acceder al diseñador presionando Shift + F7 mientras se ve el código subyacente , y se puede acceder al código subyacente presionando la tecla F7 mientras se ve el diseñador .
Trabaja con una nueva instancia cada vez.
Al ser un módulo de clase , un formulario es, por lo tanto, un modelo para un objeto . Debido a que un formulario puede contener el estado y los datos, es una mejor práctica trabajar con una nueva instancia de la clase, en lugar de con la predeterminada / global:
With New UserForm1
.Show vbModal
If Not .IsCancelled Then
'...
End If
End With
En lugar de:
UserForm1.Show vbModal
If Not UserForm1.IsCancelled Then
'...
End If
Trabajar con la instancia predeterminada puede provocar errores sutiles cuando el formulario se cierra con el botón rojo "X" y / o cuando se utiliza Unload Me
en el código subyacente.
Implementar la lógica en otro lugar.
Un formulario no debe ocuparse de nada más que de la presentación : un botón El controlador de Click
que se conecta a una base de datos y ejecuta una consulta parametrizada basada en la entrada del usuario, está haciendo muchas cosas .
En su lugar, implemente la lógica aplicativa en el código que es responsable de mostrar el formulario, o incluso mejor, en módulos y procedimientos dedicados.
Escriba el código de tal manera que UserForm solo sea responsable de saber cómo mostrar y recopilar datos: de dónde provienen los datos, o qué sucede con los datos después, no es motivo de preocupación.
La persona que llama no debe ser molestada con los controles.
Cree un modelo bien definido para el formulario con el que trabajar, ya sea en su propio módulo de clase dedicado o encapsulado dentro del propio código subyacente del formulario: exponga el modelo con procedimientos de Property Get
y haga que el código del cliente trabaje con estos: esto hace que la forma una abstracción sobre los controles y sus detalles esenciales, exponiendo solo los datos relevantes al código del cliente.
Esto significa código que se ve así:
With New UserForm1
.Show vbModal
If Not .IsCancelled Then
MsgBox .Message, vbInformation
End If
End With
En lugar de esto:
With New UserForm1
.Show vbModal
If Not .IsCancelled Then
MsgBox .txtMessage.Text, vbInformation
End If
End With
Manejar el evento QueryClose.
Por lo general, los formularios tienen un botón Cerrar , y las indicaciones / diálogos tienen los botones Aceptar y Cancelar ; el usuario puede cerrar el formulario utilizando el cuadro de control del formulario (el botón rojo "X"), que destruye la instancia del formulario de forma predeterminada (otra buena razón para trabajar con una nueva instancia cada vez ).
With New UserForm1
.Show vbModal
If Not .IsCancelled Then 'if QueryClose isn't handled, this can raise a runtime error.
'...
End With
End With
La forma más sencilla de controlar el evento QueryClose
es establecer el parámetro Cancel
en True
y luego ocultar el formulario en lugar de cerrarlo :
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Cancel = True
Me.Hide
End Sub
De esa manera, el botón "X" nunca destruirá la instancia, y la persona que llama puede acceder de forma segura a todos los miembros públicos.
Ocultar, no cerrar.
El código que crea un objeto debe ser responsable de destruirlo: no es responsabilidad del formulario descargarse y terminarse.
Evite usar Unload Me
en el código subyacente de un formulario. Call Me.Hide
en Me.Hide
lugar, para que el código de llamada aún pueda usar el objeto que creó cuando se cierra el formulario.
Nombre las cosas.
Use la ventana de herramientas de propiedades ( F4 ) para nombrar cuidadosamente cada control en un formulario. El nombre de un control se usa en el código subyacente, por lo que, a menos que esté usando una herramienta de refactorización que pueda manejar esto, cambiar el nombre de un control romperá el código , por lo que es mucho más fácil hacer las cosas bien en primer lugar, que intentarlo para descifrar exactamente cuál de los 20 cuadros de texto significa TextBox12
.
Tradicionalmente, los controles de UserForm se nombran con prefijos de estilo húngaro:
-
lblUserName
para un controlLabel
que indica un nombre de usuario. -
txtUserName
para un controlTextBox
donde el usuario puede ingresar un nombre de usuario. -
cboUserName
para un controlComboBox
donde el usuario puede ingresar o elegir un nombre de usuario. -
lstUserName
para un controlListBox
donde el usuario puede elegir un nombre de usuario. -
btnOk
ocmdOk
para un control deButton
etiqueta "Ok".
El problema es que cuando, por ejemplo, la IU se rediseña y un ComboBox
cambia a un ListBox
, el nombre debe cambiar para reflejar el nuevo tipo de control: es mejor nombrar los controles por lo que representan, en lugar de después de su tipo de control, para desacoplarlos. Código de la interfaz de usuario tanto como sea posible.
-
UserNameLabel
para una etiqueta de solo lectura que indica un nombre de usuario. -
UserNameInput
para un control donde el usuario puede ingresar o elegir un nombre de usuario. -
OkButton
para un botón de comando etiquetado "Ok".
Cualquiera que sea el estilo elegido, cualquier cosa es mejor que dejar que todos los controles tengan sus nombres predeterminados. La consistencia en el estilo de nombre también es ideal.
Manejo de consultas cerrar
El evento QueryClose
se QueryClose
cada vez que se cierra un formulario, ya sea a través de la acción del usuario o mediante programación. El parámetro CloseMode
contiene un valor de enumeración VbQueryClose
que indica cómo se cerró el formulario:
Constante | Descripción | Valor |
---|---|---|
vbFormControlMenu | El formulario se está cerrando en respuesta a la acción del usuario. | 0 |
vbFormCode | El formulario se está cerrando en respuesta a una declaración de Unload | 1 |
vbAppWindows | Sesión de Windows está terminando | 2 |
vbAppTaskManager | El Administrador de tareas de Windows está cerrando la aplicación host | 3 |
vbFormMDIForm | No soportado en VBA | 4 |
Para una mejor legibilidad, es mejor usar estas constantes en lugar de usar su valor directamente.
Un formulario de usuario cancelable
Dada una forma con un botón Cancelar
El código subyacente del formulario podría verse así:
Option Explicit
Private Type TView
IsCancelled As Boolean
SomeOtherSetting As Boolean
'other properties skipped for brievety
End Type
Private this As TView
Public Property Get IsCancelled() As Boolean
IsCancelled = this.IsCancelled
End Property
Public Property Get SomeOtherSetting() As Boolean
SomeOtherSetting = this.SomeOtherSetting
End Property
'...more properties...
Private Sub SomeOtherSettingInput_Change()
this.SomeOtherSetting = CBool(SomeOtherSettingInput.Value)
End Sub
Private Sub OkButton_Click()
Me.Hide
End Sub
Private Sub CancelButton_Click()
this.IsCancelled = True
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
this.IsCancelled = True
Me.Hide
End If
End Sub
El código de llamada podría mostrar el formulario y saber si fue cancelado:
Public Sub DoSomething()
With New UserForm1
.Show vbModal
If .IsCancelled Then Exit Sub
If .SomeOtherSetting Then
'setting is enabled
Else
'setting is disabled
End If
End With
End Sub
La propiedad IsCancelled
devuelve True
cuando se hace clic en el botón Cancelar , o cuando el usuario cierra el formulario utilizando el cuadro de control .