Está en la página 1de 11

CALENDARIO PLANNING MENSUAL1

INTRODUCCIN
Aprenderemos mediante este ejemplo a crearnos un
calendario que nos mostrar las citas que hayamos
introducido en la BD de manera global, en un planning
mensual.
Hay partes del cdigo que no explicar porque requieren
unos ciertos conocimientos de VB. En estos casos slo
explicar la mecnica del cdigo, con ms o menos detalles.
De todas maneras ya sabis que tengo cierta tendencia a comentar todos los cdigos, por lo
que podris (espero) seguir las lneas y lo que hacen.

PREPARATIVOS INICIALES
Vamos a crearnos una tabla donde introduciremos los eventos o citas. Por ejemplo,
supongamos que la BD va a ser para una consulta de un mdico (si entendemos la mecnica
podremos adaptar el ejemplo para cualquier situacin de caractersticas similares). As, vamos
a crearnos una tabla que llamaremos TCitas2, con la siguiente estructura:

Rellenamos esta tabla con algunos valores para tener material de trabajo. Por ejemplo, yo he
utilizado los siguientes:

Nos vamos a crear ahora un formulario sobre TCitas, que llamaremos FCitas. Nos lo
guardamos para despus.
Creamos una tabla para los meses, que llamaremos TMeses, con la siguiente estructura:

1
2

La BD de ejemplo os la podis bajar aqu (versin Access 2003) o aqu (versin Access 2007). Tened en cuenta que
se han detectado problemas de incompatibilidad entre versiones, por lo que os recomiendo bajaros la que
corresponda a vuestra versin de Office.
El ejemplo est simplificado al mximo en cuanto a datos. Lgicamente, con las oportunas adaptaciones,
podramos complicarlo tanto como quisiramos.

Vistame en http://siliconproject.com.ar/neckkito/

Lgicamente, si utilizamos un autonumrico, debemos introducir los meses por orden, para
que nos queden correctamente los meses con su correspondiente nmero de mes.
Finalmente creamos una tabla para introducir los das
festivos del ao. A esa tabla la llamaremos TFestivos, con la
siguiente estructura simple:

Metemos algunos festivos del ao para poder ver cmo quedarn reflejados en nuestro
calendario.

NUESTRO FORMULARIO CALENDARIO


Aqu viene un poquito de trabajo. Vamos a crearnos un formulario en blanco y lo llamaremos
FCalendario.
En el encabezado del calendario nos crearemos un cuadro de texto, que llamaremos txtAno.
Ahora, tambin en el encabezado, aadiremos un cuadro combinado, que a travs del
asistente nos coger los datos de la tabla TMeses. Este cuadro combinado, que llamaremos
cboMes, almacenar la clave principal, es decir, el nmero de mes.
En la seccin detalle vamos a crearnos nada ms y nada menos que 42 cuadros de texto,
dispuestos de la siguiente manera:

Este sera el txt1

Este sera el

,,, y as

txt2

sucesivamente

Es decir, seis filas de siete columnas (ah os ser muy til eso del copy-paste).
A continuacin sacamos las propiedades de las etiquetas de cada textbox y nos vamos a la
pestaa Otras Nombre, y escribimos lblX, donde X es un nmero que va del 1 al 42 (lbl1,
lbl2, , lbl42).
Hacemos lo mismo con los textbox, ponindoles de nombre txtX (txt1, txt2, , txt42).
Creo que la ilustracin de arriba es representativa de lo que os quiero decir
2

Vistame en http://siliconproject.com.ar/neckkito/

Las etiquetas que estn en el encabezado de formulario (las


de los nombres de los dias) vamos a ponerles, como
nombres (Propiedades Pestaa Otras Nombre), los
mismos valores que muestran, pero sin acentos. Es decir,
que la etiqueta que pone Lunes tendr de nombre
Lunes, etc., la de Sbado tendr de nombre Sabado
(sin acento), etc.
Vamos a sacar las propiedades del calendario, y en el
evento Al activar registro le generamos el siguiente
cdigo:

Private Sub Form_Current()


'Asigno el ao del sistema a txtAno
Me.txtAno.Value = Year(Date)
'Assigno el mes 1 al combo
Me.cboMes.Value = 1
'Llamo al evento cboMes_AfterUpdate()
Call cboMes_AfterUpdate
End Sub

Lo que hace este cdigo simplemente es asignar valores a los controles del encabezado y
ejecutar el procedimiento asignado a cboMes_AfterUpdate().
Y qu hace cboMes_AfterUpdate()? Pues si sacamos las propiedades del combo al evento
Despus de actualizar le generamos el siguiente cdigo:

Private Sub cboMes_AfterUpdate()


Dim miAno As Integer, miMes As Integer
miAno = Nz(Me.txtAno.Value, 0)
miMes = Nz(Me.cboMes.Value, 0)
'Si no hay valor en alguno de los controles salimos
If miAno = 0 Or miMes = 0 Then Exit Sub
'Llamamos al procedimiento primeroUltimoMes()
Call primeroUltimoMes(miAno, miMes)
End Sub

El procedimiento simplemente comprueba que los valores de los controles del encabezado sean
correctos y llama al procedimiento primeroUltimoMes(), pasndole como argumentos el ao y
el mes que se hallan seleccionados.

EL FORMULARIO DE INTRODUCCIN DE CITAS


Cogemos nuestro formulario FCitas y creamos un botn de comando, que nos servir para
llamar al calendario. El cdigo de ese botn, que he llamado cmdAbreFCalendario, ser el
siguiente:

Private Sub cmdAbreFCalendario_Click()


DoCmd.OpenForm "FCalendario"

Vistame en http://siliconproject.com.ar/neckkito/

End Sub

A m me ha quedado una cosa as:

CREANDO NUESTRO MDULO


Y ahora viene la parte creativa de cdigo. Vamos a crearnos un mdulo llamado
mdlCalendario. El mdulo que he creado tiene una estructura secuencial; es decir, los procesos
se realizan uno detrs de otro. He preferido hacerlo as porque si tenis que adaptarlo a
vuestras BD's considero que os ser ms fcil. Slo hay dos procedimientos auxiliares, que
estn al final.
Podis consultar el cdigo del mdulo mdlCalendario en el apartado final de este ejemplo. Si le
echis un vistazo os vais a encontrar con lo siguiente:
1.- La declaracin de variables comunes a todo el mdulo
2.- El procedimiento primeroUltimoMes()
Lo que hace este mdulo es determinar qu da es el primero del mes y ao que se ha
seleccionado, y convertirlo en una fecha, adems de obtener qu da de la semana es
(en nmeros, con 1=lunes). Realiza tambin un proceso paralelo, pero para detectar el
ltimo da del mes.
3.- El procedimiento rellenoDias Calendario() lo que hace son dos procesos que podemos
diferenciar claramente:
Primero, calcula qu dias se necesitan para rellenar la primera semana completa; es
decir, que si el primer dia del mes cae en mircoles 01/04/12, por ejemplo, detecta que
para rellenar la semana completa necesita realizar un conteo hacia atrs; es decir,
necesita el 31/03/12 para el martes y el 30/03/12 para el lunes, da en que comienza la
semana.
De la misma manera, realiza el proceso a la inversa para el ltimo da del mes: si cae
en viernes el 30/04/12 realiza un conteo hacia adelante hasta alcanzar el domingo; es
decir, 01/05/12 para el sbado y 02/05/12 para el domingo, da en que se acaba la
semana.
Segundo, calcula el nmero de semanas que tiene el mes analizado: si tiene seis
semanas muestra todos los textbox de FCalendario; si tiene slo cinco semanas
convierte en invisible la tlima semana.

Vistame en http://siliconproject.com.ar/neckkito/

4.- El procedimiento rellenoDatosCalendario lo que hace es rellenar una matriz con una cadena
vaca si no hay cita para ese da, o con una cadena seguida de la informacin de las citas. Ms
o menos as:
infoDia(1) = Cadena vaca
infoDia(2) = Spiderman \ Alergia a las araas\-----\
infoDia(3)
=
MeLoInvento
\
Rotura
brazo
\-----\MeLoInvento2 \ Rotura pie \----\
etc.
De manera que si seguimos el ejemplo el primer da de relleno del
mes de abril hemos detectado que era el 30/03/12; ergo se
establece una correspondencia entre la fecha y el ndice de la
matriz
InfoDia(1) equivalente a 30/03/12
InfoDia(2) equivalente a 31/03/12
etc.
El recorrido por la tabla con la informacin de las citas se realiza a travs de una SQL que filtra
da a da, y un recordset que recoge la informacin de cada uno de los registros.
Lgicamente, la matriz se redimensiona en funcin de si necesitamos la sexta semana o no.
A continuacin realizamos el proceso de recorrer la matriz y traspasar su informacin a los
textbox de FCalendario, estableciendo la siguiente correspondiencia:
InfoDia(1) equivalente a txt1
InfoDia(2) equivalente a txt2
etc.
Aprovechamos el proceso para recorrer tambin la tabla de festivos y, en caso de
concordancia, situamos el color de fondo el textbox cuya fecha coincida con el festivo de un
color amarillo-ocre (para no dificultar la lectura del texto interior). Esto no lo hace aqu, sino
que llama al proceso que s lo hace, y que encontraris en el punto 5 siguiente.
Como curiosidad os dir que cuando rellenamos la matriz lo hacemos utilizando la contrabarra
(\). Lo hago as para utilizar la funcin Replace(), de manera que cuando encuentra una
contrabarra la cambie por un salto de lnea. Eso hace el texto ms legible en el textbox.
Tambin decir que, acabado el recorrido de la matriz y su trasvase de informacin a los
textbox, elimino la matriz para evitar que se inicie un nuevo proceso (un cambio de seleccin
de mes, por ejemplo) y los datos, en lugar de empezar de cero, se acumulen a los existentes,
lo cual sera una autntica catstrofe.
5.- El procedimiento marcaFestivos() lgicamente lo que hace es buscar concordancias entre
los festivos informados en TFestivos y marcarlos en los textbox correspondientes a travs de la
modificacin del color de fondo.
6.- Los procedimientos ocultaSextaSemana() y muestraSextaSemana() son procedimientos
auxiliares y son, evidentemente, llamados cuando se determina si el mes tiene cinco o seis
semanas, para hacer invisible o visible la sexta semana en FCalendario.

Vistame en http://siliconproject.com.ar/neckkito/

Y SI QUIERO ADAPTAR EL EJEMPLO A MI


BD, QU DEBO MODIFICAR?
Ya comentaba que esta tipologa de ejemplos requieren,
para ser entendidos, de unos conocimientos mnimos de
programacin en VBA. Aunque los cdigos estn
ampliamente comentados y por el mtodo de ensayo-error
quiz se pudieran conseguir algunos resultados, quiz
tambin no puedan conseguirse los objetivos propuestos, lo
cual no deja de ser frustrante.
Ante lo anterior slo puedo deciros que en la web, para los usuarios registrados, tenis a
vuestra disposicin un manual de VBA y un manual de SQL. A partir de ah el esfuerzo os
corresponde a vosotros.
Dicho esto os explico dnde hay que meter mano para poder realizar una adaptacin a
vuestras BD's:
1.- Los nombres que he utilizado para FCalendario deberan respetarse escrupulosamente,
aunque si sabemos programar y sabemos lo que hacemos eso no es una condicin excluyente.
2.- El ejemplo se ha basado en la tabla TCitas, con sus campos correspondientes. Podramos
crearnos nuestra tabla propia, con los nombres de los campos que queramos.
3.- El meollo del cdigo, para su adaptacin, se halla en el procedimiento
rellenoDatosCalendario(). Supongamos que ahora nuestra tabla se llama TMisDatos. Nos
situamos en ese procedimiento y
3.1.- Modificamos la SQL de filtro, de manera que
miSql = "SELECT TCitas.NomPac, TCitas.MotivoCita" _
& " FROM TCitas" _
& " WHERE TCitas.FechCita=#" & Format(iDate, "mm/dd/yy") & "#"
nos podra quedar
miSql = "SELECT TMisDatos.nomCampo1, TMisDatos.nomCampo2, , TMisDatos.nomcampoN" _
& " FROM TMisDatos" _
& " WHERE TMisDatos.nomCampoFecha=#" & Format(iDate, "mm/dd/yy") & "#"

Lgicamente es condicin sine qua non que haya un campo fecha (un calendario sin fecha es
difcil de imaginar, verdad? )
3.2.- El bloque DO UNTIL... LOOP, que dice:
Do Until .EOF
contenidoDia = contenidoDia & .Fields(0).Value
'Aado carcter que me har de salto de lnea en Replace
contenidoDia = contenidoDia & "\"
contenidoDia = contenidoDia & .Fields(1).Value
'Aado carcter que me har de salto de lnea en Replace
contenidoDia = contenidoDia & "\"
'Aado una lnea separadora
contenidoDia = contenidoDia & "-----------------------------"
'Aado carcter que me har de salto de lnea en Replace
contenidoDia = contenidoDia & "\"
6

Vistame en http://siliconproject.com.ar/neckkito/

'Me muevo al siguiente registro


.MoveNext
Loop
Deberamos modificarlo en funcin de lo que hayamos
escrito en la SQL, de manera que:
TMisDatos.nomCampo1 equivale a Fields (0)
TMisDatos.nomCampo2 equivale a Fields (1)

TMisDatos.nomCampoN equivale a Fields(N-1)


As, para tres campos, podramos escribir:
Do Until .EOF
contenidoDia = contenidoDia & .Fields(0).Value
'Aado carcter que me har de salto de lnea en Replace
contenidoDia = contenidoDia & "\"
contenidoDia = contenidoDia & .Fields(1).Value
'Aado carcter que me har de salto de lnea en Replace
contenidoDia = contenidoDia & "\"
contenidoDia = contenidoDia & .Fields(2).Value
'Aado carcter que me har de salto de lnea en Replace
contenidoDia = contenidoDia & "\"
'Aado una lnea separadora
contenidoDia = contenidoDia & "-----------------------------"
'Aado carcter que me har de salto de lnea en Replace
contenidoDia = contenidoDia & "\"
'Me muevo al siguiente registro
.MoveNext
Loop
Como veis, no es tan difcil

PARA FINALIZAR ESTE EJEMPLO


Bueno... Poco hay que aadir a lo dicho. Espero que os sea de utilidad si lo utilizis as como
est, o que no tengis problemas en adaptarlo a vuestra BD.
Y, sobre todo, que os sea til.
Un saludo y...
suerte!

CDIGO DEL MDULO


Y este es el cdigo del mdulo mdlCalendario:

Option Compare Database


Option Explicit
'----------------------------------------------------------------------------------------------------------------------'-------Cdigo programado por Neckkito @ http://neckkito.eu5.org
'-------Fecha creacin: 18/06/12

Vistame en http://siliconproject.com.ar/neckkito/

'-------Fecha ltima modificacin: 23/06/12


'-------Requisitos: requiere referencia "Microsoft DAO 3.6 Object Library" o
librera equivalente
'-------Notas: no tiene una aplicacin estndard, porque depende de la
estructura de las tablas y
'
de los formularios, en concreto del formulario llamado
FCalendario.
'
Para entender su uso recomiendo visitar este sitio y analizar el
ejemplo:
'Web: http://neckkito.eu5.org/index.php?
option=com_content&view=article&id=156:calendario-planningmensual&catid=56:ejemplos-especiales&Itemid=55
'---------------------------------------------------------------------------------------------------------------------'----------------------------------------------------------------------------------------------------------------------' Declaramos las variables comunes de todo el mdulo
'----------------------------------------------------------------------------------------------------------------------Dim fechaPrimero As Date
Dim fechaUltimo As Date
Dim diaSemanaPrimero As Integer
Dim diaSemanaUltimo As Integer
Dim primerDiaCal As Integer
Dim primerDiaCalFecha As Date
Dim ultimoDiaCal As Integer
Dim ultimoDiaCalFecha As Date
Dim ctl As Control
Dim iDate As Date
Dim i As Long
Dim miSql As String
Dim rst As DAO.Recordset
Dim infoDia()
Dim maxMatriz As Long
Dim contenidoDia As String
Dim diaFestivo As Variant
'----------------------------------------------------------------------------------------------------------------------' Este procedimiento nos calcula en qu da cae el primero y el ltimo de mes, as como
' la fecha completa del primer da del mes y el ltimo.
'----------------------------------------------------------------------------------------------------------------------Public Sub primeroUltimoMes(vAno As Integer, vMes As Integer)
'Obtenemos la fecha completa para el primero de mes
fechaPrimero = DateSerial(vAno, vMes, 1)
'Obtenemos la fecha completa para el ultimo de mes
fechaUltimo = DateSerial(vAno, vMes + 1, 0)
'Obtenemos el da de la semana de ambas fechas
diaSemanaPrimero = Weekday(fechaPrimero, vbMonday)
diaSemanaUltimo = Weekday(fechaUltimo, vbMonday)
'Llamo al procedimiento rellenoDiasCalendario()
Call rellenoDiasCalendario(fechaPrimero, fechaUltimo, diaSemanaPrimero, diaSemanaUltimo)
End Sub
'----------------------------------------------------------------------------------------------------------------------' Este procedimiento nos calcula la fecha necesaria para empezar el calendario en lbl1 y la
' fecha para finalizar el calendario en lbl35 lbl42. Con esos datos nos rellena las fechas del
' calendario cambiando la caption de las labels.
'----------------------------------------------------------------------------------------------------------------------Public Sub rellenoDiasCalendario(F1 As Date, FN As Date, ds1 As Integer, dsN As Integer)
'Calculo cal sera el primer da del calendario
primerDiaCal = ds1 - 1
primerDiaCalFecha = F1 - primerDiaCal
'Calculo cul sera el ltimo da del calendario
ultimoDiaCal = 7 - dsN
ultimoDiaCalFecha = FN + ultimoDiaCal
'Determino si debo mostrar u ocultar la sexta semana
If (ultimoDiaCalFecha - primerDiaCalFecha) <= 35 Then
Call ocultaSextaSemana
Else
Call muestraSextaSemana
End If
iDate = primerDiaCalFecha

Vistame en http://siliconproject.com.ar/neckkito/

'Relleno las etiquetas


For Each ctl In Forms!FCalendario.Controls
If ctl.ControlType = acLabel Then
'Este If me salta las etiquetas con los nombres de los das
If ctl.Name = "Lunes" Or ctl.Name = "Martes" Or ctl.Name =
"Miercoles" Or ctl.Name = "Jueves" _
Or ctl.Name = "Viernes" Or ctl.Name = "Sabado" Or ctl.Name =
"Domingo" Then
'No hago nada
Else
'Slo relleno las etiquetas que estn visibles. Si no estn
visibles es que he ocultado
'la sexta semana, y no hace falta trabajar con ella.
If ctl.Visible = True Then
ctl.Caption = CStr(iDate)

iDate = iDate + 1
Else
Exit For
End If
End If
End If
Next ctl
'Llamo al procedimiento rellenoDatosCalendario()
Call rellenoDatosCalendario(primerDiaCalFecha, ultimoDiaCalFecha)
End Sub

'----------------------------------------------------------------------------------------------------------------------' Este procedimiento nos rellena los textbox con la informacin de la tabla TCitas, utilizando para ello
' un proceso en dos fases
' Fase 1: acumula los valores en una matriz (infoDia)
' Fase 2: traspasa los valores de la matriz a cada textbox correspondiente
'----------------------------------------------------------------------------------------------------------------------Public Sub rellenoDatosCalendario(pdc As Date, udc As Date)
'Compruebo la diferencia entre las fechas "ltimo dia calendario" (udc) y "Primer da calendario" (pdc)
'para saber si he ocultado la sexta semana o no. En funcin del resultado redimensiono mi matriz
If udc - pdc + 1 <= 35 Then
ReDim infoDia(1 To 35)
Else
ReDim infoDia(1 To 42)
End If
'Cojo el valor ms alto de la matriz que se haya creado
maxMatriz = UBound(infoDia)
'Inicializo el ndice de mi matriz infoDia
i=1
'Inicializo el contenido de los datos que contendr la variable contenidoDia
contenidoDia = ""
'Inicio un recorrido de las fechas desde el primer da del calendario (pdc) hasta
'el ltimo da del calendario (udc)
For iDate = pdc To udc
'Creo una SQL sobre la tabla TCitas, filtrada por iDate
miSql = "SELECT TCitas.NomPac, TCitas.MotivoCita" _
& " FROM TCitas" _
& " WHERE TCitas.FechCita=#" & Format(iDate, "mm/dd/yy") & "#"
'Creo un recordset sobre la SQL
Set rst = CurrentDb.OpenRecordset(miSql)
'Si no hay registros relleno el elemento i de la matriz infoDia con una cadena vaca
If rst.RecordCount = 0 Then
infoDia(i) = ""
Else
'Si hay registros los recorro y voy creando los valores que se incluirn
'en mi matriz infoDia
With rst
.MoveFirst
Do Until .EOF
contenidoDia = contenidoDia & .Fields(0).Value
'Aado carcter que me har de salto de lnea en Replace
contenidoDia = contenidoDia & "\"
contenidoDia = contenidoDia & .Fields(1).Value
'Aado carcter que me har de salto de lnea en Replace
contenidoDia = contenidoDia & "\"
'Aado una lnea separadora

Vistame en http://siliconproject.com.ar/neckkito/

contenidoDia = contenidoDia & "-----------------------------"


'Aado carcter que me har de salto de lnea en Replace
contenidoDia = contenidoDia & "\"
'Me muevo al siguiente registro
.MoveNext
Loop
End With
'Asigno el valor al elemento i de mi matriz
infoDia(i) = contenidoDia
End If
'Aumento una unidad el ndice
i=i+1
'Reinicializo contenidoDia
contenidoDia = ""
Next iDate
'Finalmente, relleno los textbox de FCalendario con los contenidos de la matriz
For i = 1 To maxMatriz
For Each ctl In Forms!FCalendario
If ctl.Name = "txt" & i Then
ctl.Value = infoDia(i)
'Aqu reemplazo la contrabarra con un salto de lnea
ctl.Value = Replace(ctl.Value, "\", vbCrLf)
End If
Next ctl
Next i
'Elimino la matriz
Erase infoDia
'Llamo al procedimiento marcaFestivos()
Call marcaFestivos(pdc, udc)
End Sub
'----------------------------------------------------------------------------------------------------------------------' Este procedimiento examina los festivos de TFestivos y si hay coincidencias con el calendario pone el fondo
' del textbox correspondiente
'----------------------------------------------------------------------------------------------------------------------Public Sub marcaFestivos(vpdc, vudc)
'Vuelvo a poner todos los textbox con el fondo blanco
For Each ctl In Forms!FCalendario
If ctl.ControlType = acTextBox Then
ctl.BackColor = vbWhite
End If
Next ctl
'Inicializo i
i=1
'Recorro los das del calendario
For iDate = vpdc To vudc
'Compruebo si el da que examino est marcado como festivo
diaFestivo = DLookup("[FechaFest]", "TFestivos", "[FechaFest]=#" & Format(iDate, "mm/dd/yy") & "#")
'Si diaFestivo es NULL es que no existe en la tabla
If IsNull(diaFestivo) Then
'Aado una unidad a i
i=i+1
Else
'Si no es nulo es que es festivo. Busco el textbox correspondiente y cambio su color de fondo
For Each ctl In Forms!FCalendario
If ctl.Name = "txt" & i Then
ctl.BackColor = RGB(252, 243, 128) 'Marco el festivo en ocre para que no moleste la lectura del texto
End If
Next ctl
'Aado una unidad a i
i=i+1
End If
Next iDate
End Sub
'----------------------------------------------------------------------------------------------------------------------' Este procedimiento oculta la sexta semana si el mes slo necesita cinco semanas para ser mostrado al completo
'----------------------------------------------------------------------------------------------------------------------Private Sub ocultaSextaSemana()
For i = 36 To 42
For Each ctl In Forms!FCalendario

10

Vistame en http://siliconproject.com.ar/neckkito/

If ctl.Name = "lbl" & i Or ctl.Name = "txt" & i Then


ctl.Visible = False
End If
Next ctl
Next i
End Sub
'---------------------------------------------------------------------------------------------------------------------'
Este procedimiento muestra la sexta semana si el mes necesita seis
semanas para ser mostrado al completo
'---------------------------------------------------------------------------------------------------------------------Private Sub muestraSextaSemana()
For i = 36 To 42

For Each ctl In Forms!FCalendario


If ctl.Name = "lbl" & i Or ctl.Name = "txt" & i Then
ctl.Visible = True
End If
Next ctl
Next i
End Sub

11

Vistame en http://siliconproject.com.ar/neckkito/

También podría gustarte