Agrupar un código que se repite en un módulo

Tengo este código en un formulario que lo repito en cada evento Al presionar una tecla de varios controles, para que me salte un mensaje cuando esté protegido:

Private Sub CodDeposito_KeyPress(KeyAscii As Integer)
  If KeyAscii = 9 Then Exit Sub
    If CodDeposito.Locked Then
        MsgBox "Este campo está bloqueado.", vbInformation, "Ha habido un error"
    End If
End Sub

He probado a pasarlo a un módulo, y llamarlo desde el evento Al presionar una tecla del formulario, pero no funciona.

¿De qué otra forma puedo reducir todo este código repetido?

2 Respuestas

Respuesta
2

Diego: Evidentemente el camino es el de hacer una Función personalizada.

Para ello has de provocar un Evento al abrir o cargar el Formulario, que alcance a los Controles que tu necesites.

Una forma que a mi me parece buena, aunque el Evento no sea el mismo que tu busca es un ejemplo antiguo de Marciano Almohalla, que puedes encontrar en >>

http://www.mvp-access.es/marciano/#Ejemplos 

El ejemplo se llama Ayudas Emergentes. La metodología va por ahí, aunque debes adaptar el Evento. Un saludo >> Jacinto

Muchas gracias. Investigaré por ahí. Un saludo.

Diego: Una vez que tienes la herramienta para aplicarla en otras situaciones, en él caso concreto de aviso de bloque, puedes hacer algo simple y parecido a >>

Function AvisoDeBloqueo(Frm As Form)
On Error Resume Next
Dim Ctrl As Access.Control
For Each Ctrl In Frm.Controls        
     If Ctrl.Locked = True Then
         Ctrl.OnKeyPress = "=LanzaMensaje('" & Frm.Name & "','" & Ctrl.Name & "')"
     End If        
Next Ctrl
End Function

La Función LanzaMensaje >>

Function LanzaMensaje(NombForm As String, NombControl As String)
MsgBox "Este control esta Bloqueado y no lo puedes modificar", vbCritical, "CONTROL BLOQUEADO"
End Function

Y en el Open delFormulario:

Private Sub Form_Open(Cancel As Integer)
Call AvisoDeBloqueo(Me)
End Sub

No creo que me deje algo. Un saludo >> Jacinto

He dicho de investigarlo porque no sabe qué evento era. Ahora ya lo sé: OnKeyPress. Ahora bien, dos cosas:

  1. Pensaba hacer más o menos lo que me has pasado. He probado lo que me has dicho, pero da error: me dice que no admite la propiedad este código Ctrl.Locked = True. He probado también Frm.Controls(Ctl.Name).Locked, y da el mismo error.
  2. OnKeyPress es para cuando presionas una tecla. ¿Cuál sería para mostrar el mismo mensaje en caso de hacer clic con el mouse?

¡Muchas gracias por las molestias!

Diego: Las Etiquetas por ejemplo no tienen ese Evento y me imagino que de ahí viene el Error.

No obstante si has puesto "exactamente" el código que te he enviad, no debería de ocurrir, porque ahí está la razón del >>

On Error Resume Next

En caso de que siga dándote el Error así, me comentas y probaría esas líneas de código

Sobre 2 >> OnClick y el doble Click >> OnDblClick

Un saludo >> Jacinto

Hola, Jacinto. Me funciona este código, pero a medias:

Function AvisoDeBloqueo(Frm As Form)
On Error Resume Next
     If Frm.ChkBloquear = -1 Then
        Dim Ctrl As Access.Control
        For Each Ctrl In Frm.Controls
            Ctrl.OnKeyPress = "=LanzaMensaje('" & Frm.Name & "','" & Ctrl.Name & "')"
        Next Ctrl
    End If
End Function

Como ves, he saltado el fallo poniendo lo que tú dices pero haciendo referencia al botón que tengo para bloquear, en vez de comprobar si el campo está bloqueado, que daba error.

Te comento los dos fallos:

  1. Tengo un formulario donde puedo pasar de un registro a otro (no es un formulario continuo). Cuando estoy en un registro bloqueado, funciona. Sin embargo, cuando me muevo a uno sin bloquear, me sigue saliendo el mensaje. De ahí que haya movido el If al principio.
  2. No me coje el evento OnClick. OnKeyPress es por si presiono alguna tecla en combos y campos de texto, y si hago click es para checkboxes protegidos.

¡Gracias!

Sobre el punto 1. He llamado a la función pública desde form_current, pero sigue saliendo el mensaje, de ahí que pregunte.

Estoy haciendo pruebas. El problema está en el código LanzaMensaje. Cuando llegas a un registro donde Bloquear = 0 (los registros no están activos), si analizo el código por puntos de interrupción no arranca la función AvisoDeBloqueo, porque no cumple las condiciones. Sin embargo, sí que lanza la función LanzaMensaje. ¿Cómo puedo pausar eso? Por más que lo intento, no doy con la solución.

Ahora veo tus mensajes y hay una mezcla de elementos que debo mirar, porque anoche para asegurarme, probé las líneas de código (para lo que está concebido) y no tuve ningún problema. El Evento Onclick debe tomarlo si se cumplen las condiciones para que lo haga.

A primera vista, cuando activa elEvento una vez queda activado. Además no te limitas a los controles bloqueados como era la petición original, sino que el Evento se lo estás programando a todos, excepto evidentemente a los que no lo admiten. Le daré una ojeada, pero no te prometo que sea hoy. En todo caso para pruebas yo dejaría la función Original y modificaría la de lanzar el mensaje >>

Function LanzaMensaje(NombForm As String, NombControl As String)
Dim ElFormOrigen As Access.Form
Set ElFormOrigen = Forms(NombForm)
If ElFormOrigen.ChkBloquear = -1 Then
     MsgBox "Este control esta Bloqueado y no lo puedes modificar", vbCritical, "CONTROL BLOQUEADO"
End If
Set ElFormOrigen = Nothing
End Function

Si cubre la necesidad que tenías me comenta para no ocupar tiempo.Un saludo >> Jacinto

Ese código que me has pasado funciona como quiero. Lo que no va es el evento OnClick.

Function AvisoDeBloqueo(Frm As Form)
On Error Resume Next
        Dim Ctrl As Access.Control
        For Each Ctrl In Frm.Controls
            If FName.ChkBloquear = -1 Then
                Ctrl.OnClick = "=LanzaMensaje('" & Frm.Name & "','" & Ctrl.Name & "')"
            End If
        Next Ctrl
End Function

¡Gracias!

Diego: He probado éste código que te adjunto, incluyendo un CheckBox con el Nombre que tu usas y me responde perfectamente.

Function AvisoDeBloqueo(Frm As Form)
Dim Ctrl As Access.Control
On Error Resume Next
For Each Ctrl In Frm.Controls    
   'Ctrl.OnKeyPress = "=LanzaMensaje('" & Frm.Name & "','" & Ctrl.Name & "')"
    Ctrl.OnClick = "=LanzaMensaje('" & Frm.Name & "','" & Ctrl.Name & "')"    
Next Ctrl
End Function
'Ahora la Función del Mensaje
Function LanzaMensaje(NombForm As String, NombControl As String)
Dim ElFormOrigen As Access.Form
Set ElFormOrigen = Forms(NombForm)
If ElFormOrigen.ChkBloquear = -1 Then
            MsgBox "Este control esta Bloqueado y no lo puedes modificar", vbCritical, "CONTROL BLOQUEADO"
End If
Set ElFormOrigen = Nothing
End Function

No entiendo la razón por la que la llamada la haces desde el Form_Current(), puesto que el Evento se programa una sola vez. Yo no lo he movido del Form_Open.

Quizá te confunde que no se active el "Mensaje" cundo pulsas en un ComboBox y es natural que no lo haga porque el Evento Click de ese control se activa después de desplegar y justo cuando pulsas un valor. En un Botón es el primero y en TextBox va inmediatamente después del GotFocus. Dale una mirada, si quieres y no lo has hecho, claro está, a la sucesión de Eventos en Formularios, Informes y Controles.

https://support.office.com/es-es/article/orden-de-eventos-para-objetos-de-base-de-datos-e76fbbfe-6180-4a52-8787-ce86553682f9#bm1 

Un saludo >> Jacinto

Hola, Jacinto. Lo entiendo perfectamente. Sin embargo, creo OnClick que no es el evento que estoy buscando, sino este:

Private Sub CodFormaPago_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If KeyAscii = 9 Then Exit Sub
        If CodFormaPago.Locked Then
            MsgBox "Este campo está bloqueado.", vbInformation, "Ha habido un error"
        End If
End Sub

Es decir, MouseDown.

¡Gracias!

Es decir, me funciona, pero no como debería, y creo que es debido al tipo de evento que estoy buscando. ¿Me explico?

Gracias.

Ya está. Al final esto es lo que me ha funcionado.

Function AvisoDeBloqueo(Frm As Form)
Dim Ctrl As Access.Control
On Error Resume Next
For Each Ctrl In Frm.Controls
    If Ctrl.Name <> "ChkBloquear" Then
        If Frm.ChkBloquear = -1 Then
            Ctrl.OnKeyPress = "=LanzaMensaje('" & Frm.Name & "','" & Ctrl.Name & "')"
            Ctrl.OnMouseDown = "=LanzaMensaje('" & Frm.Name & "','" & Ctrl.Name & "')"
        End If
    End If
Next Ctrl
End Function
Function LanzaMensaje(NombForm As String, NombControl As String)
Dim ElFormOrigen As Access.Form
Set ElFormOrigen = Forms(NombForm)
If ElFormOrigen.ChkBloquear = -1 Then
     MsgBox "Este control esta Bloqueado y no lo puedes modificar", vbCritical, "CONTROL BLOQUEADO"
End If
Set ElFormOrigen = Nothing
End Function

Muchas gracias por la ayuda, Jacinto.

Un saludo.

Perfecto Diego. Me alegra que lo hayas resuelto.

POr cierto, hace unos días estuve tomando café en el Casablanca y me acordé de ti, pero no tenía el ordenador conmigo. Te hubiera puesto un correo . Ya no ando por esas tierras

Un saludo >> Jacinto

Joe, me hubiera gustado conocerte. Mándame tu correo electrónico, y te mando mi móvil para la próxima vez que vuelvas.

Una última cosa. Necesito pasar por argumentos de la funciónel campo Bloquear en la función LanzaMensaje:

Function LanzaMensaje(NombForm As String, NombControl As String)
Dim ElFormOrigen As Access.Form
Set ElFormOrigen = Forms(NombForm)
If ElFormOrigen.ChkBloquear = -1 Then
     MsgBox "Este control esta Bloqueado y no lo puedes modificar", vbInformation, NombreBD
End If
Set ElFormOrigen = Nothing
End Function

El motivo es poder usarlo con un subformulario. Ese botón Bloquear está en el formulario principal, y tiene que hacer referencia a él de la siguiente forma Forms![F10TPV]!Form!TChkBloquear. ¿Cómo lo tendría que poner?

¡Gracias!

Diego: Esto último no acabo de entenderlo bien, e interpreto que lo que pretendes es que te lance el Mensaje, desde los Controles del SubFormulario. Entonces el Formulario llamante debe ser el SubFormulario y el código te va a cambiar un poco (o un bastante según lo mires). En el Ejemplo que te recomendé hay también una opción de activación de Evento desde SubFormulario. Un saludo >> Jacinto

Lo que quiero es que, en vez de 

ElFormOrigen.ChkBloquear

Pueda poner algo así:

Function LanzaMensaje(NombForm As String, NombControl As String, Optional SubFormulario As String)
Dim ElFormOrigen As Access.Form
Set ElFormOrigen = Forms(NombForm)
If SubFormulario = -1 Then
     MsgBox "Este control esta Bloqueado y no lo puedes modificar", vbInformation, NombreBD
End If
Set ElFormOrigen = Nothing
End Function

Y en la llamada, donde el argumento Subformulario --> Forms![F10TPV]!Form!TChkBloquear.

Gracias

Diego: Lo miro y te comento porque ando un poco liado. Un saludo >> Jacinto

He probado con esto, que es como lo hace el ejemplo que me pasaste. No me termina de funcionar. Échale tú un vistazo, porque no sé dónde puede estar mi error. No me corre prisa, cuando puedas. Muchas gracias.

Function AvisoDeBloqueo(Frm As Form)
Dim Ctrl As Access.Control
On Error Resume Next
For Each Ctrl In Frm.Controls
    If Ctrl.Name <> "ChkBloquear" Then
        If Ctrl.ControlType <> acCommandButton And Ctrl.ControlType <> acLabel Then
            If Frm.ChkBloquear = -1 Then
                Ctrl.OnKeyPress = "=LanzaMensaje('" & Frm.Parent.Name & "','" & Ctrl.Name & "','" & Frm.Name & "')"
                Ctrl.OnMouseDown = "=LanzaMensaje('" & Frm.Parent.Name & "','" & Ctrl.Name & "','" & Frm.Name & "')"
            End If
        End If
    End If
Next Ctrl
End Function
Function LanzaMensaje(NombForm As String, NombControl As String, Optional Subformulario As String)
Dim ElFormOrigen As Access.Form
    If IsNull(Subformulario) Or Subformulario = "" Then
        Set ElFormOrigen = Forms(NombForm)
    Else
        Set ElFormOrigen = Forms(NombForm).Controls(Subformulario).Form
    End If
    If ElFormOrigen.ChkBloquear = -1 Then
         MsgBox "Este control está bloqueado y no lo puedes modificar", vbInformation, NombreBD
    End If
Set ElFormOrigen = Nothing
End Function

Diego: Te he preparado un ejemplo para no seguir alargando el Post porque al final cualquier usuario se le va a hacer muy largo y la ayuda perderá su esencia.

http://www.mediafire.com/file/7ra0v6y0pi3db1f/ActivaEventosEnFormSubForm.rar/file 

Ve añadiendole alguna Opción que necesites, tal como el tipo de controles y lo vas adaptando de forma más generalizada o concreta. Incluso no vas a cargar una BD por hacer alguna función más aplicable a una necesidad concreta. Un saludo >> Jacinto

Está bien. Falta este código en el ejemplo:

Function LanzaMensaje(NombForm As String, NombControl As String, Optional Subformulario As String)
Dim ElFormOrigen As Access.Form
    If IsNull(Subformulario) Or Subformulario = "" Then
        Set ElFormOrigen = Forms(NombForm)
    Else
        Set ElFormOrigen = Forms(NombForm).Controls(Subformulario).Form
    End If
    If ElFormOrigen.ChkBloquear = -1 Then
         MsgBox "Este control está bloqueado y no lo puedes modificar", vbInformation, NombreBD
    End If
Set ElFormOrigen = Nothing
End Function

La razón es simple: porque si no, te salta el mensaje en los registros no protegidos.

Ahora bien, hay algo ahí que me da error, y a Marciano Almohalla no lo sé. Es:

Set ElFormOrigen = Forms(NombForm).Controls(Subformulario).Form. Me dice que no encuentra el campo F10TPVSubformulario. Obviamente, porque no es ese el nombre del subformulario en el formulario principal, que es TPVSubformulario. ¿Me explico? Donde falla es en Controls(Subformulario), que debe coger el nombre del objeto del formulario principal.

¡Mil gracias, y disculpa que esto se haya alargado!

Diego: Algo hay que no acabo de entender y posiblemente eso contribuye a seguir alargando el contenido del Post. Cuando el Chech del Formulario en el ejemplo está desactivado el mensaje no se activa en el Formulario principal ni en el Sub Formulario. Entonces, si es que no tienes datos personales o confidenciales en tu base de datos, quizá es mejor que me la enviaras por email con una breve explicación. Si es que tienes ese tipo de datos puedes aislar los objetos afectados (y su entorno de Tablas, consultas etc, para evitar errores,) con algunos datos inventados y miramos de cerrar el tema. Un saludo >> Jacinto

Respuesta
1

Veo que te están dando mejores opciones que repetir la macro je je, pero si te sirve de algo aquí te la dejo un poco más reducida

Private Sub CodDeposito_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
If Not KeyAscii = 9 And CodDeposito.Locked = True Then
MsgBox "Este campo está bloqueado.", vbInformation, "Ha habido un error"
End If
End Sub
La pregunta no admite más respuestas

Más respuestas relacionadas