Está en la página 1de 22

CURSO DE VB

CAPÍTULO 201

Índice de contenido
UN GRAN EJEMPLO: APRENDEMOS A MANEJAR MÓDULOS Y UNOS CUANTOS
“TRUCOS” MÁS.................................................................................................................................2
INTRODUCCIÓN...........................................................................................................................2
EL EJEMPLO..................................................................................................................................2
PLANIFICANDO LA BD..........................................................................................................2
CONFIGURANDO NUESTRAS RELACIONES.....................................................................3
CREANDO NUESTROS FORMULARIOS..............................................................................4
CERRANDO NUESTROS FORMULARIOS: CREAMOS EL MÓDULO..............................6
FMENU, FPPTO Y NUESTRO MÓDULO...............................................................................6
PARTIDAS DE INGRESO....................................................................................................6
PARTIDAS DE GASTO........................................................................................................9
FMENU, FMOV Y NUESTRO MÓDULO................................................................................9
MOVIMIENTOS DE INGRESO...........................................................................................9
MOVIMIENTO DE GASTO...............................................................................................11
CONFIGURANDO EL INICIO DE LA APLICACIÓN. ¿Y FCHIVATO?..............................12
CONFIGURANDO FCHIVATO..........................................................................................12
CONFIGURANDO EL INICIO DE LA APLICACIÓN.....................................................12
FORMULARIO DE CAMBIO DE AÑO DE TRABAJO........................................................13
¿CUÁNTO HEMOS INGRESADO/GASTADO EN UNA PARTIDA EN PARTICULAR?. .15
CREÁNDONOS UN INFORME FANTASMA.......................................................................18
PARA FINALIZAR ESTE CAPÍTULO........................................................................................22

1 La BD de ejemplo os la podéis bajar aquí.

1
Visítame en http://bit.ly/NckAccess
UN GRAN EJEMPLO: APRENDEMOS A
MANEJAR MÓDULOS Y UNOS
CUANTOS “TRUCOS” MÁS

INTRODUCCIÓN
Llegamos al final de este curso. Sé que hay “montones” de
cosas más que explicar, pero si habéis seguido todos los
capítulos (y estudiado un poquito ) deberíais ser
autosuficientes para investigar (entendiéndolo) por vuestra
cuenta.

¿Qué veremos en este capítulo? Vamos a ver un gran ejemplo (“gran” por su tamaño) de cómo
podemos operar a través de módulos y código. Los módulos serán módulos estándar, y el
ejemplo nos permitirá ver cómo podemos “sacarles el jugo”.

Durante el transcurso del ejemplo veremos también un par de “trucos” para conseguir
nuestros objetivos, bajo el lema: si no podemos conseguirlo directamente, demos un rodeo.

Todos los códigos estarán perfectamente comentados, por lo que quizá lo interesante no sea el
código en sí, realmente, sino cómo lo hemos articulado para lograr nuestros fines.
Evidentemente, si hay algo que destacar, os lo indicaré tras el código.

¿Qué cosas vamos a aprender/perfeccionar? Sin que sea una lista exhaustiva, vamos a ver
cómo:

• Reutilizar formularios
• Construir tablas que funcionen sólo cuando las necesitamos, y que desaparezcan
después.
• Utilizar módulos estándar con procedimientos y funciones

¿Y cuál es la idea del ejemplo? La idea del ejemplo es desarrollar una contabilidad
presupuestaria y real doméstica, para controlar nuestros gastos e ingresos. Lo veremos con
detalle en el próximo epígrafe.

EL EJEMPLO
Como os comentaba, vamos a desarrollar una contabilidad doméstica para nuestros gastos e
ingresos. Nos confeccionaremos un presupuesto y después veremos cómo podremos ir
obteniendo una comparativa de los mismos respecto de nuestros gastos reales.

Manos a la obra.

PLANIFICANDO LA BD
Cogemos papel y lápiz y nos dedicamos a pensar un rato. ¿Qué elementos necesito? Pues
parece claro que vamos a necesitar los siguientes elementos:

• Una tabla para los presupuestos


• Una tabla para los movimientos (ingresos o gastos) reales.

2
Visítame en http://bit.ly/NckAccess
¿No necesito nada más? Pues así como plantearemos la aplicación no necesito nada más 

Vamos pues a crearnos dichas tablas. La primera, que


llamaremos TPpto, tendrá la siguiente estructura:

Ya tenemos nuestra tabla creada. Ved que le he añadido un campo, [AnoPpto], que nos
permitirá trabajar con diferentes años. Si no añadiéramos este campo deberíamos crear una
BD por cada año.

Como tipo de partida ([TipoPartida]) lo que haremos será establecer una convención: si el
valor es 1 es que hablamos de ingreso; si es 2 es que hablamos de gasto.

¿Y nuestra tabla TMov? Evidentemente TMov será la tabla que nos recogerá los movimientos
reales. Vamos a confeccionarla con la siguiente estructura:

Fijaos que, para esta tabla, hemos indicado que el campo [Partida] sea numérico, porque lo
que nos va a recoger va a ser el [IdPpto], no el nombre de la partida. Veremos más adelante
cómo configurar el formulario para que nosotros “ni nos enteremos” de eso.

En principio no necesitamos nada más.

CONFIGURANDO NUESTRAS RELACIONES


Accedamos a la ventana relaciones, donde añadiremos nuestras dos tablas. Creamos una
relación entre los campos TPpto.IdPpto y TMov.Partida. Cuando nos salga la ventana para
modificar la relación le indicamos que “exigimos integridad referencial”.

La relación debería haberse creado de la siguiente manera:

3
Visítame en http://bit.ly/NckAccess
CREANDO NUESTROS FORMULARIOS
Vamos a crearnos una serie de formularios. Empezaremos por nuestro chivato. Es decir,
creamos un formulario en blanco y lo guardamos con el nombre de FChivato. En él incluiremos
un cuadro de texto, que llamaremos txtAnoTrab. Este cuadro de texto nos recogerá el año de
trabajo, que por defecto será el año del sistema.

Añadimos un nuevo cuadro de texto, que llamaremos txtTipoPartida. Este control nos recogerá
la información de si queremos operar con ingresos o gastos.

Nos debería haber quedado algo tan simple como:

Vamos a crearnos ahora otro formulario en blanco, al que llamaremos FMenu. Como habréis
podido imaginar, este será nuestro “panel de control”. Ya iremos añadiendo botones en él con
posterioridad.

Vamos a crearnos un formulario sobre la tabla TPpto, pero en forma de formularios continuos.
Lo llamaremos FPpto. Una vez creado de manera automática lo configuraremos de la siguiente
manera:

• Eliminamos el campo [IdPpto]


• Seleccionamos el campo [TipoPartida] y situamos su propiedad VISIBLE en NO.
Podemos borrar su etiqueta.
• Seleccionamos el campo [AnoPpto] y situamos su propiedad VISIBLE en NO. Podemos
borrar su etiqueta.
• En el encabezado del formulario introducimos una etiqueta y en ella escribimos:
PRESUPUESTO: INGRESOS. A esa etiqueta la llamamos lblTitulo.
• En el encabezado, a la derecha, añadimos un botón para cerrar el formulario. Lo

4
Visítame en http://bit.ly/NckAccess
llamaremos cmdCerrar.

Con algo de formato, a mí me ha quedado así:

Vamos a hacer algo similar sobre la tabla TMov, pero en vista de un solo formulario. Una vez
creado nuestro formulario, que guardaremos como FMov, lo configuramos de la siguiente
manera:

• Eliminamos el campo [IdMov]


• Situamos el campo [Partida] con su propiedad VISIBLE en NO
• Para el campo [TipoPart] situamos su propiedad en VISIBLE: NO
• Para el campo [AnoTrab] situamos su propiedad en VISIBLE: NO
• En el encabezado del formulario creamos una etiqueta y en ella escribimos
MOVIMIENTO: INGRESO. A esta etiqueta la llamamos lblTitulo.

Vamos a crearnos un cuadro combinado, que nos servirá para elegir la partida que queremos.
Cuando nos salga el asistente lo cancelamos. Vamos a configurarlo para nuestros propósitos.

Así pues, sacamos las propiedades de ese combo y nos vamos a la pestaña:

• Otras → Nombre, y lo llamamos cboPartida


• Otras → Índice de tabulación, y le indicamos que debe ser el índice 1. De hecho, he
reordenado todos los índices de los campos para que me queden en el siguiente orden:

• Datos → Limitar a la lista: sí


• Datos → Permitir ediciones de lista: no
• Formato → Número de columnas: 2
• Formato → Ancho de columnas: 0cm;3cm

Finalmente, en el encabezado, a la derecha, he añadido un botón de comando que he llamado


cmdCerrar, para salir del formulario.

Con algo de formato a mí me ha quedado así:

5
Visítame en http://bit.ly/NckAccess
CERRANDO NUESTROS FORMULARIOS: CREAMOS EL MÓDULO
Como la idea es que los formularios se abran desde FMenu podemos programar un código
común para cerrar los formularios. La idea es la siguiente secuencia:

• Desde FMenu: Cierro FMenu → Abro el formulario correspondiente.


• Desde otro formulario: Cierro el formulario → Abro FMenu

Así pues vamos a crearnos un módulo estándar, que llamaremos mdlCodigos. Si abrimos el
editor de VB (ALT+F11) nos vamos a Menú → Insertar → Módulo

Vamos a escribir el procedimiento de cierre de los formularios. Para ello escribimos este
código:


Public Sub subCierra(nomForm As String)
DoCmd.Close acForm, nomForm
DoCmd.OpenForm "FMenu"
End Sub

Como vemos, le pasamos el nombre del formulario que queremos cerrar como argumento.

FMENU, FPPTO Y NUESTRO MÓDULO

PARTIDAS DE INGRESO
Vamos a situar FMenu en vista diseño y vamos a añadir un botón de comando, que llamaremos
cmdPptoIngreso. Este botón nos servirá para introducir o modificar las partidas de ingreso del
presupuesto del año de trabajo.

¿Cuál es la idea? Que el presupuesto se nos abra pero con la información de las partidas de
ingreso y para el año de trabajo que tenemos estipulado. Pensemos...

6
Visítame en http://bit.ly/NckAccess
Lo que vamos a hacer es cambiar el origen del formulario
que, como ya sabemos (¿o no?) se debe cambiar con el
formulario en vista diseño. Lógicamente no podemos, si
estamos trabajando ya como usuario de la BD, modificar
cada vez el origen del formulario (¡eso sería absurdo!).
Vamos a decirle al código VB que haga el “trabajo sucio”
por nosotros.

Pero, ¿cómo vamos a determinar el año de trabajo y el tipo


de gasto? Pues para eso exprimiremos nuestro FChivato. Y
recurriremos a él a través de dos funciones en nuestro
módulo de códigos.

Así pues, en el módulo, insertamos una nueva función que nos determinará el año de trabajo,
y que tendrá este código:


Public Function fncAT() As String
fncAT = Forms!FChivato.txtAnoTrab.Value
End Function

En buena lógica, la función que nos determinará el tipo de partida será la siguiente:


Public Function fncTP() As Long
fncTP = Forms!FChivato.txtTipoPartida.Value
End Function

Aprovecho para recordaros que las funciones devuelven un valor; los procedimientos “hacen
algo” (aunque una función también puede “hacer algo” en medio de su programación).

Sigamos: ¿no nos parece el “ingreso presupuestario” muy similar al “gasto presupuestario”,
exceptuando la diferencia en el tipo de partida? Pues vamos a crearnos un procedimiento en
nuestro módulo para abrir uno u otro en función de un parámetro. ¿Y cuál será? Precisamente
el que marca la diferencia: si es gasto o ingreso.

Pues según lo dicho creemos un nuevo procedimiento en mdlCodigos de la siguiente manera:


Public Sub subAbreFPpto(elTP As Long)
'Declaramos las variables
Dim vAT As String
Dim miSql As String
'Pasamos el valor elTP a FChivato
Forms!FChivato.txtTipoPartida.Value = elTP
'Creamos la SQL que nos dará el origen del formulario
miSql = "SELECT * FROM TPpto" _
& " WHERE TPpto.AnoPpto='" & fncAT() & "'" _
& " AND TPpto.TipoPartida=" & fncTP()
'Abrimos FPpto en vista diseño
DoCmd.OpenForm "FPpto", acDesign
'Cambiamos su origen
Forms!FPpto.RecordSource = miSql
'Lo cerramos guardando los cambios
DoCmd.Close acForm, "FPpto", acSaveYes
'Lo volvemos a abrir en vista normal, pero cambiando el caption
'de lblTitulo en función del tipo de partida
DoCmd.OpenForm "FPpto"

7
Visítame en http://bit.ly/NckAccess
If elTP = 2 Then '1=ingreso
Forms!FPpto.lblTitulo.Caption = "PRESUPUESTO: GASTOS"
End If
'Cerramos el formulario de menú
DoCmd.Close acForm, "FMenu"
End Sub

Ahora sí ya tenemos los elementos necesarios para


programar cmdPptoIngreso. Así, el código para el evento
“Al hacer click” de ese botón sería, ya muy simplificado,
sería:


Private Sub cmdPptoIngreso_Click()
Call subAbreFPpto(1)
End Sub

Perfecto. Ya tenemos nuestro FPpto abierto según el tipo de partida. Pero, si queremos añadir
un registro, ¿cómo va a saber qué tipo de partida es y de qué año de trabajo estamos
hablando? Tendremos que hacer algo al respecto.

Así pues, situamos FPpto en vista diseño y en el evento de formulario “Al activar registro”
escribimos el siguiente código.


Private Sub Form_Current()
'Si el registro es un nuevo registro rellenamos el año de trabajo y el tipo de partida
With Me
If .NewRecord Then
.AnoPpto.Value = fncAT()
.TipoPartida.Value = fncTP()
End If
End With
End Sub

Como veis, nuestras funciones empiezan a cobrar mucha utilidad. El código viene a decir que si
lo que hacemos en el formulario es dar de alta un nuevo registro nos rellene automáticamente
los campos [AnoPpto] y [TipoPartida].

Evidentemente, si lo que hacemos es “pasearnos” por los registros el código no actuará y no


se producirá ningún cambio.

El código que nos falta, que es el del botón cmdCerrar, es tan simple como el que sigue:


Private Sub cmdCerrar_Click()
Call subCierra(Me.Name)
End Sub

Pues parece que los ingresos presupuestarios ya los tenemos listos.

8
Visítame en http://bit.ly/NckAccess
PARTIDAS DE GASTO
Como nos hemos “pegado el gran currote” en la parte de
ingresos ya tenemos prácticamente hecha la parte de
gasto. Sólo hace falta que añadamos, en FMenu, un botón
de comando, que llamaremos cmdPptoGasto, y en su
evento “Al hacer click” escribiremos el siguiente código:


Private Sub cmdPptoGasto_Click()
Call subAbreFPpto(2)
End Sub

Creo que queda clara la utilidad de utilizar funciones y procedimientos. Pero, por si acaso, lo
practicaremos un poco más en los próximos epígrafes.

 Nota: tened en cuenta que si queréis comprobar el funcionamiento de los botones y de los
códigos es necesario que FChivato esté abierto y con valor para el año de trabajo. Ya veremos
un poco más abajo cómo conseguir que esta apertura se produzca automáticamente.

FMENU, FMOV Y NUESTRO MÓDULO


La operación que vamos a realizar con los movimientos reales va a ser muy parecida a lo que
hemos visto en el epígrafe anterior, pero ahora, además, tenemos el hándicap de que en
nuestro formulario hay un combo que, por ahora, no contiene ningún tipo de información. Al
igual que el origen del formulario, habrá que definir el origen del combo.

MOVIMIENTOS DE INGRESO
Siguiendo con la sistemática aprendida en el epígrafe anterior vamos a programar un
procedimiento en nuestro módulo que nos abra FMov en función de si queremos introducir una
partida de ingreso o de gasto.

Así pues, en nuestro módulo escribiremos el siguiente código (os animo, antes de mirar el
código, a pensar en cómo podría ser dicho código).


Public Sub subAbreFMov(elTP As Long)
'Declaramos las variables
Dim vAT As String
Dim miSql As String
Dim miRce As String
'Pasamos el valor elTP a FChivato
Forms!FChivato.txtTipoPartida.Value = elTP
'Creamos la SQL que nos dará el origen del formulario
miSql = "SELECT * FROM TMov" _
& " WHERE TMov.AnoTrab='" & fncAT() & "'" _
& " AND TMov.TipoPartida=" & fncTP()
'Abrimos FMov en vista diseño
DoCmd.OpenForm "FMov", acDesign
'Cambiamos su origen
Forms!FMov.RecordSource = miSql
'Lo cerramos, guardando los cambios
DoCmd.Close acForm, "FMov", acSaveYes

9
Visítame en http://bit.ly/NckAccess
'Lo volvemos a abrir, en vista normal y a punto para introducir
'un nuevo registro
DoCmd.OpenForm "FMov", , , , acFormAdd
'Creamos la SQL para el origen del combo cboPartida
miRce = "SELECT TPpto.IdPpto, TPpto.Partida FROM TPpto" _
& " WHERE TPpto.AnoPpto='" & fncAT() & "'" _
& " AND TPpto.TipoPartida=" & fncTP()
'Cambiamos el RowSource del combo
With Forms!FMov.cboPartida
.RowSource = miRce
'Refrescamos el combo
.Requery
End With
'Si vamos a introducir un gasto cambiamos la caption del título
If elTP = 2 Then
Forms!FMov.lblTitulo.Caption = "MOVIMIENTO: GASTO"
End If
'Cerramos el formulario de menú
DoCmd.Close acForm, "FMenu"
End Sub

¡Listo! Ahora nuestro código en el botón cmdMovIngreso que añadiremos en FMenu se


simplificará así:


Private Sub cmdMovIngreso_Click()
Call subAbreFMov(1)
End Sub

Nos queda, en primer lugar, decirle al formulario que si el registro es un nuevo registro nos
“pase” la información del tipo de partida y el año de trabajo. Para ello sacamos las propiedades
de FMov y en el evento “Al cargar” le generamos el siguiente código:


Private Sub Form_Load()
With Me
If .NewRecord Then
.AnoTrab.Value = fncAT()
.TipoPart.Value = fncTP()
End If
End With
End Sub

En segundo lugar debemos indicar al combo que, una vez se haya seleccionado un valor, lo
pase al campo [Partida]. Para ello, en el evento “Después de actualizar” de cboPartida le
generamos el siguiente código:


Private Sub cboPartida_AfterUpdate()
If Not IsNull(Me.cboPartida.Value) Then
Me.Partida.Value = Me.cboPartida.Value
End If
End Sub

10
Visítame en http://bit.ly/NckAccess

Finalmente debemos controlar que todos los datos estén


introducidos correctamente. Si cerráramos sin ese control
se nos crearía un registro en blanco, sólo relleno con los
datos del año de trabajo y el tipo de partida. Así pues, el
código del botón cmdCerrar sería:


Private Sub cmdCerrar_Click()
'Declaramos las variables
Dim hayVacios As Boolean
Dim resp As Integer
'Suponemos que todo está rellenado correctamente
hayVacios = False
'Comprobamos que haya valor en el campo fecha
If IsNull(Me.FechaMov.Value) Then
MsgBox "No ha introducido ninguna fecha", vbInformation, "SIN FECHA"
hayVacios = True
End If
'Comprobamos que haya valor en el combo
If IsNull(Me.cboPartida.Value) Then
MsgBox "No ha introducido ninguna partida", vbInformation, "SIN PARTIDA"
hayVacios = True
End If
'Comprobamos que haya introducido importe
If IsNull(Me.ImpPartida.Value) Then
MsgBox "No ha introducido ningun importe", vbInformation, "SIN IMPORTE"
hayVacios = True
End If
'Si hay campos sin rellenar pedimos al usuario qué hacemos
If hayVacios = True Then
resp = MsgBox("¿Desea salir? Si hay campos vacíos se borrará el registro", _
vbQuestion + vbYesNo, "CONFIRMACIÓN")
'Si sí quiere salir sin guardar los cambios pues deshacemos los cambios
If resp = vbYes Then
Me.Undo
Else
'Si no quiere salir salimos del procedimiento
Exit Sub
End If
End If
'Salimos
Call subCierra(Me.Name)
End Sub

MOVIMIENTO DE GASTO
En FMenu añadimos un nuevo botón de comando, que llamaremos cmdMovGasto, que tendrá
(seguro que lo adivináis) este gran código:


Private Sub cmdMovGasto_Click()
Call subAbreFMov(2)
End Sub

11
Visítame en http://bit.ly/NckAccess
CONFIGURANDO EL INICIO DE LA APLICACIÓN.
¿Y FCHIVATO?
Como hemos visto hasta ahora, el funcionamiento correcto
de la aplicación pasa por el hecho de que FChivato esté
cargado para que nuestras funciones tengan de dónde sacar
su valor. Vamos a ver el proceso para conseguir eso de
manera automática.

CONFIGURANDO FCHIVATO
Vamos a situar FChivato en vista diseño y vamos a operar sobre el evento de formulario “Al
cargar”. ¿Qué debe ocurrir? Que txtAnoTrab se rellene automáticamente con un año de
trabajo, que hemos convenido que, por defecto, será el año del sistema.

Pues nada más fácil. El código que debemos asignar al evento “Al cargar” será el siguiente:


Private Sub Form_Load()
Me.txtAnoTrab.Value = Year(Date)
End Sub

Por ahora no debemos hacer nada más con este formulario.

CONFIGURANDO EL INICIO DE LA APLICACIÓN


Como ya sabéis (espero) podemos indicarle a Access qué formulario queremos que se cargue
al abrir la aplicación. Lógicamente, nosotros queremos que se nos cargue FMenu.

Para aquellos que no tengan esto muy claro lo explico muy rápidamente:

Access 2003:
• Menú Herramientas → Inicio...
• Mostrar formulario/página, y ahí seleccionamos FMenu.

Access 2007 y 2010:


• Pulsamos el botón de Office (Menú Archivo en 2010)
• Pulsamos el botón “Opciones de Access”
• Opción “Base de datos actual”
• Opciones de aplicación → Mostrar formulario, y seleccionamos “FMenu”

Y, como imagino que ya habréis adivinado, si necesitamos que se abra también FChivato
únicamente se lo tenemos que decir al formulario que se carga al inicio.

Así pues, en el evento “Al cargar” de FMenu le generamos el siguiente código:


Private Sub Form_Load()
DoCmd.OpenForm "FChivato", , , , , acHidden
End Sub

12
Visítame en http://bit.ly/NckAccess
Es decir, que hemos conseguido realizar el siguiente
proceso de manera automática:

1. Abrimos la aplicación
2. La aplicación nos abre FMenu
3. FMenu nos abre FChivato, en modo oculto
4. FChivato se carga con el año de trabajo

¡Listo!

 Truco: para comprobar el correcto funcionamiento de lo anterior lo lógico sería cerrar


Access y volverlo a abrir. Pero en Access 2007 ó 2010, si no queremos ir haciendo “tantos
clicks por ahí”, podemos ir a la opción de “Compactar la BD” y compactarla. Así “mataremos
dos pájaros de un tiro”: eliminaremos archivos temporales y forzaremos el reinicio de la
aplicación.

Hasta aquí parece que nuestra aplicación ya funcionaría a pleno rendimiento, pero
evidentemente, ya que tenemos los datos, vamos a necesitar extraer información de los
mismos.

Veamos pues algunas opciones complementarias y un par de opciones de consulta y emisión


de informes para complementar nuestra aplicación.

FORMULARIO DE CAMBIO DE AÑO DE TRABAJO


¿Qué pasaría si queremos cambiar de año de trabajo? Pues algo tan simple como indicárselo a
nuestra aplicación.

Vamos a crearnos un simple formulario, que llamaremos FCambiaAT, en el cual introduciremos


los siguientes elementos:

• Un textbox para indicar el año de trabajo que queremos


• Un botón de comando, que llamaremos cmdAceptar
• Un botón de comando, que llamaremos cmdCancelar

A mí me ha quedado una cosa así:

Veréis que lo he hecho “pequeñito” porque vamos a configurarlo como emergente y modal. Así
pues, nos vamos a las propiedades del formulario y Pestaña Otras →
→ Emergente: Sí
→ Modal: Sí

13
Visítame en http://bit.ly/NckAccess
Al textbox lo vamos a llamar txtAT

El código del botón cmdCancelar va a ser tan simple como:


Private Sub cmdCancelar_Click()
DoCmd.Close acForm, Me.Name
End Sub

El código del botón cmdAceptar va a ser ligeramente más


complejo, puesto que nos va a servir para controlar el valor
introducido por el usuario.

Pensemos... ¿Qué puede hacer el usuario?

• Dejarlo en blanco
• Introducir un valor no numérico
• Introducir un valor numérico, pero no válido como año de trabajo

Nuestro código va a evaluar estas posibilidades y actuará en consecuencia.

Pues tras lo anterior ahí va el código:


Private Sub cmdAceptar_Click()
'Declaramos las variables
Const miMsg As String = "El valor introducido no es correcto"
Dim vAT As Variant
'Cogemos el valor introducido por el usuario
vAT = Nz(Me.txtAT.Value, 0)
'Si lo ha dejado en blanco avisamos y salimos
If vAT = 0 Then
MsgBox "No ha introducido ningún año de trabajo", vbExclamation, "SIN DATOS"
GoTo Salida_error
End If
'Comprobamos que haya introducido un valor numérico
If Not IsNumeric(vAT) Then
MsgBox miMsg, vbExclamation, "INCORRECTO"
GoTo Salida_error
End If
'Comprobamos que el año de trabajo tenga cuatro dígitos
If Len(vAT) <> 4 Then
MsgBox miMsg, vbExclamation, "INCORRECTO"
GoTo Salida_error
End If
'Comprobamos que el año de trabajo empiece por 2
If Left(vAT, 1) <> 2 Then
MsgBox miMsg, vbExclamation, "INCORRECTO"
GoTo Salida_error
End If
'Tras las comprobaciones, pasamos el nuevo año a FChivato
Forms!FChivato.txtAnoTrab.Value = vAT
'Cerramos el formulario
DoCmd.Close acForm, Me.Name
Exit Sub

14
Visítame en http://bit.ly/NckAccess
Salida_error:
With Me.txtAT
'Borramos el valor introducido
.Value = Null
'Situamos el enfoque
.SetFocus
End With
End Sub

Ahora sí podemos irnos a nuestro formulario FMenu, introducir un


botón de comando, que llamaremos cmdCambiaAT, y generarle el
siguiente código:


Private Sub cmdCambiaAT_Click()
'Abrimos FCambiaAT
DoCmd.OpenForm "FCambiaAT"
End Sub

¿CUÁNTO HEMOS INGRESADO/GASTADO EN UNA PARTIDA EN


PARTICULAR?
Veamos cómo cambiar el origen de un combo al seleccionar una opción, y cómo podemos
obtener información a través de SQL's parciales, que nos darán la información reflejada en un
textbox (para una información puntual “a lo rápido”).

En nuestro FMenu introduciremos un marco de opciones. El asistente que nos aparece lo


configuraremos de la siguiente manera:

• Nombres de las etiquetas: escribiremos, para la primera (sin comillas), “Ingreso”, y


para la segunda, “Gasto”.
• Dejamos la opción predeterminada en ingreso.
• Dejamos los valores por defecto que nos salen, coincidentes con nuestra convención: 1-
Ingreso; 2-Gasto.
• Le damos el formato que más nos guste.
• Como título escribimos (sin comillas), “Seleccionar:”

A este marco le pondremos de nombre mrcTP.

Debería habernos quedado una cosa así:

Ahora vamos a insertar un cuadro combinado. Para que Access nos haga parte del trabajo de
configuración, al salirnos el asistente, vamos a decirle que queremos que nos coja los valores
de la tabla TPpto, los campos [IdPpto] y [Partida] y ocultaremos la clave principal. Da igual el
título que le pongamos porque borraremos la etiqueta.

A este combo lo llamaremos cboSelPartida.

Con una etiqueta auxiliar, un pequeño rectángulo y algo de formato podemos conseguir algo

15
Visítame en http://bit.ly/NckAccess
así:

Vamos primero a por el combo. Vamos a asignarle, en el


evento “Al recibir el enfoque”, el siguiente código, que nos
irá cambiando el origen de la fila según nuestras
necesidades:


Private Sub cboSelPartida_GotFocus()
'Declaramos las variables
Dim vTP As Long
Dim miRce As String
Dim vAT As String
'Cogemos el valor del marco
vTP = Me.mrcTP.Value
'Cogemos el valor del año de trabajo
vAT = fncAT()
'Creamos la SQL para el RowSource, filtrándola por dichos valores
miRce = "SELECT TPpto.IdPpto, TPpto.Partida FROM TPpto" _
& " WHERE TPpto.AnoPpto='" & vAT & "'" _
& " AND TPpto.TipoPartida=" & vTP
'Asignamos nuestro RowSource al combo
With Me.cboSelPartida
.RowSource = miRce
'Refrescamos la información del combo
.Requery
'Borramos el valor que pudiera haber en el combo
.Value = Null
End With
End Sub

OK. Aunque se podría hacer en un sólo código vamos a ver cómo encadenar códigos en
nuestro módulo para que nos dé el resultado deseado, ya que no sólo se nos informará de lo
que llevamos gastado sino también de la desviación presupuestaria.

¿Qué vamos a necesitar? Pues vamos a necesitar:


• Una función que nos dé el valor presupuestado
• Una función que nos dé el valor de todos los movimientos
• Un procedimiento que nos calcule la diferencia y nos muestre toda la información en un
msgbox.

Vamos a por la primera, que es la más sencilla.

En nuestro módulo de códigos escribimos simplemente:


Private Function fncTotalPptado(vIdPartida As Long) As Currency

16
Visítame en http://bit.ly/NckAccess
fncTotalPptado = DLookup("[ImpPartida]", "TPpto", "[IdPpto]=" & vIdPartida)
End Function

Fijaos que:

La he declarado privada (Private), lo que significa que no


podrá ser llamada desde otro procedimiento que no sea
alguno de nuestro propio módulo.

Como vamos por identificadores de partida (recordad que el combo


almacenará el ID, no el texto de la partida) no es necesario tener
en cuenta el año de trabajo (es el propio combo el que ya lo tiene
en cuenta).

Para conseguir el sumatorio vamos a crearnos una consulta, pero a través de una SQL, y
después examinaremos su resultado a través de un recordset DAO. El código sería, pues:


Private Function fncTotalMovimientos(vIdPartida As Long) As Currency
'Declaramos las variables
Dim rst As DAO.Recordset
Dim miSql As String
'Creamos la SQL que nos dará la suma de movimientos de la partida seleccionada
miSql = " SELECT Sum(TMov.ImpPartida) AS TotMov FROM TMov" _
& " WHERE TMov.Partida=" & vIdPartida
'Creamos el recordset sobre la SQL
Set rst = CurrentDb.OpenRecordset(miSql)
'Si no hubiera registros la función devolverá 0
If rst.RecordCount = 0 Then
fncTotalMovimientos = 0
Else
'Si no, cogemos el total que nos devuelve la SQL
fncTotalMovimientos = Nz(rst.Fields(0).Value, 0)
End If
'Cerramos conexiones y liberamos memoria
rst.Close
Set rst = Nothing
End Function

Fijaos, en este caso, que también he declarado la función como privada. Debemos contemplar
la posibilidad de que esa partida esté presupuestada, pero que aún no haya movimientos. En
este caso esto lo hemos controlado a través del conteo de registros del recordset, indicando
que, si no hay registros, la función nos retorne 0.

¡Ah! Y recordad que si no os funciona el código debéis comprobar si tenéis registrada la librería
“Microsoft DAO 3.6 Object Library”.

Ahora sí ya tenemos de dónde obtener lo presupuestado y lo ingresado/gastado. Como vamos


a sacar un msgbox crearemos un procedimiento sub, de carácter público (porque lo vamos a
llamar desde el combo), que conjuntará las dos funciones anteriores a fin de darnos el
resultado deseado.

El código para ese procedimiento sub de nuestro módulo sería:

17
Visítame en http://bit.ly/NckAccess

Public Sub subMsgInfoPartida(vIdPart As Long)
'Declaramos las variables
Dim vDif As Currency
Dim vTotPpto As Currency
Dim vTotMov As Currency
Dim vTP As Long
'Llamamos a la función que nos da el total
presupuestado
vTotPpto = fncTotalPptado(vIdPart)
'Llamamos a la función que nos da el total de
movimientos
vTotMov = fncTotalMovimientos(vIdPart)
'Calculamos la diferencia
vDif = vTotPpto - vTotMov
'Mostramos el msgbox con la información
MsgBox "Total presupuestado: " & Format(vTotPpto, "#,##0.00") & vbCrLf & vbCrLf _
& "Total movimientos: " & Format(vTotMov, "#,##0.00") & vbCrLf & vbCrLf _
& "Diferencia: " & Format(vDif, "#,##0.00"), vbInformation, "RESUMEN DATOS"
End Sub

Sólo remarcar que he aprovechado el texto del msgbox para dar formato a los valores
obtenidos (separador de miles con punto y separador de decimales con coma, con dos
decimales).

Y ya lo tenemos hecho. Ahora sólo queda decirle al combo que nos llame a nuestro
procedimiento. Para ello, en el evento “Después de actualizar” del combo, escribimos el
siguiente código:


Private Sub cboSelPartida_AfterUpdate()
'Comprobamos que haya valor. Si no lo hay no hacemos nada
If IsNull(Me.cboSelPartida.Value) Then Exit Sub
'Llamamos al procedimiento
Call subMsgInfoPartida(Me.cboSelPartida.Value)
End Sub

Como vemos, le pasamos como argumento del procedimiento sub el valor seleccionado en el
combo.

CREÁNDONOS UN INFORME FANTASMA


Lógicamente vamos a querer un informe con todas las desviaciones. Para este proceso
haremos lo siguiente:

• Nos crearemos una tabla como plantilla, que utilizaremos para crear el informe.
• Una vez creado el informe borraremos la tabla.
• Programaremos la creación de esa tabla a través de código.
• Programaremos el llenado de la tabla a través de SQL y código

Evidentemente se podría hacer a través de consultas-objeto y quizá de manera más simple,


pero lo que interesa del ejemplo es saber que lo que os voy a explicar se puede hacer con
código VA con SQL.

18
Visítame en http://bit.ly/NckAccess
Dicho lo anterior vamos a crearnos una tabla plantilla, que llamaremos TReportTotal. Esta tabla
tendrá la siguiente estructura:

Fijaos en que no hay ninguna clave principal. Como la tabla sólo nos va a servir de base para
el informe, y se rellenará con información variable, no necesitamos clave principal.

A continuación nos creamos un informe sobre esta tabla, que llamaremos RReportTotal,
utilizando el asistente. Usaremos el asistente porque vamos a añadir un nivel de agrupamiento
por el campo [TipoPartida] (al seleccionar los campos del informe no necesitamos añadir [Id]).

Es decir, se lo indicamos en este punto:

A ese informe vamos a realizarle un pequeño cambio, para que el usuario lo tenga más claro.
Buscamos el campo [TipoPartida] y situamos su propiedad VISIBLE en no. A continuación
introducimos un cuadro de texto (borramos su etiqueta) y en su interior escribimos la siguiente
expresión:

=Iif([TipoPartida]=1;"INGRESO";"GASTO")

Con esto cambiamos el 1 por INGRESO, y el 2 por GASTO.

En el encabezado del informe podemos añadir un textbox, y en su interior introducimos la


siguiente expresión:

=fncAT()

Así el propio informe nos indicará de qué año estamos hablando.

Vamos a por el procedimiento: el esquema de dicho procedimiento será el siguiente:

• Miraremos si la tabla TReportTotal existe (aunque en teoría no debería existir, lo


hacemos así por precaución y para evitarnos errores posteriores de código).

19
Visítame en http://bit.ly/NckAccess
• Si la tabla existe la borraremos.
• Creamos la tabla en tiempo de ejecución
• Combinamos SQL y recordset para ir obteniendo los datos
que necesitamos, y los añadimos a nuestra tabla.
• Abrimos el informe en vista previa.
• Al cerrar el informe se nos borrará la tabla (recurriremos a
un pequeño truco para ello).

Veamos cómo podemos hacer lo anterior.

En nuestro módulo vamos a crearnos un procedimiento como el


que sigue:


Public Sub subCreaTReportTotal()
'Declaramos las variables
Const miTabla As String = "TReportTotal"
Dim miSql As String
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim rstTReport As DAO.Recordset
Dim tbl As Object
'Comprobamos si la tabla existe. Si existe la borramos
For Each tbl In CurrentData.AllTables
If tbl.Name = miTabla Then
DoCmd.SetWarnings False
DoCmd.DeleteObject acTable, miTabla
DoCmd.SetWarnings True
Exit For
End If
Next tbl
'Configuramos la SQL de creación de tabla
miSql = "CREATE TABLE " & miTabla & " (Id INTEGER, Partida STRING, TipoPartida INTEGER," _
& "TotPpto CURRENCY, TotMov CURRENCY, Dif CURRENCY)"
'Ejecutamos la SQL
DoCmd.RunSQL (miSql)
'Creamos la SQL a través de la cual recorreremos todas las partidas presupuestadas
miSql = "SELECT * FROM TPpto WHERE TPpto.AnoPpto='" & fncAT() & "'"
'Creamos el recordset sobre la tabla TReportTotal
Set dbs = CurrentDb
Set rstTReport = dbs.OpenRecordset("TReportTotal", dbOpenTable)
'Creamos el recordset sobre la consulta SQL
Set rst = dbs.OpenRecordset(miSql)
'Si no hay valores saltamos a Salida
If rst.RecordCount = 0 Then GoTo Salida
'Nos movemos al primer registro
rst.MoveFirst
'Iniciamos el proceso de recorrido de registros
Do Until rst.EOF
'Vamos a rellenar la tabla TReportTotal con la información que tengamos, y, si no la tenemos,
'la buscaremos entre nuestros "recursos"
With rstTReport
.AddNew
'El primer campo [Id] nos lo dará el campo [IdPpto] de la consulta
.Fields("Id").Value = rst.Fields("IdPpto").Value
'El segundo campo [Partida] nos lo dará el campo [Partida] de la consulta
.Fields("Partida").Value = rst.Fields("Partida").Value
'El tercer campo [TipoPartida] nos lo dará el campo [TipoPartida] de la consulta
.Fields("TipoPartida").Value = rst.Fields("TipoPartida").Value
'El cuarto campo [TotPpto] nos lo dará el campo [ImpPartida] de la consulta
.Fields("TotPpto").Value = rst.Fields("ImpPartida").Value
'El quinto campo TotMov nos lo dará nuestra función fncTotalMovimientos, y el argumento de
'la función vendrá dado por el campo [IdPpto] de la consulta
.Fields("TotMov").Value = fncTotalMovimientos(rst.Fields("IdPpto").Value)
'El sexto campo [Dif] nos vendrá dado por la resta del total presupuestado menos el valor
'que nos devuelva la función fncTotalMovimientos
.Fields("Dif").Value = rst.Fields("ImpPartida").Value - fncTotalMovimientos(rst.Fields("IdPpto").Value)

20
Visítame en http://bit.ly/NckAccess
.Update
End With
'Nos movemos al siguiente registro
rst.MoveNext
Loop
Salida:
'Cerramos conexiones y liberamos memoria
rst.Close
rstTReport.Close
dbs.Close
Set rst = Nothing
Set rstTReport = Nothing
Set dbs = Nothing
End Sub

Ahora sólo nos queda llamar a nuestro procedimiento. Para ello, en FMenu, creamos un botón
de comando para abrir el informe, que llamaremos cmbAbreRReportTotal, y le asignaremos el
siguiente código al evento “Al hacer click”:


Private Sub cmdAbreRReportTotal_Click()
'Llamamos al procedimiento
Call subCreaTReportTotal
'Abrimos el informe en vista preliminar
DoCmd.OpenReport "RReportTotal", acViewPreview
'Cerramos el menú
DoCmd.Close acForm, Me.Name
End Sub

Sigamos. No podemos borrar la tabla al cerrar el formulario porque precisamente la tabla es el


Recordsource del formulario. Vamos a utilizar un “rebote” para conseguirlo evitando ese
“inconveniente” que os comentaba.

En el evento “Al cerrar” del formulario generaremos el siguiente código:


Private Sub Report_Close()
DoCmd.OpenForm "FMenu"
'Situamos el enfoque sobre el botón de comando cmdAbreRReportTotal
Forms!FMenu.cmdAbreRReportTotal.SetFocus
End Sub

Como vemos obligamos a que el enfoque se sitúe sobre cmdAbreRReportTotal en cuanto se


abre FMenu. Y aprovecharemos este “hecho fortuito” (convenientemente planeado por nuestro
“frankensteiniano” cerebro) para asignar un código al evento “Al recibir el enfoque” de dicho
botón, que lo que hará será borrarnos la tabla “para no dejar huellas”.

El código sería:


Private Sub cmdAbreRReportTotal_GotFocus()
'On Error Resume Next
'Le damos dos segundos para que se ejecute el código de borrado. Así conseguimos
'tiempo para que se cierre totalmente el informe
Me.TimerInterval = 2000
End Sub

21
Visítame en http://bit.ly/NckAccess

Y ahora programamos el evento del cronómetro.


Seleccionamos pues el evento “Al cronómetro” de FMenu y
le generamos el siguiente código:


Private Sub Form_Timer()
On Error Resume Next
DoCmd.SetWarnings False
DoCmd.DeleteObject acTable, "TReportTotal"
DoCmd.SetWarnings True
'Restablecemos el intervalo de cronómetro a cero para
que deje de actuar
Me.TimerInterval = 0
End Sub

Ved que le he puesto un simple control de errores por si el botón recibiera el enfoque sin
provenir la acción de la apertura del informe. Si no lo hiciéramos así nos daría error de código
porque no encontraría TReportTotal.

Y listos.

¿Y por qué lo de “informe fantasma”? Pues porque si alguien accediera “por detrás” e intentara
ejecutar el informe lógicamente sólo podría un mensaje de error.

PARA FINALIZAR ESTE CAPÍTULO


Este capítulo nos ha servido para ver la utilidad de utilizar los módulos, de combinar SQL con
VBA, y además (espero) nos ha servido para ver unos cuantos “truquillos” para esos
momentos en que “si no funciona algo de frente, pues pruebo por la izquierda, y si no por la
derecha”... je, je...

Espero que todos los capítulos del curso os hayan aportado alguna cosa, por pequeña que sea,
para aprender un “poquito más” cosas de Access y VBA para Access.

Pensad que en la red hay muy buenos foros, hay ejemplos de “monstruos del Access” y hay
otras “cosillas” relacionadas con Access que os pueden ser de utilidad.

Finalmente, también espero que la finalidad marcada en el primer capítulo, que era que al
acabar el curso fuerais capaces de coger cualquier código VBA y, con sus más y sus menos,
fuerais capaces de entenderlo, modificarlo y adaptarlo a vuestras necesidades, se haya
cumplido en gran parte.

Un gran saludo y...

¡suerte!

22
Visítame en http://bit.ly/NckAccess

También podría gustarte