VBA: nuestro módulo punto
15/01/2022Diseño: aplicar transparencia
16/01/2022Con éste artículo empiezo a reciclar varios de ellos escritos hace más de una década y que hoy en día siguen siendo válidos. Sólo hay que cambiar alguna cosilla específica de la versión del momento, aunque en esta ocasión he optado por no cambiar nada, salvo un poco título y dejar lo demás íntegro.
El artículo original está en https://geeks.ms/access/evento-notinlist-en-access-2007/
Evento NotInList en Access 2007
En Access 2007, el evento NotInList puede funcionar exactamente igual que en versiones anteriores, pero dos nuevas propiedades de los cuadros combinados y listas, Permitir ediciones de la lista de valores y Formulario de edición de la lista, pueden hacer innecesario escribir una sola línea de código para este evento. Fue empezar a escribir estas líneas antes de las vacaciones y verme explicando en algún foro a algún no tan principiante cómo se utiliza NotInList, así que no está de más empezar repasando la manera más canónica de usarlo, pues aún hay gente que no lo entiende y se complica haciendo cosas raras; luego contaremos como, modificando un par de propiedades, en Access 2007 puede ser innecesario
El evento NotInlist en cualquier versión de Access
Manejar el evento NotInList suele resultar complicado a los principiantes. A pesar de su simplicidad aparente, se manejan algunos conceptos con los que posiblemente no estén familiarizados.
Aunque esté claramente explicado en la ayuda, suele obviarse que el evento NotInList cuenta con dos parámetros con un cometido muy específico: NewData nos proporciona el valor que hemos introducido y que no está en la lista y Response espera que le demos un valor de entre una serie de opciones (acDataErrDisplay , acDataErrContinue o acDataErrAdded) para que la aplicación actúe en consecuencia, mostrando mensaje de error o no o aceptando el nuevo valor y haciendo un requery del combo.
A veces no basta con meter un dato directamente a una tabla, sino que es necesario abrir un formulario para añadir ese y otros datos. La cuestión aquí es cómo esperar a que se introduzca, o no, el nuevo dato y luego darle el valor apropiado al parámetro Response. Es fácil si se tienen las claves:
Si al abrir un formulario DoCmd.Openform utilizamos la constante acDialog en el parámetro WindowMode, éste se abrirá en modo diálogo, de manera que cualquier otro código se detiene hasta que cerremos el formulario.
DoCmd.OpenForm “Detalles de clientes”, , , , acFormAdd, acDialog
Ahora, el problema está en pasar información entre el formulario que está abierto y el que ha detenido el código hasta que se cierre el otro. A mí me gusta dimensionar una variable como pública en la sección de declaraciones del formulario que contiene el cuadro combinado. Al declararla como pública será accesible desde cualquier lugar de la aplicación, como si fuera una propiedad del formulario, con la ventaja de que morirá con el formulario. Podemos asignarle un valor desde el formulario abierto en modo diálogo y luego comprobarlo al cerrar éste.
El código completo en el formulario del evento NotInList sería el siguiente:
Option Compare Database
Option Explicit
Public Respuesta As Integer
Private Sub Id_de_cliente_NotInList(NewData As String, Response As Integer)
DoCmd.OpenForm "Detalles de clientes", , , , acFormAdd, acDialog, NewData
Response = Me.Respuesta
End Sub
Y, en el formulario diálogo, bastaría con una cosa así:
Private Sub cmdAceptar_Click()
Forms!Pedidos.Respuesta = acDataErrAdded
End Sub
Private Sub cmdCancelar_Click()
Forms!Pedidos.Respuesta = acDataErrContinue
End Sub
Es decir, al Aceptar o Cancelar, damos a la variable pública Respuesta del primer formulario el valor que luego tomará Response.
Normalmente, querremos que en el formulario de edición ya se haya insertado el nuevo valor introducido en la lista en su cuadro de texto correspondiente. Para eso, en el último parámetro de la instrucción Docmd.OpenForm, OpenArgs, he pasado el valor de NewData:
DoCmd.OpenForm “Detalles de clientes”, , , , acFormAdd, acDialog, NewData
En el formulario para añadir el nuevo dato comprobamos si estamos en un nuevo registro y si hemos pasado algún valor en OpenArgs, en cuyo caso, nos posicionamos en el control correspondiente con SetFocus y ponemos en la propiedad Text el valor que hemos recibido en OpenArgs.
Option Compare Database
Option Explicit
Private Sub Form_Load()
If Me.NewRecord And Nz(Me.OpenArgs, "") <> "" Then
Me.Apellidos.SetFocus
Me.Apellidos.Text = Me.OpenArgs
End If
End Sub
El Evento NotInlist en Access 2007
En Access 2007, dos nuevas propiedades de los cuadros combinados y listas, “Permitir ediciones de la lista de valores” y “Formulario de edición de la lista”, pueden suplir al evento NotInlist.
Propiedad Permitir ediciones de la lista de valores
Si el Tipo de origen de la fila es Lista de valores y el cuadro combinado o lista tiene una sola columna, si establecemos el valor de la propiedad Permitir ediciones de la lista de valores a Sí, podremos modificar sus valores en tiempo de ejecución. Tenemos dos posibilidades:
Editar directamente la lista
Al desplegar un cuadro combinado o lista que tenga Permitir ediciones de la lista de valores, se muestra al final de la lista un icono flotante.
Si pulsamos sobre el icono, se despliega un formulario para editar los valores de la lista, incluso podemos editar el valor predeterminado.
Funciona de la misma manera que el evento NotInList, de hecho, en primer lugar se dispararía ese evento. Es decir, si la propiedad Limitar a Lista es Sí e introducimos en ella un valor inexistente, Access 2007 nos informará de que no existe el valor y nos preguntará si deseamos modifcar los elementos de la lista, en cuyo caso nos abriría el mismo formulario para editar valores que en el caso anterior.
Ambas posibilidades sólo funcionan si la lista o cuadro combinado sólo tiene una columna. Si tiene más de una columna, tendríamos que recurrir a los mismos métodos de versiones anteriores.
Propiedad Formulario de edición de la lista
La propiedad Formulario de edición de la lista indica el nombre del formulario que queremos usar para editar los valores de un cuadro combinado o lista cuando cuando la propiedad “Tipo de origen de la fila” es Tabla o Consulta.
Lo mismo que veíamos cuando el tipo de origen de la fila era “Lista de valores”, podemos editar los valores en tiempo de ejecución, bien pulsando directamente sobre el icono flotante al final de la lista desplegada, bien al introducir un valor que no existe; la diferencia es que el formulario de edición será uno que nosotros hayamos creado para editar la tabla subyacente al combo o lista.
Nuestro formulario se abrirá en modo diálogo (no necesariamente emergente) deteniendo la ejecución del código de los demás formularios. Al cerrarse, si se han modificado los datos, se actualizará el origen de datos del combo o lista. y si el texto que habíamos introducido coincide con un nuevo valor, se dará por válido y no se producirá error. O sea, más o menos lo que nosotros habríamos hecho editando el evento NotInList.
Añadiendo un poco de código
Pero este formulario se comportará exactamente igual si hemos pulsado el icono flotante para editarlo que si se ha abierto al no estar en la lista, es decir, se abre en modo edición en el primer registro. Seguramente querremos que se comporte como hemos hecho mediante código en versiones anteriores, o sea, que vaya directamente a un registro nuevo y que posicione en el cuadro de texto correspondiente el valor que hemos introducido en la lista ¿Cómo conseguimos esto? Tendremos que usar un mínimo de código.
Si en el formulario de edición de la lista ponemos el siguiente código:
Private Sub Form_Load()
Debug.Print Me.OpenArgs
End Sub
Al no estar en lista, en la venta de inmediato del editor de VBA nos encontraremos algo así:
[Detalles de pedidos de compra]![Supplier ID]=Ramirez
Es decir, que al abrirse el formulario el formulario de edición de la lista, sin necesidas de ninguna intervención por nuestra parte, Access 2007 ha pasado un argumento OpenArgs con el nombre del formulario y el del cuadro combinado o de lista y el valor que hemos dado a éste. Podemos utilizar OpenArgs para, si existe, ir a un registro nuevo y rellenar el cuadro de texto correspondiente:
Private Sub Form_Load()
Dim v As Variant
If Nz(Me.OpenArgs, "") <> "" Then
If InStr(Me.OpenArgs, "=") <> 0 Then
v = Split(Me.OpenArgs, "=")
DoCmd.GoToRecord , , acNewRec
Me.Apellidos.SetFocus
Me.Apellidos.Text = v(1)
End If
End If
End Sub
Pero ¿Qué pasa con el evento NotInlist en Access 2007?
Podemos usar el evento NotInList junto con la propiedad Formulario de edición de la lista. En primer lugar se disparará el evento y luego, dependiendo del valor que en éste demos a Response, se abrirá automáticamente, o no, el formulario de edición de la lista.
Posdata
Cuando explicaba, en 2007, el tratamiento del evento en cualquier versión de Access, dije que “A mí me gusta dimensionar una variable como pública en la sección de declaraciones del formulario que contiene el cuadro combinado.”. Hoy, en 2022, ya no uso ese método. Cuando quiero recuperar la respuesta de un formulario abierto como diálogo, lo que uso es una variable TempVars con el mismo nombre del formulario, para evitar confusiones, y, luego el el formulario llamador, tomo el valor de esa TempVar y luego la elimino.
Por ejemplo, al pulsar Aceptar en el formulario diálogo, pongo algo así:
TempVars!frmMiFormulario = MiValor
Luego, desde el formulario que ha abierto el diálogo, tomo el valor y borro la TempVar. Algo así:
Valor = TempVars!frmMiFormulario
TempVars.Remove “frmMiFormulario”
TempVars no necesita declaración y, como es Variant, puedo darle el valor que quiera.