Formularios en Componentes de CódigoTécnicas Depuradas para Suministrar Formularios desde Componentes ActiveX con Visual Basic
|
|
|
Suministrar Formularios desde componentes es una buena estrategia de desarrollo. Los formularios ocupan espacio considerable en el ambiente de desarrollo de un proyecto. No es necesario mantener cada formulario en el proyecto principal, de hecho el único formulario de una aplicación podría ser el inicial, hablando técnicamente el Front End de la solución. Empaquetar formularios en componentes de código permitirá a una aplicación robusta evolucionar en tamaño y desarrollo libre de sobrecarga. Sin embargo, usar Formularios en Componentes tiene su intríngulis y suele ser un tema relativamente nuevo para programadores Visual Basic corrientes, quizá extraño y difícil. Puede que Ud. haya empacado ya muchos formularios en componentes de código, sin embargo, los modelos que sugiero en este articulo son altamente competentes, y representan una alternativa simple y robusta al mismo tiempo. |
Inicialmente pense escribir este articulo para que cubriera los formularios modales y no modales, sin embargo el escrito se extendió tanto, que decidí dividirlo en dos partes: en (1) Formularios Modales en Componentes en Proceso, (2) Formularios no Modales en Componentes en Proceso, con alguna nota sobre formularios en componentes fuera de proceso.
Otra difícil decisión que tuve que tomar fue: ¿Escribo todo basado en interfaces múltiples, o uso el estilo tradicional?. Vaya decisión. Si me decidia por usar interfaces, quizás programadores noveles e intermedios en Visual Basic no leerían este articulo, o quiza lo leerían y perciban un extraño modo de hacer difícil las cosas fáciles. La programación orientada a Interfaces presenta unos perfiles si no avanzados, poco frecuentes entre programadores (en especial aquellos que vienen de la antigua OOP), y reviste mayores explicaciones que pueden terminar en desanimar al lector. De otro lado la programación tradicional será aceptada inmediatamente en todos los niveles de programadores Visual Basic, y finalmente, el articulo será útil. Bien, que me condenen al infierno de Dante los programadores avanzados en Visual Basic, use programación tradicional en los modelos de código de este articulo. Sin embargo, para expirar en parte mi pecado, escribí un ejemplo en un anexo para explicar exactamente como usar lo mismo pero con interfaces. Si me preguntan: ¿Cuál es mejor?, la respuesta es: La programación orientada a interfaces tiene mayores beneficios, pero en grandes desarrollos.
Para iniciar en el tema, le podría sugerir indagar por «Creación de una DLL ActiveX» y «Creación de un Componente EXE ActiveX», en la documentación estándar de Visual Basic (libros en pantalla para VB5 o MSDN para VB6). Esta documentación es ideal, lo robustecerá en conocimientos y lo pondrá al tanto de los beneficios y precauciones de usar formularios dentro de componentes. Sin embargo, a través de mi experiencia he delineado algunos modelos de código que contribuyen a solucionar sistemáticamente las necesidades de usar formularios en componentes.
En general, las fallas comunes de una mala programación de formularios en componentes provienen de dejar objetos sueltos, en particular por el entorno conceptual de iniciar y terminar un Formulario. En general, la clave del éxito de usar formularios en componentes se fundamente en que la clase que envuelve el formulario es la encargada de controlar la vida del formulario, y no el formulario quien dictamina su permanencia en memoria. Quizá se sorprenda, pero dominar las referencias a un objeto puede ser más difícil de lo presupuestado. Los modelos aquí expuestos suministran total dominio sobre la instancia del formulario.
Necesariamente los formularios se deben envolver en clases las cuales suministran la interfaz. ¿Cómo va el código dentro de la clase y dentro del formulario?; este articulo es una cátedra.
Pense escribir este articulo con un estilo más deductivo y formal, delegando los modelos de código en líneas generales, pero recordé unas palabras en el prologo de Bruce McKenney, autor de Hardcore Visual Basic: «Ejemplos!!!! Maldición ». Esta realmente me parece una brillante sugerencia para escritos técnicos de programación. Bien, así se hará, explicare con un ejemplos reales y resaltaré aquellas partes que se deberán reemplazar para beneficiarse del código.
Formularios Modales en Componentes en Proceso
Los formularios modales tienen una misión clásica: Una ventana que recoge datos suministrados por el usuario y los devuelve a la aplicación para que haga algo. Asi pues, los formularios modales son idóneos para ser empaquetados en componentes. Un programa bien diseñado (con mentalidad de objetos) no almacena formularios que se presentarán modales en su proyecto principal.
Ejecución proceso significa una DLL ActiveX, o un Control ActiveX, instalados en el PC del cliente. En general aquí hablaré de componentes de código, más precisamente DLLs ActiveX, sin embargo, los Controles ActiveX a la larga son componentes de código con ciertas particularidades: Básicamente: (1) tiene interfaz gráfica para ser perfilada en tiempo de diseño, y (2) el contenedor (generalmente un Formulario) tras bambalinas controla la vida del control. Los formularios empaquetados en controles ActiveX perfectamente pueden seguir las reglas de este articulo.
Por demás, bebiera seguir las normas de diseño de formularios modales, p.e. BorderStyle=Fixed (yo prefiero Fixed ToolWindow), TabStrips, y así sucesivamente. También es conveniente usar el prefijo dlg, en vez de frm, para los formularios que se presentaran modales.
Según mi criterio, la estrategia de código para suministrar formularios depende de dos casos: Formularios Modales Eventuales y Formularios Modales Frecuentes (en memoria).
1. Formularios Modales Eventuales Pasivos
Me refiero a aquellos que se usan muy pocas veces dentro de la aplicación y no suministran servicios activos (por ejemplo el Formulario Acerca De). Es decir, los podemos cargar en memoria cuando se solicitan, y eliminarlos cuando se cierran. Este caso es el más sencillo de programar, observe el código de la clase que envuelve un formulario dlgAbout:
|
'// CLASE : cls_About |
El código dentro del Formulario es el siguiente:
|
'// FORMULARIO : dlgAbout |
Como el formulario es pasivo (no toma ni retorna datos), no se requiere de más código. Noté que el método ShowDialog tiene parámetros para configurar el formulario, y este a su vez tiene el método publico FillLabels. La lista de parámetros en este método la usaria para pasar la información con la cual se configurará el formulario.
|
Todo aquello que vaya en cursiva, dentro de los bloques de código, es lo que Ud. debiera modificar para emplear el modelo. |
Finalmente, el código en el cliente que invoca el formulario (supongamos un botón cmdAbout) es:
|
Private Sub cmdAbout_Click() |
2. Formularios Modales Eventuales que Retornan Datos
Otro es el caso para formularios eventuales que retornan datos al cliente. Simplemente delegamos los valores recogidos en controles como propiedades limpias de la clase. Además, el formulario deberá tener un botón Acept y uno Cancel. Normalmente, en beneficio de usar teclado, se sigue la lógica de que el botón Acept tiene la propiedad Default=True, y el botón Cancel tiene la propiedad Cancel=True. He aquí el ejemplo:
Se trata de un formulario dlgLoging, el cual recoge el nombre y contraseña del usuario. Normalmente este tipo de formulario se presenta una sola vez en el proceso de una aplicación. El modelo de código de la clase que envuelve este dialogo es el siguiente:
|
'// CLASE : cls_Loging |
La clase retorna limpiamente User y Password como propiedades, siempre que el usuario usa el comando Aceptar.
|
Note que implemente las propiedades User y Password como variables publicas. En general, en diseño de objetos poco se hace, es más conveniente usar la pareja de procedimientos Get y Let. No obstante, en este caso puede ser una excepción y es perfectamente válido, ya que realmente son delegaciones simples y es el formulario quien debiera filtrar los datos si fuese necesario. Por ejemplo tras el botón Acepar, se podrían usar procedimientos de validación. |
Los valores que retorna el dialogo provienen de valores de controles en el formulario, como TextBox, CheckBox, etc. En este ejemplo son dos TextBox. El modelo de código en el formulario es el siguiente:
|
'// FORMULARIO : dlgLoging |
El código en el cliente debe seguir este modelo (evaluamos la propiedad Acept):
|
Private Sub cmdModalVolatil_Click() |
Este mismo ejemplo fue el que use en el Anexo I para mostrar la implementación usando interfaces múltiples.
3. Formularios Modales Frecuentes (En Memoria)
Son aquellos Formularios que se usarán frecuentemente, por ejemplo aquel formulario que pide los parámetros del filtro para una consulta. Como caso clásico tenemos el formulario Buscar. Es conveniente mantener estos formularios en memoria por razones de rapidez de la aplicación.
En este caso es conveniente jugar con eventos, dan una salida limpia e intuitiva. El ejemplo que seguiré será un formulario que lee un nombre y apellido de un empleado, un clásico dlgGetEmployee. El modelo de código en la clase que envuelve el dialogo es el siguiente (recuerde que las palabras en cursiva indican aquel código que cambia para un caso particular):
|
'//CLASE : cls_GetEmployee |
Como regla estándar, el formulario debe tener un botón Aceptar y un botón Cancelar. También, los valores que retorna el dialogo provienen de valores de controles en el formulario, como TextBox, CheckBox, etc. El modelo de código en el formulario es:
|
'// FORMULARIO : dlgGetEmployee |
El código en el cliente debe seguir este modelo:
|
'//Cuadro de dialogo en memoria |
La clase se mantiene en memoria del cliente, pero el formulario solo se cargará la primera vez que es llamado. Esto es un buen diseño.
ANEXO I
Usando Programación Orientada a Interfaces Múltiples
La Programación Orientada a Interfaces Múltiples suministra un estilo de programación lejanamente superior a la programación tradicional. Representa el perfil mejor elaborado de programación de objetos y reutilización de código con Visual Basic (si bien, supera en varios aspectos al paradígma dogmático de la OOP).
Escribiré el ejemplo de «Formularios Modales Eventuales que Retornan Datos», usando interfaces. Se requieren tres pasos.
Paso 1: Definir la interfaz abstracta. Como repasará en el caso que traté (numeral 2), la clase solo suministra dos atributos: La propiedad Acept y el método ShowDialog. Bien, la interfaz abstracta, que he bautizado IVolatilModal, es así de simple:
'//CLASE : IVolatilModal
'//DESCRIPCIÓN : Interfaze que envuelve un formulario modal
Public Property Get Acept() As Boolean
End Property
Public Sub ShowDialog()
End Sub
Note que la propiedad Acept tiene solo el procedimiento Get, lo cual significa que la interfaz suministra la propiedad para solo lectura.
Recuerde que para las clases abstractas, la propiedad Insancing debe ser 2-PublicNotCreatable.
Paso 2: Implementar la interfaz en la clase que envuelve al formulario. La clase que envuelve el formulario cambia ligeramente. Los datos que sede el cuadro de dialogo son atributos particulares de la interfaz que implementa IVolatiolModal, en este ejemplo llamaré a esta nueva interfaz CLoging. Aquí esta el código de la clase que envuelve el formulario:
'//CLASE : CLoging
'//DESCRIPCIÓN : Modelo de clase que envuelve un formulario modal
Option Explicit
'//Implementa la interfaz
Implements IVolatilModal
'//Miembro heredado de la Implementación
Private Acept As Boolean
'//Retrono del cuadro de dialogo
Public User As String
Public Password As String
Private Property Get IVolatilModal_Acept() As Boolean
IVolatilModal_Acept = Acept
End Property
Private Sub IVolatilModal_ShowDialog()
Dim dlg As dlgLoging
Set dlg = New dlgLoging
Load dlg
With dlg
.Show vbModal
Acept = .Acept
If Acept Then
User = .txtUser
Password = .txtPassword
End If
End With
Unload dlg
End Sub
NOTA. En mi privada norma de codificación (si se puede llamar Húngara), uso el prefijo cls_ClassName para clases con una única interfaz. Mientras que uso CClassName para clases con varias interfaces. No me ponga cuidado, solo es un pequeño capricho.
El código dentro del formulario ni su interfaz cambian, así que no hay necesidad de repetir estas líneas. Esto quiere decir que solo cambia la implementación del formulario dentro del componente.
Paso 3. Usar la Interfaz en el cliente. Ahora debemos declarar un objeto para la interfaz y otro para la clase particular que implementa la interfaz. El código tiene esta forma (como ejemplo, un botón cmdLogging que muestra el formulario):
Private Sub cmdLogging_Click()
Dim dlg As CLoging '//Subclase
Dim vm As IVolatilModal '//Superclase
Set dlg = New CLoging
Set vm = dlg
With vm
.ShowDialog
If .Acept Then
MsgBox "Procesa el formulario anterior"
Debug.Print "User ="; dlg.User
Debug.Print "Password ="; dlg.Password
End If
End With
Set dlg = Nothing
End Sub
Este caso se vé muy elegante. Sin embargo, seré sincero, este caso es simple. Los demás modelos requieren algo más profundo y complicado para poder implementar interfaces. Por ejemplo, analice las consecuencias de los eventos. Buena suerte.
¿Porque emplear Interfaces Múltiples?
A parte de tener un código reutilizable, suministrar una plantilla de diseño, y tener un código listo para ser usado en desarrollos pesados, tenemos nada menos y nada más que poliformismo. Por ejemplo, podríamos agrupar formularios de acceso a datos que implementen la interfaz IVolatilModal (algo más elaborada) y administrarlos desde procedimientos únicos.