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
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
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:
- 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.
- 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:
- 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.
- 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.
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
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
- Compartir respuesta
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
- Compartir respuesta