TRUCOS ACCESS

TRUCOS SCRIPTS

TRUCOS
 

Trucos Access


4.- Formularios

4.1.- Numeración correlativa automática sin campo autonumérico

Supongamos una tabla llamada Clientes con varios campos, de los cuales uno es numérico entero largo llamado NumCliente, estableciendo que el campo sea indexado sin duplicados o bien clave principal.
En el evento Al activar registro del formulario de entrada de datos para esa tabla, insertar el siguiente código:
On Error GoTo err_Form_Current

If [NumCliente] < 1 Then
[NumCliente] = DMax("NumCliente", "Clientes") + 1
End If

exit_Form_Current:
Exit Sub

err_Form_Current:
If Err = 94 Then 'Uso no válido de Null
Resume Next
Else
MsgBox Error$
Resume exit_Form_Current
End If

En la propiedad Punto de tabulación del campo NumCliente, dentro de formulario, establecer su valor a No, ya que será un campo que no hay que rellenar manualmente.
Ha sido absolutamente necesario incluir las líneas que hacen referencia al error nº 94 (uso no válido de Null) debido a que la primera vez que se accede al formulario para introducir datos, se producirá dicho error al no existir registros. Con esas líneas de código se evita que aparezca dicho error, ya que la línea On error goto... envía el flujo de la ejecución a la parte del código donde se detecta y se envía de nuevo el flujo de ejecución a la línea siguiente, excepto en el caso de producirse un error diferente, en cuyo caso se mostraría el error producido gracias a las líneas que siguen a Else.

4.2.- Ejecutar programas externos desde un formulario

Crear un botón en el formulario con la herramienta al efecto y, justo en el momento de aparecer la primera pantalla del asistente, cancelar el proceso. De esta forma, el botón queda creado aunque sin código asociado. Acceder a las propiedades del botón y, dentro del evento Al hacer clic, insertar esta línea de código:
Shell ("Ruta\Programa.exe Parámetros")
donde Ruta\ es la ruta de acceso al programa a ejecutar, Programa.exe es el nombre del ejecutable con su extensión, y Parámetros se refiere a los posible parámetros que lleva aparejados el programa ejecutado, siendo por tanto opcional. Si hay más de un parámetro, se separan con un espacio. Si, por ejemplo, se quisiera hacer una copia comprimida con el programa compresor Winzip de una base de datos, una forma sería así:
Shell ("c:\winzip\winzip32.exe -a c:\destino\copia c:\personal\access\database.mdb")
Aquí se puede ver que Winzip (cuya ruta de acceso en este caso sería C:\WINZIP y su ejecutable es WINZIP32.EXE) emplea 3 parámetros: -a para indicar que debe comprimir, luego viene la ruta de destino con su nombre final de archivo y en tercer lugar la ruta de origen con el nombre de la base de datos a comprimir. Si las rutas o los archivos tienen nombre largo, lo aconsejable es emplear en esta situación siempre el nombre corto, cuestión que se debe comprobar previamente accediendo a una sesión MS-DOS para listar directorios y archivos.
El ejemplo anterior haría que se comprimiera una base de datos llamada DATABASE.MDB ubicada en C:\PERSONAL\ACCESS en la carpeta C:\DESTINO y bajo el nombre COPIA.ZIP.
Por supuesto, esta línea de código se puede asociar a cualquier otro tipo de evento y a otro tipo de control. Por ejemplo, se podría ejecutar algo al cargar el formulario o al actualizar un determinado campo.
Otro caso que se puede dar es el de ejecutar comandos internos del DOS, como COPY. Imaginemos que se desea ejecutar la orden COPY ARCH1 C:\TEMP. En estos casos hay que hacerlo de la siguiente manera:
Shell (Environ("comspec") & " /c copy arch1 c:\temp", 1)
Esto es así porque hay que ejecutar el procesador de comandos del DOS (COMMAND.COM), el cual está definido por la variable de entorno comspec.
Algunos comandos internos del DOS están emulados con órdenes directas de Access. Tal es el caso de RMDIR, CHDIR, MKDIR y DIR(). Este último se diferencia del comando del DOS en que no devuelve carpetas, sino sólamente nombres de archivo y tampoco lista los que tengan atributos de oculto y de sistema.

4.3.- Añadir un botón de automarcado

Si alguna vez se necesita llamar a alguien por teléfono mientras se está una base de datos, he aquí cómo. Desde el modo Diseño del formulario, hacer clic sobre el icono del asistente de botones de comando en la caja de herramientas. Seleccionar Otros en la ventana Categorías y Automarcador en la ventana Acciones. Hacer clic en Siguiente, elegir una imagen o texto para el botón y hacer clic en finalizar, después cambiar al modo Formulario y probar el botón. Poner el cursor en el campo de número de teléfono del formulario, hacer clic en el botón recién creado, y cuando el diálogo de Marcado telefónico automático aparezca, elegir Aceptar.
Cuando suene el teléfono, descolgar y hacer clic en el botón de hablar en la ventana de diálogo de Marcado telefónico automático.

4.4.- Imprimir el registro actual

· Imprimir el registro actual no debería ser tan pesado. Y no lo será una vez que se añada este botón a los formularios. Ya no habrá que merodear con el ratón por los menús Editar y Archivo o por la opción Registros seleccionados en el cuadro de diálogo Imprimir.
· Abrir el formulario en modo de diseño.
· Asegurarse de pulsar el botón de control de asistentes en la caja de herramientas.
· Hacer clic sobre el botón comando en la caja de herramientas.
· Al pulsar en el lugar en el que quiere el nuevo botón, el asistente del botón de comando empezará a ejecutarse.
· En la lista Categorías del cuadro de diálogo del asistente, hacer clic sobre Operaciones con registros, y después en la lista Acción.
· Hacer clic sobre Imprimir registro.
· Pulsar el botón Siguiente y añada texto o una imagen al botón.
· Hacer clic sobre Finalizar y después elegir Formulario del menú Ver y probar su nuevo botón.

4.5.- Evitar datos duplicados en el mismo campo

Aunque Access diga, al introducir datos en un campo clave principal en un nuevo registro, que ya existe en el campo clave principal de otro registro, avisa del error después de que ya se ha producido, obligando a introducir todos los campos del registro duplicado hasta el final. Sin embargo, existe un procedimiento mediante el cual Access puede avisar de la duplicidad nada más introducir el dato.
Lo primero es asegurarse de que el campo a comprobar está indexado y es clave principal. Supongamos una base de datos de pacientes que ingresan en un hospital y el objetivo es detectar que no se repita el dato introducido en el campo NumHistoria.
Abrir el formulario en vista Diseño, elegir Ver/Código e incluir en el apartado General/Declaraciones (General a la izquierda y Declaraciones a la derecha) el siguiente código:
Dim BaseDatos as DataBase
Dim Pacientes as Recordset

Con ello se define que van a utilizarse dos objetos DAO o de acceso a datos: una base de datos y un recordset y asegurando que serán visibles en todos los procedimientos del formulario.
En el evento Al cargar del formulario incluir estas líneas de código:
Set BaseDatos = CurrentDB()
Set Pacientes = BaseDatos.OpenRecordset("PacientesIngresados",dbOpenTable)

La primera línea asigna la base de datos actual a la variable BaseDatos, la segunda asigna a la variable Pacientes los registros existentes en la tabla Pacientes Ingresados de la base de datos BaseDatos, y la abre de tipo tabla, es decir, se va a poder leer de ella por índice, que será el que se indica con la siguiente instrucción que debe ir a continuación de las dos anteriores:
Pacientes.Index = "PrimaryKey"
En el evento Antes de actualizar de la variable NumHistoria incluir:
Sub NumHistoria_BeforeUpdate (Cancel as integer)
Pacientes.Seek "=", NumHistoria
If Not Pacientes.NoMatch then
Msgbox "Num. de historia ya existente.",48
Cancel = True
Exit Sub
End If
End Sub

La instrucción que contiene Seek (que es un método que sólo se puede utilizar con los Recordset abiertos con dbOpenTable), lo que hace es intentar encontrar en la tabla Pacientes alguno con el número de historia igual a la variable NumHistoria, y va a buscar en números de historia porque al cargar el formulario ya sabe que el índice iba a ser la clave principal, que hemos supuesto que va por Número de Historia.

4.6.- Incrementar y decrementar fechas

Una característica interesante es permitir que el usuario pueda incrementar y decrementar fechas pulsando sobre ellas las teclas (+) y (-). Para proporcionar esta característica se debe añadir el siguiente código al evento Al pulsar una tecla de los campos de tipo de fecha que existan en el formulario.
Select Case KeyCode
Case 107, 187
Screen.ActiveControl =
Screen.ActiveControl + 1
SendKeys "{Esc}"
Case 109, 189
Screen.ActiveControl =
Screen.ActiveControl - 1
SendKeys "{Esc}"
End Select

4.7.- Visualizar mensajes personalizados

El siguiente código permite ver mensajes en la barra de estado cuando el ratón se mueve sobre un objeto de un formulario (texto, botones, etc.). Son 2 subrutinas concatenadas y deben estar en un módulo para que sean accesibles globalmente.
Global StatusCalled
Global CurrentStatusMsg
Sub StatusBarMsg (StatusMsg)
If StatusMsg <> CurrentStatusMsg Then
Dim ss As Variant
ss= syscmd (SYSCMD_SETSTATUS, StatusMsg)
StatusCalled=True
CurrentStatusMsg=StatusMsg
End If
End Sub
Sub ClearStatusBarMsg ()
If StatusCalled Then
Dim ss As Variant
ss= Syscmd (SYSCMD_CLEARSTATUS)
StatusCalled= False
CurrentStatusMsg =" "
End If
End Sub

El siguiente código se debe añadir al evento Al mover el mouse del control sobre el que deseemos visualizar un mensaje en la barra de estado:
Sub CmdButton_MouseMove (Button As Integer, Shift As integer, x As
Single, Y As Single)
Status BarMsg "Su Mensaje Personalizado"
End Sub
El siguiente código se debe añadir al fondo del formulario para que se borre el mensaje cuando el ratón se mueva fuera del objeto.
Sub Detail0_MouseMove (Button As Integer, Shift As Integer, X As Single,
Y As Single)
ClearStatusBarMsg
End Sub

4.8.- Indicadores de progreso

Una manera de acceder a un indicador de progreso desde Access es hacer una llamada a SysCmd; no obstante, se puede crear uno usando dos etiquetas de manera sencilla y con la ventaja de obtener un mayor control sobre él.
· Primero, crear una etiqueta transparente con estilo hundido. La llamaremos Fondo.
· Segundo, crear otra etiqueta de idéntica altura que la anterior, con anchura cero y con bordes transparentes. Situarla justo alineada con la primera y enviarla al fondo. La llamaremos Indicador.
· Tercero, situar el siguiente código en un módulo del formulario e ir llamándolo pasando como parámetros el progreso actual y el progreso total.
Sub Actualiza (Actual, Total)
Dim Porcentaje as Single
Porcentaje = Actual / Total
Me!Fondo.Caption = Int(Porcentaje * 100) & "%"
Me!Indicador.Width =
CLng(Me!Fondo.Width * Porcentaje)
Select Case Porcentaje
Case Is < .15
Me!Indicador.BackColor = 255
Case Is < .50
Me!Indicador.BackColor = 65535
Case Else
Me!Indicador.BackColor = 65280
End Select
Me.Repaint
End Sub

4.9.- Forzar a que el valor introducido en un campo del formulario se quede como predeterminado para subsiguientes registros

Estando en modo de diseño del formulario, pulsar el botón de Código (o elegir Ver/Código). Si no se ha introducido nunca código, aparecerá sólo una o dos líneas con algo así:
Option Compare Database
Teclear en la línea siguiente:
Dim CampoTrabajo As String
Con ello se define un campo de trabajo para todo el formulario llamado CampoTrabajo y de tipo carácter; también se podría utilizar Integer, Long, Real, etc. ya que debe ser igual a como esté definido en la tabla de la base de datos.
Luego ir a la ventana de propiedades del Formulario, buscar el evento Después de actualizar, elegir Procedimiento de evento, pulsar después sobre el botón de los tres puntos, con lo cual se abre de nuevo la ventana de código, en este caso con tres líneas como las siguientes:
Private Sub Form_AfterUpdate()
End Sub
Entre ellas se tecleará:
CampoTrabajo = [Campo]

suponiendo que el campo que se desea que salga predeterminado sea Campo. Buscar después la propiedad Antes de insertar, seleccionar Procedimiento de evento, pulsar el botón de los tres puntos y aparecerá:
Private Sub Form_BeforeInsert(Cancel As Integer)
End Sub

Teclear entre ellas:
[Campo] = CampoTrabajo
Si este campo no es el primero del registro, cuando se introduzca el primer carácter en el siguiente registro aparecerá el valor en el campo deseado.
Nota:
Puede aparecer un problema al operar con el primer registro de la tabla, para lo cual hay dos posibilidades:
1) Permitir a [campo] longitud cero en sus propiedades dentro de la tabla.
2) En el código del evento Antes de insertar, en lugar de poner
[campo]=CampoTrabajo
poner:
If Len(CampoTrabajo) >0 Then
[campo] = CampoTrabajo
End If

4.10.- Manipular cadenas de texto

Una cuestión a controlar es la introducción de datos en una base de datos; por supuesto querremos que la base de datos controle en todo momento las características del texto introducido. Así se podrá forzar a que todo el texto se convierta en mayúsculas, minúsculas o tipo título. Se pueden utilizar características del formato como > para todo mayúsculas y < para minúsculas (por ejemplo, una máscara de entrada como >AAAAAAAA), pero ésta no es la solución ya que en las tablas se guarda tal y como se escribe.
A continuación se ofrecen unos códigos para facilitar la tarea; la forma de utilizarlos es colocarlos en el evento Después de Actualizar en las propiedades del campo, elegir Procedimiento de evento del menú desplegable y luego pulsar el botoncito de los puntos suspensivos para introducir este código:
Sub Campo_KeyPress(KeyAscii As Integer)
KeyAscii = Asc(Ucase(Chr(KeyAscii)))
End Sub
---------------
Sub Campo_AfterUpdate() ' Cambia el contenido a mayúsculas al salir del campo
[Campo] = Ucase ([Campo] )
End Sub
---------------
Sub Campo_AfterUpdate() ' Cambia el contenido a minúsculas al salir del campo
[Campo] = Lcase ([Campo] )
End Sub
---------------
Sub Campo_AfterUpdate() ' Cambia el contenido a primera letra mayúscula al salir del campo
Dim CadenA as String
CadenA = Lcase ([Campo] )
Mid ( CadenA, 1, 1 ) = Ucase ( Left ( CadenA, 1 ) )
[Campo] = CadenA
End Sub
---------------
Sub Campo_AfterUpdate() 'Pone en mayúscula la primera letra de cada palabra
Dim CadenA as String
Dim ANSI as Variant
Dim Numero as Integer
CadenA = Lcase ([Campo] )
Mid ( CadenA, 1, 1 ) = Ucase ( Left ( CadenA, 1 ))
For Numero = 2 To Len ( CadenA ) -1
ANSI = Asc ( Mid ( Cadena, Numero,1) )
If ANSI < 65 Or ANSI > 122 Or ( ANSI > 90 And ANSI < 97 ) Then
Mid ( CadenA, Numero + 1, 1 ) = Ucase ( Mid ( Cadena, _ Numero +1, 1) )
End If
Next Numero
[Campo] = Cadena
End Sub

También existe la posibilidad de guardar esto en un módulo y convertir estos procedimientos en funciones. Para ello pasaríamos a la función la cadena de texto como valor, que podría quedar:
Function Mayusculas ( ByVal Cadena As String ) As String

4.11.- Personalizar el título, el icono, el archivo de ayuda y la pantalla inicial de carga de una base de datos

Si se ha creado una base de datos con interfaz de usuario de modo que parezca una aplicación independiente, puede quedar más profesional cambiar estos valores. Esto se puede hacer en el archivo INI de Access. Sin embargo, si se hace esto, los cambios afectarán a todo lo que se cargue desde Access. Para que sólo afecte a un archivo en concreto, hay que crear un nuevo archivo INI para la aplicación deseada (por ejemplo, MIAPLIC.INI) y hacer uso de un parámetro en la línea de comandos de Access: /INI MIAPLIC.INI. El contenido de este archivo INI será según esta sintaxis:
[Run-Time Options]
TitleBar=Nombre que se desea que aparezca como título
Icon=Icono a utilizar (con formato ICO y especificando esta extensión)
HelpFile=Nombre del archivo de ayuda a utilizar (especificando extensión HLP)
StartUpScreen=Gráfico en formato BMP (especificando la extensión BMP)

4.12.- Forzar a que un formulario se abra mostrando el último registro introducido

Al abrir un formulario, siempre se abre por defecto mostrando el primer registro introducido. Para forzar que se abrir con el último, acceder a sus propiedades y en la sección Al cargar, elegir Procedimiento de evento, luego pulsar sobre el botón de los puntos suspensivos e insertar el siguiente código:
DoCmd.GoToRecord , , acLast

4.13.- Sincronizar dos cuadros combinados en un formulario

Se pretende describir cómo sincronizar dos cuadros combinados en un formulario, de forma que la selección que se hacer en el primer cuadro combinado limite la lista que aparezca en el segundo cuadro combinado.
El siguiente ejemplo usa la base de datos de ejemplo Neptuno.mdb, proporcionada con Access. El primer cuadro combinado muestra las categorías de productos, y el segundo cuadro combinado muestra los productos disponibles para la categoría seleccionada en el primer cuadro combinado:
a) Abrir la base de datos de ejemplo Neptuno.mdb.
b) Crear la siguiente consulta nueva basada en la tabla Productos, y guardar la consulta como Consulta Lista Categorías.
Consulta : Consulta Lista Categorías
Tabla : Productos
Tipo : Consulta de Selección
Campo: ID de Producto
Orden: Ascendente
Mostrar: Sí
Campo: Nombre de producto
Tabla: Productos
Mostrar: Sí
Campo: ID de categoría
Mostrar: No
Criterios: Formularios![Categorías y Productos]![Categorías]
c) Crear un nuevo formulario no basado en ninguna tabla o consulta con los siguientes cuadros combinados, y guardar el formulario como Categorías y Productos:
- Cuadro Combinado 1
Nombre : Categorías
Tipo de origen de la fila: Tabla / Consulta
Origen de la fila : Categorías
Número de columnas : 2
Anchura de columnas : 0;1
Columna dependiente : 1
Después de actualizar : Refrescar

- Cuadro Combinado 2
Nombre : Productos
Tipo de origen de la fila: Tabla / Consulta
Origen de la fila : Categorías y Productos
Número de columnas : 2
Anchura de columnas : 0;1
Columna dependiente : 1
Nota: La propiedad Columna dependiente del primer cuadro combinado no debe definirse al campo llamado en la fila Criterios de la consulta de arriba; de otra forma, el segundo cuadro combinado mostrará sólo el primer registro.

d) Crear la siguiente macro y guardarla como 'Refrescar':
Nombre de Macro: Refrescar
Acción: NuevaConsulta
Argumentos de la acción
Nombre del control: Productos

e) Ver el formulario Categorías y Productos en vista Formulario. Cuando se seleccionar una categoría en el primer cuadro combinado, el segundo cuadro combinado se actualiza sólo a la lista de productos disponibles para la categoría seleccionada.
En el ejemplo anterior, el segundo cuadro combinado se rellena con el resultado de la consulta 'Consulta Lista Categorías'. Esta consulta encuentra todos los productos que tienen un ID de Categoría igual al de la categoría seleccionada en el primer cuadro combinado.
Para cualquier categoría seleccionada en el primer cuadro combinado, el evento Después de Actualizar ejecuta la macro Refrescar, que fuerza al segundo cuadro combinado a ejecutar la consulta Consulta Lista Categorías de nuevo. Esto refresca la lista de productos disponibles en el segundo cuadro combinado. Sin esta macro, podría forzar al segundo cuadro combinado a refrescarse por sí mismo pulsando la tecla F9.

4.14.- Crear una suma continua en un formulario

Para crear una suma continua en un formulario, la tabla sobre la que está basada debe contener al menos un campo autonumérico (en las versiones 1.x o 2.0, un campo contador). Si la tabla no contiene ese campo, se puede abrir la tabla en modo diseño y crear el campo.
El siguiente ejemplo utiliza una tabla que contiene tres campos: Contador (Campo Autonumérico), Cantidad (Campo numérico) y Total (Campo Numérico). La tabla se llama Prueba.
Crear un formulario nuevo basado en la tabla Prueba.
Formulario: Formulario1
------------------------
OrigendelRegistro: Prueba
Cuadro de Texto: Contador
Origen del Control: Contador
Cuadro de Texto: Cantidad
Origen del Control: Cantidad
Cuadro de Texto: Total
Origen del control: =Dsum("[Cantidad]";"Prueba";"[Contador]<=Forms![Formulario1]![Contador]")

La función Dsum calcula la suma del campo Cantidad en todos los registros que tengan el contador menor o igual que el registro activo. Esta es la razón por la que se necesita un campo autonumérico.

4.15.- Forzar la aparición de los datos de un registro existente al introducir uno de los datos

Supongamos que al introducir un DNI queremos que aparezcan los demás datos de una persona, si es que existe en la base de datos y, si no, poder introducir sus datos. Para ello hay que crear 2 tablas y después relacionarlas entre sí. Una de ellas contendrá sólo el campo del DNI y la otra contendrá todos los datos (incluido el DNI también).
Para introducir datos hay que crear un formulario con origen en la primera tabla (la más pequeña) que incluya el campo del DNI referente a esa primera tabla y además un subformulario con origen en la segunda tabla que presentará el resto de los datos excepto el del DNI, que se debe establecer como No visible en sus propiedades.

4.16.- Establecer el valor por defecto para un cuadro combinado

Cuando se abre un formulario que incluye cuadros combinados, éstos no muestran ningún valor por defecto automáticamente, sino que hay que programarlo previamente. Supongamos un cuadro combinado llamado ListaNom. En la propiedad Valor predeterminado del cuadro combinado poner lo siguiente:
=[ListaNom].[ItemData](x)
siendo x el nº del elemento menos 1, es decir, el 0 corresponde al primer elemento, el 1 al 2º y así sucesivamente.
Al entrar en el formulario, el elemento de la lista elegido será mostrado por defecto.

4.17.- Repetir un valor introducido en un registro al siguiente dentro de un formulario

Para repetir un valor a partir del registro previo, hay que utilizar la propiedad Valor por defecto del control de que se trate. Supongamos que hay un cuadro de texto llamado CajaTxt. Se trata de insertar el siguiente código en el evento Antes de actualizar del formulario:
CajaTxt.defaultvalue = CajaTxt.value
Con esto, cuando Access pase al siguiente registro, el campo ya incluirá el valor del registro anterior.

4.18.- Generar un botón para cerrar un informe

Un informe no permite incluir dentro de sí mismo un botón que lo cierre, sino que es obligado a cerrar el mismo de la forma convencional, lo cual deja menos profesional una aplicación construida bajo Access que se controle desde un interfaz de usuario.
Normalmente, se crearía un botón en el formulario interfaz que abriera el informe. Lo que vamos a hacer aquí es abrir a la vez el informe y un formulario adicional que vamos a construir de reducido tamaño, lo justo para insertar en él un botón con el texto Cerrar. En las propiedades de este botón y dentro del evento Al hacer clic debe haber este código:
Dim stDocName As String
stDocName = "Macro1"
DoCmd.RunMacro stDocName
Esto ejecutará una macro llamada Macro1 que más adelante vamos a crear.
En las propiedades del formulario acceder al evento Al cargar e insertar esta línea:
DoCmd.Restore
Esto es para evitar que el formulario del botón se maximice si la ventana anterior (la del formulario interfaz) ya estuviera maximizada. De este modo, aparecerá sólo la imagen del botón creado.
En las propiedades del formulario acceder al evento Al descargar e insertar esta línea:
DoCmd.Maximize
Esto es para volver a maximizar las ventanas al pulsar el botón. No sería necesario si las ventanas no se maximizaran.
Otras propiedades del formulario que conviene modificar para lograr una mejor apariencia y funcionalidad son las siguientes:
Dentro de la ficha Formato:
Título: Cerrar
Barras de desplazamiento: Ninguna
Selectores de registro: No
Botones de desplazamiento: No
Separadores de registros: No
Cuadro de control: No
Botones Minimizar Maximizar: No
Botón Cerrar: No
Dentro de la ficha Otras:
Emergente: Sí
Menú contextual: No
Crear una macro (llamémosla Macro1) con 2 líneas de acciones, en las cuales se debe seleccionar la acción Cerrar. En la primera de ellas, en los argumentos de acción (la parte inferior de la ventana) consignar lo siguiente:
Tipo de objeto: Informe
Nombre del objeto: Elegir el nombre del informe que se deba cerrar
Guardar: No.
En los argumentos de la segunda línea de acción consignar:
Tipo de objeto: Formulario
Nombre del objeto: Elegir el nombre dado al formulario del botón Cerrar
Guardar: No

4.19.- Cuadros combinados sincronizados sin utilizar VBA

En ocasiones un formulario incluye 2 cuadros combinados (listas desplegables) de forma que, al seleccionar una opción del primer cuadro, las opciones que aparezcan en el 2º sean sólo las relacionadas con la opción elegida en el 1º.
Supongamos 3 tablas en una base de datos que llamaremos Inventario. En esta base de datos tenemos las tablas Clientes, Productos y Resultados. La tabla Clientes contiene los campos CodigoCliente (Numérico Entero Largo) y Cliente (Texto).
La tabla Productos se compone de los campos CodigoCliente (Numérico Entero Largo), CodigoProducto (Numérico Entero Largo) y Producto (Texto).
Cada cliente vende una serie de productos, por lo que en esta tabla hay un código de Cliente, un código de Producto y un nombre del Producto.
CodigoCliente CodigoProducto Producto
1 1 Zapatos
1 2 Zapatillas
2 3 Manzanas
2 4 Peras
La tabla Resultados está formada por los campos CodigoCliente (Numérico Entero Largo) y CodigoProducto (Numérico Entero Largo). Esta tabla es para guardar el código del cliente y el código del producto.
· Crear un formulario en vista diseño basado en la tabla Inventario sin agregar campos en él.
· Crear un cuadro combinado para elegir el cliente basado en los valores de la tabla Clientes y almacenando el valor en el campo CodigoCliente. Esto hará que, al seleccionar un registro en el cuadro combinado, se almacene el CodigoCliente de la tabla Clientes en la tabla Inventario.
· Crear el cuadro combinado para elegir el producto basándose en los valores de la tabla Productos y almacenando el valor en el campo CodigoProducto. Esto hará que, al seleccionar un registro en el cuadro combinado, se almacene el CodigoProducto de la tabla Productos en la tabla Inventario.
Una vez terminado, guardar el formulario con cualquier nombre y seguir los siguientes pasos:
· Acceder a las propiedades del campo ElegirCliente y en el nombre del campo consignar NumeroCliente.
· Acceder a las propiedades del cuadro combinado ElegirProducto. En la propiedad Origen de la fila pulsar sobre los tres puntos suspensivos de la parte derecha, lo cual lleva a una cuadricula de consultas donde hay que hacer doble clic sobre el campo CodigoCliente para añadirlo a la cuadricula.
· En la línea de criterios debajo de este campo incluir el siguiente criterio:
Formularios![prueba]![NumeroCliente]
Esto le indica que solo debe mostrar aquellos registros de la tabla Productos donde el código del cliente sea el del cliente elegido en el primer cuadro combinado. También se puede añadir esta línea con el botón Generar.
· Guardar la consulta con cualquier nombre y cerrarla.
· Crear una nueva macro con la única acción Enviar teclas. Como argumentos de esta macro elegir Pulsaciones de teclas consignando {F9}.
· Guardar la macro dando un nombre.
· Volver al formulario y acceder a las propiedades del cuadro combinado CodigoCliente, en cuya propiedad Al hacer clic se asignará la macro anteriormente creada.
Ahora en el formulario, al seleccionar una opción del primer cuadro combinado, las opciones que aparecerán en el 2º serán sólo las que correspondan a ese cliente.

4.20.- Controlar el ciclo de la tecla TAB en formularios

Por defecto, la tecla TAB va pasando de campo en campo y cuando llega al último, pasa al primer campo del registro siguiente. Esto se puede cambiar mediante la propiedad Ciclo, que por defecto se establece con el valor Todos los registros, pero admite otros dos valores: Registro activo (se queda en el mismo registro sin pasar al siguiente, con lo cual el cursor pasa de nuevo al primer campo) y Página activa (se queda en la misma página del mismo registro).

4.21.- Convertir nombres de personas del tipo Apellidos, Nombre a Nombre Apellidos

Incluir este código:
Function ConvertName(strName As String) As String
On Error GoTo Err_ConvertName
Dim strLastName As String
Dim strFirstName As String
IsSpace = InStr(Name, Chr(32))
FNPos1 = InStr(1, strName, Chr(44))
FNPos2 = Len(strName)
If IsNull(FNPos1) Then
ConvertName = LTrim(strName)
Else
If IsSpace = 0 Or FBPos1 + 1 <> IsSpace Then
FirstLen = FNPos1 + 1
GoTo StringChange
Else
FirstLen = FNPos1 + 2
GoTo StringChange
End If
End If
StringChange:
strFirstName = Mid(strName, FirstLen)
LNPos1 = InStr(1, strName, Chr(44))
strLastName = Mid(strName, 1, LNPos1 - 1)
ConvertName = LTrim(strFirstName & "" & strLastName)
Exit Function
Err_ConvertName:
Resume Next
End Function

Una vez introducido el texto, la función puede ser llamada desde cualquier otro procedimiento. Para comprobar que funciona se puede elegir la opción Ver/Ventana de depuración (en la versión 2000 hay que elegir Ver/Ventana Inmediato), en la que se pueden introducir comandos para ser ejecutados de modo inmediato haciendo uso de la función recién creada. En la parte inferior de dicha ventana ejecutar la siguiente orden:
Print ConvertName ("López Muñoz, Juan")
Pulsando INTRO aparecerá el nombre completo y ordenado (Juan López Muñoz). Se pueden probar más ejemplos en la misma ventana.
En cualquier procedimiento se puede ya incorporar una sentencia tal como esta:
strNombre = ConvertName (Variable)
Variable es el nombre de una variable, campo de una tabla o cuadro de texto que contenga apellidos y nombre separados por coma.
strNombre es el nombre una variable o un campo de una tabla o un cuadro de texto de un formulario o informe en el que se desea incluir el nombre completo convertido.
ConvertName es el nombre dado a la función conversora.
Al cerrar el módulo, contestar afirmativamente a la pregunta de guardar cambios y asignar un nombre cualquiera para él.
Ahora vamos a incluir la función en un formulario. Supongamos que en un formulario hay un cuadro de texto llamado Alumno cuyo Origen del control puede ser un campo de una tabla. Si se desea que, una vez introducido por el usuario un apellido más nombre separados por una coma, se reemplace el contenido del campo, se podría incluir en el evento Después de actualizar del cuadro de texto :
Alumno = ConvertName (Alumno)

4.22.- Calcular la letra del NIF a partir de un DNI

Esta función recibirá una cadena con un valor y la devolverá añadiendo al final la letra correspondiente. Si la cadena recibida tiene signos de puntuación, los quitará; realmente sólo deja los números. Para ello, crear un módulo nuevo incluyendo todo el código siguiente tal cual:
Function LetraNif(strA As String) As String
Dim cCADENA As String
Dim cNUMEROS As String
Dim strT As String, strB As String
Dim a#, NIF#, b#, c#
Dim i As Integer
LetraNif = ""
cNUMEROS = "0123456789"
cCADENA = "TRWAGMYFPDXBNJZSQVHLCKE"
strT = Trim$(strA)
If Len(strT) = 0 Then Exit Function
strB = ""
'---Dejar sólo los números...
For i = 1 To Len(strA)
If InStr(1, cNUMEROS, Mid$(strA, i, 1)) Then
strB = strB + Mid$(strA, i, 1)
End If
Next
strA = strB
a# = 0
NIF# = Val(strA)
Do
b# = Int(NIF# / 24)
c# = NIF# - (24 * b#)
a# = a# + c#
NIF# = b#
Loop While b# <> 0
b# = Int(a# / 23)
c# = a# - (23 * b#)
LetraNif = Mid$(cCADENA, c# + 1, 1)
End Function

Una vez introducido el código, la función puede ser llamada desde cualquier otro procedimiento. Para comprobar que funciona se puede elegir la opción Ver/Ventana de depuración (en la versión 2000 hay que elegir Ver/Ventana Inmediato), en la que se pueden introducir comandos para ser ejecutados de modo inmediato haciendo uso de la función recién creada. En la parte inferior de dicha ventana ejecutar la siguiente orden:
Print LetraNIF ("1623532")
Pulsando INTRO aparecerá la letra P, que es la correspondiente a ese DNI. Se puede en esta misma ventana probar con cualquier otro DNI.
En cualquier procedimiento se puede ya incorporar una sentencia tal como esta:
Letra = LetraNIF (VariableDNI)
VariableDNI es el nombre de una variable, campo de una tabla o cuadro de texto, que tenga un DNI para el que se desee calcular la letra.
Letra es el nombre una variable o un campo de una tabla o un cuadro de texto de un formulario o informe en el que deseas incluir la letra calculada.
LetraNIF es el nombre dado a la función que calcula el NIF.
Al cerrar el módulo, contestar afirmativamente a la pregunta de guardar cambios y asignar un nombre cualquiera para él.
Ahora vamos a incluir la función en un formulario. Supongamos que en un formulario hay un cuadro de texto llamado DNI cuyo Origen del control puede ser un campo de una tabla, o no. Si se desea que una vez introducido por el usuario un DNI en dicho campo se le añada la letra calculada, se podría incluir en el evento Después de actualizar del cuadro de texto DNI un procedimiento de evento, que debe quedar así:
Private Sub DNI_AfterUpdate ()
DNI = DNI & "-" & LetraNIF (DNI)
End Sub

También se podría querer tener la letra en un cuadro de texto separado llamado Letra, y en ese caso hay que sustituir la sentencia por:
Letra = LetraNIF (DNI)
pero siempre dentro del evento Después de actualizar del cuadro de texto en el que se introduce el DNI.

4.23.- Concatenar varias funciones en el mismo evento

Para incorporar más de una función en un mismo evento basta con emplear el signo + entre ellas. Por ejemplo, se podría incluirr en el evento Al hacer clic de un botón de formulario una concatenación de 2 funciones como:
CloseForm() + CheckStatus()
Ambas funcionarán.

4.24.- Texto automático en cuadro de texto combinando otros 2

Supongamos que existen 3 cuadros de texto en un formulario con los nombres Texto1, Texto2 y Texto3, de tal forma que en el cuadro Texto3 vaya apareciendo automáticamente lo tecleado en Texto1 más lo tecleado en Texto2.
Para ello, acceder a las propiedades del cuadro Texto3 y, dentro del evento Al cambiar, establecer un procedimiento de evento con el siguiente código:
Sub Texto1_Change()
Texto3 = Texto1.Text & " " & Texto2
End Sub

Sub Texto2_Change()
Texto3 = Texto1 & " " & Texto2.Text
End Sub

4.25.- Hacer desaparecer una sección de un formulario dependiendo del valor de un campo

Se puede forzar a que desparezca de la vista una sección del formulario, como puede ser la sección Detalle o bien los encabezados o pies.
Para ello hay que incluir el siguiente código en un procedimiento de evento a incluir en la propiedad Al activar registro:
If Nz(Me![nombre_campo]) = "xxx" Then
Me.Section(acDetail).Visible = True
Else
Me.Section(acDetail).Visible = False
End If

En la primera línea de código se establece la condición. Cuandos se trate de campos de tipo texto hay que incluir las comillas. Si se trata de un campo numérico, no se ponen. En cuanto al operador lógico, puede asignarse cualquiera de los disponibles. En este ejemplo se ha escrito el signo de igualdad (=) pero se puede trabajar con los operadores menor que (<), mayor que (>) o distinto (<>). Obviamente, donde pone [nombre_campo]hay que sustituirlo por el nombre del campo a evaluar, el cual siempre irá entre corchetes.
En este ejemplo se ha utilizado acDetail como sección a desaparecer, pero puede utilizarse cualquiera de estos nombres de secciones:
Valor Constante Descripción
0 acDetail Sección detalle de formulario
1 acHeader Sección de encabezado de formulario
2 acFooter Sección de pie de formulario
3 acPageHeader Sección de encabezado de página de formulario
4 acPageFooter Sección de pie de página de formulario

La palabra clave Section que se usa en el código es de sólo lectura en todas las vistas.
Para los formularios y los informes, la propiedad Sección (Section) es una matriz con todas las secciones existentes del formulario o informe identificada por el número de sección. Por ejemplo, Section(0) hace referencia a la sección Detalle de un formulario y Section(3) se refiere a la sección de encabezado de página de un formulario.
También se puede hacer referencia a una sección por su nombre. Las siguientes instrucciones hacen referencia a la sección Detalle del formulario Clientes y son equivalentes:
Forms!Clientes.Section(acDetail).Visible
Forms!Clientes.Section(0).Visible
Forms!Clientes.Detalle0.Visible
Para los formularios y los informes, se ha de combinar la propiedad Sección (Section) con otras propiedades que se aplican a las secciones de formularios o informes. Este ejemplo muestra cómo hacer referencia a la propiedad Visible de la sección de encabezado de página del formulario Clientes.
Forms!Clientes.Section(acPageHeader).Visible
Forms!Clientes.Section(3).Visible
Para los controles, puede usar la propiedad Sección (Section) para determinar en qué sección aparece un control de un formulario o informe. El ejemplo siguiente utiliza la propiedad Sección (Section) para determinar qué sección contiene el control IdDeCliente.
Dim entNúmeroSección As Integer
entNúmeroSección = Forms!Clientes!IdDeCliente.Section

4.26.- Utilizar un cuadro combinado como filtro en un formulario

Supongamos que existe un formulario de facturación en el que están todas las facturas, tanto las pagadas como las impagadas. La tabla de facturas debe tener un campo [Situacion] de tipo numérico cuyos valores son:
1=Factura Pagada
2=Factura Impagada
Hay que incluir un cuadro combinado en el formulario cuyos valores en la propiedades deberán ser:
Nombre: filtro
Origen del Control:
Origen de la Fila: 0;"Todas";1;"Pagadas";2;"Impagadas"
Columna dependiente: 1
Numero de Columnas: 2
Ancho de Columnas: 0cm;2cm
Limitar a Lista: Sí
Después de Actualizar: Insertar el siguiente procedimiento de Evento:
Private Sub AfterUpdate_filtro()
dim origen as string
origen = "Select * from Clientes"
if me![filtro] <> 0 then
origen = origen & " Where ((Clientes.situacion)= Forms![nombreformulario]![filtro]);"
else
origen = origen &";"
end if
me.recordsource = origen
me.requery
end sub

Este mismo truco se puede utilizar también para establecer el orden de los registros; en tal caso, en vez de emplear la cláusula WHERE, se usaría la cláusula ORDER BY.

4.27.- Añadir un nuevo elemento a un cuadro combinado cuyo origen de la fila es una tabla no actualizable

Muchas veces se crean tablas para las que no nos molestamos en hacer formularios de mantenimiento, como pueden ser tablas de países o de códigos postales. Sin embargo, utilizamos estas tablas en cuadros combinados, con lo que existe la posibilidad de que el usuario quiera añadir un nuevo elemento a la lista. Mediante el siguiente procedimiento se añade un nuevo país a la tabla de países sin necesidad de abrir un formulario de altas. En la propiedad Al no estar en la lista del cuadro combinado insertar el siguiente código:
Sub id_pais_notinlist(newdata as string,response as integer)
dim mensaje as string,titulo as string,respuesta as integer
dim db as database,r as recordset,codigo as byte
mensaje = "El elemento no se encuentra en la lista. ¿Desea añadirlo?"
titulo = "Nuevo Pais"
respuesta = msgbox(mensaje,36,titulo)
if respuesta = 6 then 'Si se desea dar de alta el nuevo elemento
set db = currentdb()
set r = db.openrecordset(Tpais)
codigo = ult_idpais() + 1 'Función que obtiene el último código de país de la tabla
r.addnew
r![id_pais] = codigo
r![nombre] = newdata
r.update
r.close
origen = "Select id_pais,nombre From Tpais" 'Se actualiza el origen de la fila
me![id_pais].rowsource = origen
me![id_pais].requery
me![id_pais] = codigo 'Se asigna el nuevo código
else
me![id_pais] = null
docmd.gotocontrol "id_pais"
end if
response = data_errcontinue
End Sub

La función ult_idpais() podría ser de la siguiente forma:
Private Function ult_idpais() As Byte
Dim db As Database
Dim ssTmp As Recordset
Dim sSQL As String
Dim yCodigo As Byte
sSQL = "SELECT Max(id_pais) AS UltCodigo FROM Tpais"
Set db = currentdb()
Set ssTmp = db.OpenRecordset(sSQL, dbOpenSnapshot, dbForwardOnly)
yCodigo = ssTmp!UltCodigo
ssTmp.Close
Set ssTmp = Nothing
Set db = Nothing
Return yCodigo
End Function

4.28.- Numeración automática dependiente de un cambio de año

En muchos libros de registro de entrada de empresas, departamentos y organismos públicos se lleva una numeración consecutiva que comienza con el nº 1 cada año. Si en Access se crea un campo autonumérico para este cometido, al pasar a un nuevo año, el contador del autonumérico seguirá adelante indefinidamente. Si lo que se desea conseguir es que el contador vuelva al valor 1 de modo automático, hay que seguir el procedimiento que aquí se explica.
Supongamos una tabla llamada Expedientes en la que, entre otros, existen los campos Añoactual, que controla el año en que estamos, y Numexp, que controla el campo contador del que hablamos. Como estos campos se van a calcular automáticamente, en el formulario de entrada de datos no serán punto de tabulación. Por esta razón vamos a tener en cuenta el primer campo que reciba el enfoque del cursor para introducir un dato. En las propiedades de este campo, ir al evento Al recibir el enfoque para incluir unas líneas de código como las siguientes:
[Añoactual] = Year(Date)
If [Numexp] = Null Then
[Numexp] = DCount("[Numexp]", "Expedientes") + 1
End If
If [Numexp] = 0 Then
[Numexp] = DCount("[Numexp]", "Expedientes") + 1
End If

Lo único que hay que hacer es reemplazar los nombres de los campos (que figuran entre corchetes) y el nombre de la tabla por los que correspondan.

4.29.- Abrir un formulario en el mismo registro que mostraba cuando se cerró la última vez

No existe una opción por defecto, pero se puede añadir un pequeño código para que se guarde el último registro visualizado y Access vuelva a él al ser abierto el mismo formulario.
Los pasos a seguir son:
1º) Crear una tabla auxiliar (que aquí vamos a llamar Acceso) para almacenar el último registro visualizado en el formulario. Contendrá dos campos, uno (que llamaremos CampoClave para guardar el nombre del campo clave principal de la tabla asociada al formulario y otro para guardar el valor de dicha clave:
CAMPOS TIPO
CampoClave Texto (Clave principal)
Valor Texto
El campo CampoClave se ha descrito como de tipo texto pero puede ser también de tipo numérico o autonumérico. Ello dependerá del tipo de campo que sea el campo clave principal de la tabla asociada al formulario. En este ejemplo suponemos que ese campo es de tipo texto y que su nombre es ClaveFormul. En cada formulario deberemos tomar nota del nombre de ese campo y de su tipo.
2º) Añadir el siguiente código al evento Al descargar del formulario deseado:
Private Sub Form_Unload(Cancel As Integer)
Dim Valor As String
If IsNull(Me![ClaveFormul]) Then
' Cambiar [ClaveFormul] por el nombre del campo clave principal
Valor = "acNewRec"
Else
Valor = Me![ClaveFormul]
' Cambiar [ClaveFormul] por el nombre del campo clave principal
End If
Set rst = db.OpenRecordset(Sql, dbOpenDynaset)
If rst.RecordCount = 0 Then
rst.AddNew
rst![CampoClave] = Me.Name
rst![Valor] = Valor
rst.Update
Else
rst.Edit
rst![Valor] = Valor
rst.Update
End If
rst.Close
End Sub

3º) Añadir el siguiente código al evento Al cargar del formulario, el cual efectúa una búsqueda en la tabla Acceso del campo clave del registro abierto, toma el valor de la clave y se coloca en él:
Private Sub Form_Load()
Set db = CurrentDb
Sql = "SELECT * FROM Acceso WHERE CampoClave = '" & Me.Name & "'"
Set rst = db.OpenRecordset(Sql, dbOpenSnapshot)
If rst.RecordCount > 0 Then
If Not IsNull(rst![Valor]) Then
If rst!Valor <> "acNewRec" Then
Set rstFrm = Me.RecordsetClone
' Si el campo clave principal ("ClaveFormul" en este ejemplo) es de tipo texto,
' la instrucción a incluir sería esta:
rstFrm.FindFirst "[ClaveFormul] = '" & rst![Valor] & "'"
' Cambiar [ClaveFormul] por el nombre del campo clave principal
' Si el campo clave principal ("ClaveFormul" en este ejemplo) es de tipo
' numérico, la instrucción sería:
' rstFrm.FindFirst "[ClaveFormul] = " & rst![Valor]
' Cambiar [ClaveFormul] por el nombre del campo clave principal
If Not rstFrm.NoMatch Then
Me.Bookmark = rstFrm.Bookmark
End If
rstFrm.Close
Else
DoCmd.GoToRecord , , acNewRec
End If
End If
End If
rst.Close
End Sub

No hay que olvidar que no sólo hay que incluir el código, sino asegurarnos que en la hoja de propiedades del formulario quedan marcados ambos eventos: Al cargar y Al descargar con [Procedimiento de evento].
4º) Estando abierto el formulario en modo de diseño, pulsar el botón Código y añadir en la sección Declaraciones el siguiente código:
Option Compare Database
Option Explicit
Dim db As Database
Dim rst As Recordset
Dim rstFrm As Recordset
Dim Sql As String

Las dos primeras líneas ya estarán escritas al acceder a esa sección. Lo mismo ocurre con las líneas primera y última del código de los eventos. Simplemente hay que procurar no repetirlas.
En el número siguiente se explica cómo ampliar este truco para que reconozca al usuario y a su PC.

4.30.- Abrir un formulario en el mismo registro que mostraba cuando se cerró la última vez teniendo en cuenta al usuario y al PC que utilizó

Como ampliación de lo anterior, aquí se trata el mismo asunto pero teniendo en cuenta el nombre del usuario y de su PC, lo cual puede ser útil en entornos corporativos. Todo el procedimiento es prácticamente similar. Se añaden ciertas líneas al código de los eventos y lo realmente nuevo es la adición de un módulo para definir la función que recoge el nombre del PC. Se ha incluido en un módulo y no en el código del formulario porque de esta forma podrá ser utilizado desde cualquier formulario y no sólo desde uno. También la tabla auxiliar tendrá ahora más campos.
Los pasos a seguir son:
Crear una tabla auxiliar (que aquí vamos a llamar Acceso) para almacenar el último registro visualizado en el formulario. Contendrá dos campos, uno (que llamaremos CampoClave para guardar el nombre del campo clave principal de la tabla asociada al formulario y otro para guardar el valor de dicha clave:
CAMPOS TIPO
CampoClave Texto (Clave principal)
Usuario Texto (Clave principal)
Ordenador Texto (Clave principal)
Valor Texto
El campo CampoClave se ha descrito como de tipo texto pero puede ser también de tipo numérico o autonumérico. Ello dependerá del tipo de campo que sea el campo clave principal de la tabla asociada al formulario. En este ejemplo suponemos que ese campo es de tipo texto y que su nombre es ClaveFormul. En cada formulario deberemos tomar nota del nombre de ese campo y de su tipo.
Añadir el siguiente código al evento Al descargar del formulario deseado:
Private Sub Form_Unload(Cancel As Integer)
Dim Valor As String
If IsNull(Me![ClaveFormul]) Then
' Cambiar [ClaveFormul] por el nombre del campo clave principal
Valor = "acNewRec"
Else
Valor = Me![ClaveFormul]
' Cambiar [ClaveFormul] por el nombre del campo clave principal
End If
Set rst = db.OpenRecordset(Sql, dbOpenDynaset)
If rst.RecordCount = 0 Then
rst.AddNew
rst![Usuario] = Application.CurrentUser
rst![Ordenador] = NombrePC
rst![CampoClave] = Me.Name
rst![Valor] = Valor
rst.Update
Else
rst.Edit
rst![Valor] = Valor
rst.Update
End If
rst.Close
End Sub

Añadir el siguiente código al evento Al cargar del formulario, el cual efectúa una búsqueda en la tabla Acceso del campo clave del registro abierto, toma el valor de la clave y se coloca en él:
Private Sub Form_Load()
Set db = CurrentDb
Sql = "SELECT * FROM Acceso WHERE "
Sql = Sql & "Usuario = '" & Application.CurrentUser
Sql = Sql & "' AND Ordenador = '" & NombrePC
Sql = Sql & "' AND CampoClave = '" & Me.Name & "'"
Set rst = db.OpenRecordset(Sql, dbOpenSnapshot)
If rst.RecordCount > 0 Then
If Not IsNull(rst![Valor]) Then
If rst!Valor <> "acNewRec" Then
Set rstFrm = Me.RecordsetClone
' Si el campo clave principal ("ClaveFormul" en este ejemplo) es de tipo texto,
' la instrucción a incluir sería esta:
rstFrm.FindFirst "[ClaveFormul] = '" & rst![Valor] & "'"
' Cambiar [ClaveFormul] por el nombre del campo clave principal
' Si el campo clave principal ("ClaveFormul" en este ejemplo) es de tipo
' numérico, la instrucción sería:
' rstFrm.FindFirst "[ClaveFormul] = " & rst![Valor]
' Cambiar [ClaveFormul] por el nombre del campo clave principal
If Not rstFrm.NoMatch Then
Me.Bookmark = rstFrm.Bookmark
End If
rstFrm.Close
Else
DoCmd.GoToRecord , , acNewRec
End If
End If
End If
rst.Close
End Sub

No hay que olvidar que no sólo hay que incluir el código, sino asegurarnos que en la hoja de propiedades del formulario quedan marcados ambos eventos: Al cargar y Al descargar con [Procedimiento de evento].
Estando abierto el formulario en modo de diseño, pulsar el botón Código y añadir en la sección Declaraciones el siguiente código:
Option Compare Database
Option Explicit
Dim db As Database
Dim rst As Recordset
Dim rstFrm As Recordset
Dim Sql As String

Crear un módulo con un nombre cualquiera, que llevará este código:
Option Compare Database
Option Explicit
Declare Function GetComputerName Lib "kernel32" Alias "GetComputerNameA" (ByVal lpBuffer As String, nSize As Long) As Long
Function NombrePC() As String
Dim Buffer As String
Dim Size As Long
Dim X As Long
Buffer = Space(255)
Size = 255
'Asigna Nombre Maquina
X = GetComputerName(Buffer, Size)
NombrePC = Left$(Buffer, Size)
End Function

4.31.- Capturar el número de registro con el que se trabaja en cada momento

Para incluir en un formulario un campo que muestre el registro actual dentro de una selección, es decir, que aparezca lo mismo que en el contador de registros, hay que crear un cuadro de texto con la siguiente expresión:
=[CurrentRecord]
Sin embargo, hay que tener en cuenta que esto no funciona en formularios tabulares.

4.32.- Formularios en la misma posición

Para que aparezca siempre un formulario en una misma posición hay que crear un módulo con este código:
Declare Function glrMoveWindow Lib "user32" Alias "MoveWindow" ByVal (hwnd as Long, ByVal X as Long, ByVal Y as Long, ByVal nWidth as Long, ByVal nHeight as Long, ByVal bRepaint as Long) as Long
En el evento Al abrir del formulario incluir este código:
glrMoveWindow (Me.hwnd, posiciónX, posiciónY, ancho, alto, True)

Los parámetros 2º, 3º, 4º y 5º son los que hay que variar. Con esto siempre se abrirá el formulario en la misma posición.