Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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
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:
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
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.
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.
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:
4
Visítame en http://bit.ly/NckAccess
llamaremos cmdCerrar.
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:
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:
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:
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.
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.
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.
…
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
…
…
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].
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
…
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.
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
…
…
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
…
…
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
…
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.
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.
…
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!
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.
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
…
Private Sub cmdCancelar_Click()
DoCmd.Close acForm, Me.Name
End Sub
…
• Dejarlo en blanco
• Introducir un valor no numérico
• Introducir un valor numérico, pero no válido como año de trabajo
…
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
…
…
Private Sub cmdCambiaAT_Click()
'Abrimos FCambiaAT
DoCmd.OpenForm "FCambiaAT"
End Sub
…
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.
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í:
…
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.
…
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:
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”.
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.
• 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
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]).
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")
=fncAT()
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).
…
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
…
…
Private Sub Report_Close()
DoCmd.OpenForm "FMenu"
'Situamos el enfoque sobre el botón de comando cmdAbreRReportTotal
Forms!FMenu.cmdAbreRReportTotal.SetFocus
End Sub
…
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
…
…
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.
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.
¡suerte!
22
Visítame en http://bit.ly/NckAccess