Los Trucos del Guille publicados en MSDN España

 

Lista de trucos publicados en MSDN España



Truco publicado con fecha 23/Jul/99

 

Mejorando lo presente

Seguro que en más de una ocasión te hubiera gustado mejorar el comportamiento de un control de Visual Basic.
Casi seguro que en muchos TextBoxes que usas tienes alguna "rutinilla" para, por ejemplo, seleccionar todo el texto cuando el control recibe el foco.
Ya sabrás que puedes crear tu propio control mejorado, pero seguramente te dará algo de "pereza", (por llamarlo de alguna forma), el usar un control externo; si eres como yo, preferirás usar un módulo de clase antes que usar "otro" control más... si es así, puedes hacer que un módulo de clase se comporte como un control creado por tí mismo, pero sin la "sobrecarga" de añadir un control externo...
¿Cómo?
¿Tampoco te gusta añadir módulos de clases?
Entonces... esto...
¡NO IMPORTA!
Lo que te voy a explicar no necesita siquiera de módulos externos de ningún tipo y te permitirá mejorar cualquier control... incluso cualquier formulario...
¿Cómo se hace eso?
Con WithEvents

 

Lo que dice la ayuda del Visual Basic sobre WithEvents:

Palabra clave que especifica que nombre_variable es una variable de objeto utilizada para responder a eventos desencadenados por un objeto ActiveX. WithEvents solamente es válido en módulos de clase. Puede declarar tantas variables individuales como desee mediante WithEvents, pero no puede crear matrices con WithEvents. No puede utilizar New con WithEvents.

Osea, cuando declaramos una variable con WithEvents, lo que estamos es creando una variable que "apunta" a un control o a cualquier otro objeto ActiveX que desencadene eventos, (si no desencadena eventos no se puede usar WithEvents).
Esa variable podrá acceder a los métodos y propiedades del objeto, (lo mismo que una variable declarada normal), pero además nos permite acceder a los eventos producidos por ese objeto, incluso se crea una entrada con el nombre de la variable en el combo de los objetos usados en el módulo de clase en el que se ha declarado... (recuerda que un formulario también se considera una clase, por tanto, también se puede usar WithEvents en los módulos FRM, pero no se podrá usar en los módulos BAS)

 

Vamos a ver un par de ejemplos que clarifiquen el tema:

1- Declarando la variable que mejorará el objeto en un módulo de clase o en un formulario.
2- Creando una clase que encapsule y mejore el comportamiento de dicho objeto.

 

Usar WithEvents directamente en el código del formulario

La primera es más directa y, desde mi punto de vista, menos recomendable, no porque sea menos eficiente, sino porque no "encapsula" el funcionamiento del control mejorado y además es menos orientada a objetos que la segunda... con esto quiero decir que el código usado es menos reutilizable, al menos de forma fácil. Pero aún así, consigue el objetivo: mejorar el funcionamiento del control.

Para comprobarlo, crea un nuevo proyecto, añade un control TextBox (Text1) y escribe el siguiente código:

'
Option Explicit

' Declaramos el objeto que queremos manipular
Private WithEvents mTextEnForm As TextBox


Private Sub Form_Load()
    ' Asignamos el textbox que queremos manipular directamente,
    ' en este caso es el Text1
    Set mTextEnForm = Text1
    ' A partir de ahora todos los eventos podemos manejarlos con este objeto,
    ' es decir con todos los que empiezan con mTextEnForm_
    ' (que estará en la lista de objetos del formulario)
    ' De esa forma podemos fácilmente copiar y pegar el código usado
    ' en otros formularios
    
End Sub


Private Sub Form_Unload(Cancel As Integer)
    Set mTextEnForm = Nothing
End Sub


Private Sub mTextEnForm_GotFocus()
    ' Seleccionar todo el texto
    ' Hay que indicar el nombre de la variable,
    ' no el del objeto asignado, aunque en este caso funcionaría igual,
    ' salvo que después asignaramos otro TextBox
    With mTextEnForm
        .SelStart = 0
        .SelLength = Len(.Text)
    End With
End Sub


Private Sub mTextEnForm_KeyPress(KeyAscii As Integer)
    ' Convertir las letras a mayúsculas,
    ' con esto cubrimos todas las letras
    If KeyAscii >= Asc("a") And KeyAscii <= 255 Then
        KeyAscii = Asc(UCase$(Chr$(KeyAscii)))
    End If
End Sub

Si, en la ventana de código, seleccionas el combo de la izquierda, te darás cuenta que tenemos un nuevo objeto: mTextEnForm, que es precisamente la variable que hemos declarado con WithEvents. Si haces que se muestre ese objeto y seleccionas el combo de la derecha, verás que están todos los eventos que tiene un control TextBox.
Por supuesto, también está el "objeto" Text1 con sus correspondientes eventos... esto puede llegar a confundirnos e incluso hacer que codifiquemos indistintamente en un objeto o en otro... es algo con lo que tienes que aprender a "convivir"

 

Crear una clase para mejorar un objeto

Pero la "gracia" de mejorar controles o formularios, es que podamos reutilizarlo en cualquier otro proyecto, sin tener que cambiar ni una sóla línea de código... al menos en el código que hace la "mejora".
Para conseguirlo habrá que crear una clase que "encapsule" la funcionalidad que queremos darle.

Crea un nuevo proyecto, añade al formulario un control TextBox.
Añade un módulo de clase, cambia el nombre por el de cTextBEx. Pega este código al módulo de clase:

'
'------------------------------------------------------------------------------
' Clase TextBox mejorada                                            (14/Jul/99)
'
' ©Guillermo 'guille' Som, 1999
'------------------------------------------------------------------------------

Option Explicit

' Declaramos el objeto que queremos manipular
Private WithEvents unTextB As TextBox

' Constantes para el tipo de "teclas" aceptadas por el TextBox
Public Enum etbEx
    etbSoloNumeros = 1
    etbSoloLetras = 2
    etbMayusculas = 4
End Enum

Private m_TipoDatos As etbEx

' Este será el único evento de esta clase
Public Event KeyPress(KeyAscii As Integer)


Private Sub unTextB_GotFocus()
    ' Seleccionar todo el texto
    ' Hay que indicar el nombre de la variable
    With unTextB
        .SelStart = 0
        .SelLength = Len(.Text)
    End With
    
End Sub


Private Sub unTextB_KeyPress(KeyAscii As Integer)
    If m_TipoDatos And etbSoloLetras Then
        ' Aceptar sólo letras
        ' o lo que es lo mismo, no aceptar números
        If KeyAscii >= Asc("0") And KeyAscii <= Asc("9") Then
            KeyAscii = 0
        End If
    ElseIf m_TipoDatos = etbSoloNumeros Then
        ' Aceptar sólo números (o casi)
        If KeyAscii > Asc("9") Then
            KeyAscii = 0
        End If
    End If
    
    If m_TipoDatos And etbMayusculas Then
        ' Convertir las letras a mayúsculas,
        ' con esto cubrimos todas las letras
        If KeyAscii >= Asc("a") And KeyAscii <= 255 Then
            KeyAscii = Asc(UCase$(Chr$(KeyAscii)))
        End If
    End If
    
    ' Lanzamos el evento después de haber filtrado la tecla
    RaiseEvent KeyPress(KeyAscii)
End Sub


Public Property Get TipoDatos() As etbEx
    TipoDatos = m_TipoDatos
End Property

Public Property Let TipoDatos(ByVal NewValue As etbEx)
    m_TipoDatos = NewValue
End Property

Public Sub Create(unTextBox As Object)
    ' Asignar el textbox a la variable interna
    
    ' Sólo aceptamos TextBoxes
    If TypeOf unTextBox Is TextBox Then
        Set unTextB = unTextBox
    Else
        ' Error... Type Mismatch
        Err.Raise 13, "cTextBEx::Create", "Type Mismatch" & vbCrLf & "El objeto debe ser del tipo TextBox"
    End If
End Sub

Este otro código lo tendrás que pegar en el formulario:

'
Option Explicit

'Private WithEvents mTextClase As cTextBEx
' También podemos declararla de forma normal
Private mTextClase As cTextBEx


Private Sub Form_Load()
    ' Creamos una nueva instancia de la clase
    ' La forma de crearla es la misma con o sin WithEvents
    Set mTextClase = New cTextBEx
    
    With mTextClase
        ' Asignamos el textbox que queremos mejorar
        .Create Text1

        ' Admitir sólo letras
        '.TipoDatos = etbSoloLetras
        ' Admitir sólo números
        '.TipoDatos = etbSoloNumeros
        ' Convertir las letras en mayúsculas
        '.TipoDatos = etbMayusculas
        
        ' Admitir sólo letras y convertirlas a mayúsculas
        .TipoDatos = etbMayusculas + etbSoloLetras
    End With
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Set mTextClase = Nothing
End Sub

Fíjate que en el formulario no he declarado la clase cTextBEx con WithEvents, aunque podría haberlo hecho, pero sólo hubiese mostrado un evento: el que se ha declarado en la propia clase...

Sin embargo, en el código de la clase si que he creado una variable WithEvents del tipo TextBox, ya que esa es la intención de esa clase.

Por supuesto, si quisieramos usar esta clase como "sustituto" de un TextBox habría que añadir las propiedades y métodos propios de un TextBox, además de los de nuestra cosecha, como en este caso he hecho con Create y TipoDatos.
Pero creo que para esos casos es mejor crear un control ActiveX, ya que supone menos trabajo... aunque, (que esto quede entre nosotros), yo tengo algunas clases que uso para sustituir controles a las que he añadido las propiedades y métodos que "normalmente" suelo usar...

¿Que quieres un ejemplo de esto que digo?
Vale.
Añade esto al módulo de clase:

'
Public Property Get Text() As Variant
    ' Devolver el contenido de la propiedad Text del TextBox
    Text = unTextB.Text
End Property


Public Property Let Text(ByVal NewValue As Variant)
    ' Asignar el nuevo valor de la propiedad Text
    unTextB.Text = NewValue
End Property

Y esto otro en el evento Load del formulario, después de la asignación de .Create, ya que hasta que no se llama al método Create, no hay ningún TextBox que mejorar...


    .Text = "Hola radiola"

 

Si quieres tener más propiedades y métodos en la clase que sean aplicables al control TextBox, tendrás que añadirlas manualmente, ya que no te servirá el Wizard para creación de controles... ¡porque no tienes ningún control de usuario en el proyecto!, pero siempre lo harás "delegando" en el propio control... tal y como se muestra en el ejemplo.

Bueno, espero que con estos ejemplos te haya quedado más o menos claro cómo usar WithEvents para mejorar controles.

Te aconsejo que pruebes con otros tipos de controles e incluso con formularios... dentro de otro formulario... si no te sale nada que te satisfaga... al menos te distraerás... je, je.

Nos vemos.
Guillermo

Nerja, 14 de Julio de 1999

 


la Luna del Guille o... el Guille que está en la Luna... tanto monta...