Formularios en Componentes de CódigoTécnicas Depuradas para Suministrar Formularios desde Componentes ActiveX con Visual Basic
|
|
|
En la primara parte de este articulo trate de los formularios empaquetados en componentes de código y que se presentarán como modales. Bien, ese caso es relativamente sencillo comparado con la utilización de formularios no modales en componentes. Realmente esto requiere un dominio de Visual Basic algo más depurado. Existe una precaución en la utilización de formularios no modales en componentes en proceso, pero realmente no hay porque prescindir de este recurso si se usa un modelo de código bien diseñado. El ejemplo más frecuente y util de formularios no modales en DLLs, lo representan las ToolBar emergentes, por lo tanto expondré este diseño. De otra parte, también es posible manejar en código formularios instansiables no modales. |
Explicaré a través de ejemplos los dos casos respectivamente: (1) Formularios con una única instancia, y (2) Formularios que pueden suministrar varias instancias.
Formulario No Modal en Componente en Proceso, Unica Instancia
El caso clásico lo representan los formularios de herramientas flotantes (emergentes), conocidos comúnmente como ToolBars. Una Toolbar permite al usuario escoger opciones a partir de iconos, en una interfaz cómoda. Para un mejor desempeño de la aplicación, la mejor estrategia es mantener el formulario en memoria.
El ejemplo que expondré es un sencillo Form, con Name=frmToolBoxSample y que incorpora una matriz de cuatro CommandButton, con Name=cmdOption. Sigue esta ilustración:
Normalmente usaremos controles especializados como el Toolbar de la biblioteca Microsoft Windows Common Controls, no obstante, para simplificar el asunto, este sencillo ejemplo es suficientemente claro. El siguiente modelo suministra el código para la clase que envuelve un formulario flotante:
|
'//CLASE: cls_ToolBox |
El código anterior se ve un poco extenso, pero solo se debe a la declaración y constantes de la API SetWindowPos, cuya función es habilitar como flotante (emergente) el formulario que envuelve. El método ShowForm podría llevar otros argumentos que permitan configurar de manera particular el ToolBox. Note que la clase suministra un evento al cliente: ReturnOption.
El siguiente modelo es el código para el formulario:
'//FORM : TOOLBOX SAMPLE
'//DESCRIPCIÖN : Formulario No Modal Flotante (opcional)
Option Explicit
Public Event ReturnOption(Value As Integer, Name As String)
Private Sub cmdOption_Click(Index As Integer)
RaiseEvent ReturnOption(Index, cmdOption(Index).Caption)
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
If UnloadMode = vbFormControlMenu Then
Cancel = True
Hide
Else
Unload Me
End If
End SubEl código que usará en el cliente será:
Option Explicit
'//OBJETOS
Private WithEvents tbSample As cls_ToolBox
'//algun comando que muestra el ToolBox
Private Sub cmdToolBoxSample_Click()
tbSample.ShowForm
End Sub
Private Sub Form_Load()
Set tbSample = New cls_ToolBox
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set tbSample = Nothing
End Sub
Private Sub tbSample_ReturnOption(Value As Integer, Name As String)
'//Este evento se genera cuando se selecciona un ítem
Me.SetFocus '//Importante cuando se usa una ventana flotante
MsgBox "Fue seleccionada la opción: " & Value
'//Hace algo con los parámetros retornados
End SubComo podrá analizar, al usar eventos el código se hace flexible e intuitivo. Las palabras en cursiva seria lo que el programador modificaría para construir su ToolBox particular.
Formulario No Modal en Componente en Proceso, Unica Instancia, No Flotante
Este caso es idéntico al expuesto anteriormente, la excepción es que no requiere la implementación para hacer flotante la ventana. Quitamos todo lo referente a la API SetWindowPos, y tenemos el código. Realmente este tipo de formulario es poco frecuente en aplicaciones.
Formulario No Modal en Componente en Proceso, Múltiples Instancias
Este es el caso más complicado de formularios en componentes de código. En la documentación de Visual Basic hacen reiteradas advertencias de su utilización, vea la siguiente nota textual:
La presentación de formularios no modales desde componentes en proceso requiere comunicación con el bucle de mensajes del cliente. No todos los clientes lo permiten. Para ver una explicación de esta limitación, vea "Presentar formularios desde componentes de código" en "Generar componentes de código".
En general, escribiremos componentes en proceso para mostrar formularios no modales en clientes de Visual Basic y herramientas que suministren Visual Basic para Aplicaciones. Para más información, consultar «Presentar formularios desde componentes de código» de la documentación MSDN o Libros en Pantalla (VB5). También podría buscar documentación para la palabra «NonModalAllowed».
Antes de preocuparse por saber que quiere decir «comunicación con el bucle de mensajes del cliente», por cierto una documentación algo ambigua, un buen diseño con código solucionará el problema fácilmente. Se requiere un fuerte control en la clase que administra los formularios. La técnica que muestro a continuación se basa en la colección Forms del componente (DLL) y en identificadores programados en los formularios. Aplico esta técnica en una de mis mejores aplicaciones de gestión.
Básicamente nos basamos en una clase que controla la creación y eliminación global de instancias de un tipo de formulario especifico. El formulario deberá tener una propiedad que lo identifique como único, y que esta propiedad se conserve durante su vida. En los casos que he empleado formularios instanciables en componentes, esta propiedad, o Id de Formulario, ha sido la clave de un registro en una basa de datos.
En el siguiente ejemplo, expongo un caso al extremo simple, un formulario con un TextBox multi-línea, el cual cubre toda el área del formulario. Un capturador de notas rústico. El código de la clase cls_ModelessNotes, la cual envuenve los formularios, es el siguiente:
'// CLASE : cls_ModelessNotes
'// DESCRIPCION : Modelo de clase que envuelve un formulario no modal
Option Explicit
'//EVENTS
Public Event Busy(Value As Boolean)
Public Event CustomError(Index As Long)
'//Filter another Forms in component
Private Const FormClassName As String = "frmNotes"
Public Sub ShowModeless(IdForm As Long, IdWell As Variant)
Dim frm As Form
Dim Cont As Boolean
Cont = True
RaiseEvent Busy(True)
For Each frm In Forms
If frm.Name = FormClassName Then
If IdForm = frm.IdForm Then
frm.SetFocus
Cont = False
Exit For
End If
End If
Next
If Cont Then
Call LoadInstance(IdForm, IdWell)
End If
RaiseEvent Busy(False)
End Sub
Private Function LoadInstance( _
IdForm As Long, _
IdWell As Variant _
) As Boolean
Dim frm As frmNotes
Dim Cont As Boolean
Dim ErrIndex As Long
Set frm = New frmNotes
Load frm
frm.IdForm = IdForm
'//Validate iniatization
Cont = frm.Init(IdWell, ErrIndex)
If Not Cont Then
Unload frm
Set frm = Nothing
RaiseEvent CustomError(ErrIndex)
Else
frm.Show vbModeless
End If
Set frm = Nothing
LoadInstance = Cont
End Function
Private Sub Class_Terminate()
Call UnloadAll
End Sub
Public Sub UnloadAll()
Dim frm As Form
For Each frm In Forms
If frm.Name = FormClassName Then
Unload frm
End If
Next
End SubSe agregaron los eventos Busy y CustomError, los cuales serán útiles en un desarrollo más pesado. El evento Busy servirá para que el cliente haga algo como mostrar un reloj de espera, un mensaje, etc. El evento CustumError servirá para pasar al cliente códigos de error (CustomError es para simplificar el asunto).
Es preferible usar la tecnología de control de errores de Visual Basic, para más información, consultar «Generar y tratar errores en los componentes ActiveX», de la documentación MSDN o Libros en Pantalla (VB5).
El parámetro IDWell que se suministra en el método ShowModeless es solo una muestra de una clave que se pasa al componente para personalizar el formulario.
El código dentro del formulario del cual se crearán instancias (lo he llamado frmNotes) es el siguiente:
'//FORMULARIO : frmNotes
'//DESCRIPCIÓN : Modelo de formulario no modal
Option Explicit
'//KEY FORM
Private m_IdForm As Long
Private Sub Form_Resize()
If Not Me.WindowState = vbMinimized Then
txtMemo.Move 0, 0, Me.ScaleWidth, Me.ScaleHeight
End If
End Sub
Public Property Get IdForm() As Long
IdForm = m_IdForm
End Property
Public Property Let IdForm(ByVal v As Long)
m_IdForm = v
End Property
Public Function Init(IdWell As Variant, ErrIndex As Long) As Boolean
'//Required if the form must be configurate
'//Sample:
On Error GoTo ErrHandler
Me.Caption = "Form of Key " & m_IdForm
txtMemo = "IdWell = " & IdWell
Init = True
Exit Function
ErrHandler:
ErrIndex = Err.Number
End FunctionFinalmente, el código de lado del cliente es el siguiente:
Option Explicit
'//Formulario no modal multiples instancias
Private WithEvents mn As cls_ModelessNotes
Private Sub cmsModelessNotes_Click()
'//Ejemplos
mn.ShowModeless 12345, "DOR00012_E"
mn.ShowModeless 12377, "ADORX018_X"
End Sub
Private Sub Form_Load()
Set mn = New cls_ModelessNotes
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set mn = Nothing
End Sub
Notas sobre Formularios Componentes Fuera de Proceso
En general, los formularios en componentes fuera de proceso pueden seguir las mismas reglas expuestas en estos dos artículos. Si le inquieta el tema le sugiero "Comportamiento fuera de proceso de los formularios modales y no modales" de la documentación Visual Basic. Los formularios modales tienen poca aplicación, dado que se ejecutan en un proceso diferente, es decir serán modales para el componente, no para el cliente. Los formularios no modales pueden ser tener funciones interesantes aunque su implantación podría ser algo compleja (se supone que deben servir a varios clientes). En fin, quiza merezca una tercera parte este articulo, para cubrir este caso.