Access

download Access

of 52

Transcript of Access

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 1/52

    Iniciar sesin | HAZTE MIEMBRO! | Ayuda

    Access

    Lo que vamos conociendo de Access 2007 y Access 2010

    27/2/2013 0:03

    Utilizar un subinforme como sustituto de un control TreeView en Access 2010

    Con los problemas y vulnerabilidades cada vez mas frecuentes de los Activex, aunque existan parches para ir tirando, muchos programadores en Accesshan decidido finiquitar el nico control del vetusto Common Controls que segua mereciendo la pena y que careca de una alternativa nativa: el TreeViewControl. El que mas y el que menos se ha elaborado sus propias soluciones recurriendo a lo que tenan a mano en Access, en general jugando con cuadrosde lista o subformularios y el resultado, variable, a veces sorprende por lo sencillo y lo eficiente. Sin embargo, no conozco a nadie que haya optado porutilizar un informe.

    En Access una estructura en rbol se muestra fcilmente, de toda la vida, con un informe agrupado. Puede ser como una fotografa, mas rica, de un ControlTreeView, pero es difcil imaginarse un informe que no sea completamente esttico, sin capacidad de contraer o expandir las ramas. Sin embargo lasversiones 2007 y 2010 de Access aportaron nuevas caractersticas, la Vista Informe en 2007 y la posibilidad de incrustar un subinforme en un formulario en2010 que, bien utilizadas, pueden convertirse en una alternativa, mas sencilla de usar, mas potente y mas bonita que el control original.

    El subinforme como alternativa al TreeView Control

    Desde Access 2007, existe una nueva vista para los informes, la llamada Vista Informe que, al contrario que los informes tradicionales, no est pensada paraimprimir, sino para ver en pantalla; por eso no reparte el informe en pginas, por lo que tampoco se producen los eventos Format o Print, sino que lomuestra todo seguido, y, tambin por eso, admite bsquedas y filtros directamente o eventos mas propios de los formularios, como Click, DblClick,keyDown, etc.

    Desde Access 2010, los subInformes, en Vista Informe, se pueden incluir en un formulario exactamente igual que si fueran subformularios. Pueden serindependientes, o vinculados al formulario principal a travs de las propiedades LinkMasterFields y LinkChildFields.

    Con todos estos ingredientes es fcil imaginar que un informe podra sustituir con ventaja a un control TreeView. Los informes podemos vincularlos a unorigen de datos de forma muy sencilla y sin escribir una sola lnea de cdigo, y podemos agrupar datos con facilidad, mostrando una estructura en ramas.Podemos usar distintos formatos de texto, colores, fondos, formatos condicionales, aadir los campos que queramos, resmenes, totales solo con unosclics de ratn.

    Parece que en todo, en facilidad y posibilidades, superan al control TreeView y que solo les falta una cosa: La facilidad de los controles TreeView paracontraer y expandir ramas. Pues bien, esto tambin es posible con un poco de programacin, mas bien muy poco, un poco de SQL y cuidando algunosdetalles del diseo, nada que no est al alcance la la inmensa mayora de los desarrolladores en Access.

    Aqu tenemos una imagen de un ejemplo de un subinforme ejerciendo de TreeView. Puede descargase la aplicacin de ejemplo enhttp://www.bengoechea.net/utilidades-1/reporttreeview

    Funciona? S, y solo un parpadeo casi imperceptible a la hora de contraer o expandir una rama hace que no sea cien veces mejor que un control TreeView.

    Aunque hay que cuidar algunos detalles en el diseo convencional del informe para que el resultado sea el que buscamos, esta parte no se aleja de lamanera de disear un informe con grupos a la que estamos acostumbrados. Lo que tiene su pequeo truco, que necesita mas explicacin, es la manera dehacer que las ramas se expandan o contraigan.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 2/52

    La consulta origen del informe

    Un informe con grupos se basa en una nica consulta en la que estn contenidas todas las tablas relacionadas entre s por campos en comn. Si a estoscampos en comn aadiramos uno mas de cada lado, cambiando su valor podramos hacer que la consulta no devolviera los registros correspondientes deesa rama, si hacemos, a continuacin de cambiar el valor de ese campo, un requery del informe basado en esa consulta, el efecto ser el de contraer oexpandir la rama.

    A ver si me explico un poco mejor. Tenemos dos tablas, Gnero y Especie, con un campo en comn idGenero; con una consulta que vincule ambas tablasmediante ese campo el resultado ser una relacin de todos los gneros y las especies de cada gnero. Pero podemos incluir un campo mas en cada tabla,bExpandir y bExpandiendo, por ejemplo, y bExpandiendo tendra siempre valor True. Si relacionamos tambin ambas tablas por esos campos, cambiando elcampo bExpandir de la tabla Gnero coincidir o no con el de la tabla Especie y, en consecuencia, se mostrarn o no las especies de ese gnero.

    Ese planteamiento inicial obligara a a cambiar el diseo de las tablas implicadas y a andar cambiando datos en ellas de manera poco justificada, por lo que,partiendo de esa idea, lo que hacemos es utilizar una tabla auxiliar, con el campo en comn y el campo bExpandir, que interponemos entre las dos tablasrelacionadas. No necesitamos modificar ni andar tocando las tablas originales, sino que escribimos en la tabla auxiliar y, en vez utilizar una tabla auxiliar paracada par de tablas relacionadas, utilizamos una sola, con distintas consultas filtradas por el nombre de la tabla del lado uno, que son las que interponemos.

    As sera la consulta original del informe que mostramos arriba si fuera esttico:

    O, si lo prefiere, as sera el texto SQL:

    SELECT Ttulos.*, Grupos.*, cuentas.*

    FROM (Ttulos LEFT JOIN Grupos ON Ttulos.ID_TITULO = Grupos.ID_TITULO) LEFT JOIN cuentas ON Grupos.ID_GRUPO = cuentas.ID_GRUPO;

    Sin embargo, para poder ocultar o mostrar las ramas a voluntad, la consulta qArbolCuentas ha quedado como sta:

    SELECT Ttulos.*, qExpandirTitulo.NombreTablaPadre, qExpandirTitulo.Expandir

    AS ExpandirTitulo, Grupos.*, qExpandirGrupo.NombreTablaPadre, qExpandirGrupo.Expandir

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 3/52

    AS ExpandirGrupo, cuentas.*

    FROM (((Ttulos LEFT JOIN qExpandirTitulo ON Ttulos.ID_TITULO = qExpandirTitulo.idPadre)

    LEFT JOIN Grupos ON qExpandirTitulo.idPadre = Grupos.ID_TITULO)

    LEFT JOIN qExpandirGrupo ON Grupos.ID_GRUPO = qExpandirGrupo.idPadre)

    LEFT JOIN cuentas ON qExpandirGrupo.idPadre = cuentas.ID_GRUPO;

    Es decir, entre Ttulos y Grupos hemos interpuesto la consulta qExpandirTitulo, y, entre Grupos y Cuentas, qExpandirGrupo. Tambin hemos aadido losrespectivos campos Expandir, que cambiamos de nombre.

    Las consultas qExpandirTitulo y aExpandirGrupo, se basan ambas en una nica tabla filtrada porque Expandir sea Verdadero y por un nombre, que podrase aleatorio, y que servir luego para filtrar en la tabla que registros modificar.

    SELECT tblExpandir.Id, tblExpandir.idPadre, tblExpandir.NombreTablaPadre, tblExpandir.Expandir

    FROM tblExpandir

    WHERE (((tblExpandir.NombreTablaPadre)="Grupos") AND ((tblExpandir.Expandir)=True));

    SELECT tblExpandir.Id, tblExpandir.idPadre, tblExpandir.NombreTablaPadre, tblExpandir.Expandir

    FROM tblExpandir

    WHERE (((tblExpandir.NombreTablaPadre)="Ttulos") AND ((tblExpandir.Expandir)=True));

    Como la tabla tblExpandir est de momento vaca, ahora la consulta qArbolCuentas solo mostrara los Ttulos, pues no existen los campo idPadre que seinterponen entre las distintas tablas. Si le aadimos el ID de un ttulo, lo identificamos con el nombre Titulos y le damos al campo Expandir valorVerdadero, se mostrarn todos los Grupos de ese Ttulo, y si cambiamos Expandir a Falso, no se mostrarn, pues qExpandirTitulo solo devuelve losregistros en que Expandir es verdadero.

    Con las consultas creadas, solo nos falta crear el informe y aadirle un par de procedimientos para que busque y modifique el campo Expandircorrespondiente y lo aada si no existe.

    El diseo del informe

    El diseo del informe es bien sencillo, aunque hay algunos detalles que no se deben dejar escapar.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 4/52

    Tiene su origen en la consulta qArbolCuentas, est agrupado por Titulo y por Grupo y muestra los campos Titulo, Grupo y Cuenta y, a la izquierda de losdos primeros, el valor correspondiente de Expandir y, a la derecha de cada uno de ellos, oculto, el ID correspondiente.

    Debemos cuidar que las propiedad Autocomprimible, tanto de los controles que se expanden como de las secciones que los contienen, sea S y, adems,la propiedad Alto Automtico de las distintas secciones (Encabezado de Grupo y Detalle) sea tambin S.

    Si los controles no se comprimen, o si no se comprime la seccin que los contiene, aunque no haya contenido para ese grupo, se muestra en blanco elespacio correspondiente a ese control o a esa seccin y, aparte del derroche de espacio innecesario, el resultado es menos esttico.

    Lo controles solo se comprimen cuando no tienen nada que mostrar y las secciones cuando todos los controles estn comprimidos, as que no podemosaadir a las secciones prcticamente nada que no sean campos de texto que puedan estar vacos; no podemos, por ejemplo, aadir casillas de verificacin obotones. Tampoco podemos ocultarlos o cambiar de tamao sobre la marcha, pues no tenemos los eventos Format y Prine

    La pega que tenemos es que ExpandirGrupo y ExpandiTitulo, devuelven valores 0 y 1, aunque no haya registros que mostrar y que, adems, no queremosmostrarlos as, sino como + y .

    En el campo ExpandirTitulo es mas sencillo, pues, como, al ser el tronco, siempre se mostrar, y no importa que no se comprima. Lo que hacemos con elcampo ExpandirGrupo es cambiarlo por un campo calculado que devuelve un nulo si el Grupo es nulo.

    =SiInm(EsNulo([Grupo]);Nulo;[ExpandirGrupo])

    Y, en ambos campos, para que se muestren como + y , lo que utilizamos es la propiedad Formato, que tiene distintas secciones, separadas por punto ycoma, para valores positivos, negativos, ceros y nulos. En ambos casos, la propiedad formato es:

    +;-;+

    En el caso de la cuenta, no hay un campo Expandir, por lo que utilizamos un campo calculado. txtPunto, cuyo origen es:

    =SiInm(EsNulo([Cuenta]);Nulo;0)

    Y, como lo que queremos es que se muestre una vieta, la propiedad Formato es:

    ;;

    Volviendo a ExpandirTitulo, y puesto que siempre muestra algn registro, no nos ha importado adornarlo un poco poniendo un botn de forma redonda y

    fondo transparente sobre l, para darle un resultado mas aparente

    El cdigo VBA

    Lo que bsicamente hace el cdigo es que, cuando pulsamos sobre el campo ExpandirTitulo o ExpandirGrupo, que en el informe se muestran con + o , secambia por el contrario el valor correspondiente en la tabla tblExpandir para la tabla Titulos o Grupos y, si no exista el registro en la tabla tblExpandir, seaade. A continuacin, hacemos un Requery del informe, que ser lo que produzca el efecto de contraer o expandir la rama.

    Private Sub ExpandirTitulo_Click()

    fFindEditTblexpandir Nz(Me.Ttulos_ID_TITULO), "Ttulos", Not Nz(Me.ExpandirTitulo)

    Echo False

    Me.Requery

    Echo True

    End Sub

    Private Sub TxtExpandirGrupo_Click()

    fFindEditTblexpandir Nz(Me.Grupos_ID_GRUPO), "Grupos", Not Nz(Me.TxtExpandirGrupo)

    Echo False

    Me.Requery

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 5/52

    Echo True

    End Sub

    Estos eventos llaman a un procedimiento en un mdulo general que busca en la tabla tblExpandir el ID y el texto identificativo de la tabla (Ttulos oGrupos) que pasamos como argumento y cambia el valor de el campo Expandir por el que tambin le pasamos. Si no encuentra el registro, llama a otroprocedimiento que lo aade con los valores de los argumentos que hemos pasado al primero. Ninguna cosa del otro mundo, pero, para que quede masclaro, pego el cdigo.

    '---------------------------------------------------------------------------

    ' Procedure : fFindEditTblexpandir

    ' DateTime : 11/02/13 20:33

    ' Author : Chea

    ' Purpose : Abrir un recordset de DAO , buscar por un campo y asignar valor

    '---------------------------------------------------------------------------

    Public Function fFindEditTblexpandir(BuscarlidPadre As Long, sNombreTablaPadre As String, bExpandir As Boolean) As Long

    Dim miBD As DAO.Database

    Dim rstblExpandir As DAO.Recordset

    On Error GoTo fFindEditTblexpandir_Error

    Set miBD = CurrentDb()

    Set rstblExpandir = miBD.OpenRecordset("tblExpandir", dbOpenDynaset)

    With rstblExpandir

    If Not (.EOF And .BOF) Then

    .FindFirst "(idPadre = " & BuscarlidPadre & ") AND ( NombreTablaPadre = '" & sNombreTablaPadre & "')"

    If Not .NoMatch Then

    .Edit

    !Expandir = bExpandir

    .Update

    .Bookmark = .LastModified

    fFindEditTblexpandir = !Id

    Else

    fAddTblexpandir BuscarlidPadre, sNombreTablaPadre, bExpandir

    End If

    Else

    fAddTblexpandir BuscarlidPadre, sNombreTablaPadre, bExpandir

    End If

    .Close

    End With

    Set rstblExpandir = Nothing

    Set miBD = Nothing

    fFindEditTblexpandir_Salida:

    On Error GoTo 0

    Exit Function

    fFindEditTblexpandir_Error:

    MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure fFindEditTblexpandir "

    GoTo fFindEditTblexpandir_Salida:

    End Function

    '---------------------------------------------------------------------------

    ' Procedure : fAddTblexpandir

    ' DateTime : 11/02/13 21:11

    ' Author : Chea

    ' Purpose : Abrir un recordset de DAO , aadir un nuevo registro y asignar valor

    ' : a los campos de ese registro con los valores que se pasen como parmetros.

    '---------------------------------------------------------------------------

    Public Function fAddTblexpandir(lidPadre As Long, sNombreTablaPadre As String, bExpandir As Boolean) As Long

    Dim miBD As DAO.Database

    Dim rstblExpandir As DAO.Recordset

    On Error GoTo fAddTblexpandir_Error

    Set miBD = CurrentDb()

    Set rstblExpandir = miBD.OpenRecordset("tblExpandir", dbOpenDynaset)

    With rstblExpandir

    .AddNew

    !idPadre = lidPadre

    !NombreTablaPadre = sNombreTablaPadre

    !Expandir = bExpandir

    .Update

    .Bookmark = .LastModified

    fAddTblexpandir = !Id

    .Close

    End With

    Set rstblExpandir = Nothing

    Set miBD = Nothing

    fAddTblexpandir_Salida:

    On Error GoTo 0

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 6/52

    Exit Function

    fAddTblexpandir_Error:

    MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure fAddTblexpandir "

    GoTo fAddTblexpandir_Salida:

    End Function

    Hay algo mas de cdigo, por ejemplo, para llamar al evento ExpandirTitulo_Click, cuando pulsamos sobre el botn que cubre el campo, o para detectarpulsaciones de teclas y pasarlas al evento Click correspondiente. No lo ponemos para que quede mas claro el funcionamiento bsico.

    Conclusin

    Los informes, usados generalmente como subinformes, son una alternativa al Control Treeview, sencilla, completamente funcional y con mas posibilidades.Estamos utilizando elementos nativos de Access y algo tan sumamente familiar como son los informes. No vamos a tener que instalar o registrar nada ajenoa Acces, ni vamos a tener nunca problemas por cambio de versiones o caractersticas obsoletas. Se necesita menos cdigo que con un TreeView Control y eldiseo grfico de los informe facilita muchsimo la tarea.

    Se pueden aadir todos los campos que se quiera, del tipo que se quiera y en la posicin que se quiera. No tenemos por qu limitarnos al clsico TreeView.

    Seguramente es mas lento que un TreeView y produce un ligero parpadeo cada vez que hacemos Requery (contraemos o expandimos) Este parpadeo esmas notorio cuanto mas cosas le pidamos al informe, por ejemplo, formatos condicionales, totales y en general todo lo que signifique clculos en el informe,pues los campos afectados tardan una pizca mas el mostrarse. Pero algn precio habra que pagar.

    Publicado por Chea con no commentsArchivado en: Informes,Access 2010,TreeView16/2/2013 23:48

    Apuntes para una seguridad a nivel de usuario en Access 2010 II. Macros de datos

    Despus de casi dos aos tomando impulso, por fin me animo a continuar con la seguridad a nivel de usuario usando las macros de datos. El que consigaacabar este artculo me disculpar por el retraso, pues se dar cuenta de que haca falta tener nimo para ponerse a hablar de las macros de datos: Apenasnadie utiliza macros, el editor y muchas caractersticas son completamente nuevos y las macros de datos son una novedad absoluta en Access 2010, a loque se aade que apenas existen ayuda o facilidades al respecto.

    Tendra que explicar el funcionamiento de las macros, los tipos, sus posibilidades, las macros de datos y, cuando empezara por la forma de usarlas paraasegurar una tabla a nivel de usuario, ya habra escrito todo un tratado, seguramente muy aburrido. As que voy directamente al grano, a empezar dandounas ideas de cmo crear macros que eviten que los usuarios no autorizados expresamente manipulen los datos de las tablas y, a medida que las voyexplicando, mencionar pormenores y detalles de las macros y de su editor. Espero que se entienda algo.

    En el artculo anterior veamos que, para asegurar una base de datos Access, es necesario hacer inaccesible el back-end y dbamos unas pistas acerca decmo protegerlo. Si un usuario sin permiso expreso puede acceder directamente al contenido de las tablas, o, peor an, a su diseo, todo lo hablado aquno sirve para nada. Una vez conseguido esto, podemos abordar la utilizacin de macros de datos para que solo los usuarios autorizados puedan aadir,editar o borrar datos solo en las tablas para las que se les haya concedido permiso. Tenga en cuenta que solo son unos apuntes y que es su propiaresponsabilidad procurar que no queden agujeros en la seguridad.

    Grosso modo, lo que vamos a hacer con las macros es verificar si el usuario tiene permisos para la operacin que est pretendiendo hacer y, si no los tiene,abortarla. Un paso mas adelante, aprovechando de que conocemos el usuario, vamos a guardar en cada registro qu usuario lo crea, lo que aparte de unrudimentario seguimiento de cambios, nos permite dar permisos para que slo el autor de un registro pueda modificarlo.

    Las macros de datos

    Las macros de datos son nuevas en Access 2.010 y el editor de macros, de datos o no, tambin es nuevo, por lo que no es de extraar que haya muy pocopublicado al respecto.

    Las macros de datos estn disponibles en la Vista Diseo de la tabla, en la pestaa Diseo de la cinta de opciones, en el grupo de Eventos de campo,registro y tabla

    Es decir, en Access 2010 las tablas tienen eventos y podemos escribir macros en respuesta a estos eventos. Los evento son Despus de insertar,Despus de actualizar, Despus de eliminar, Validar eliminacin y Antes del Cambio. Desde el punto de vista de la seguridad por usuarios, los tresprimeros son apropiados para registrar al usuario que produce el evento, y los dos ltimos para verificar si el usuario tiene los permisos necesarios y, encaso contrario, abortar la operacin.

    Vamos a empezar por algo muy, muy bsico, impedir que se pueda borrar un registro accidentalmente, pero antes debemos abrir el editor de macros.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 7/52

    El editor de macros

    Da la sensacin de que el editor de macros en Access 2010 est a medio acabar, pues le faltan cosas tan elementales como un men contextual para copiary pegar, que, sin embargo, ya existe en 2013, y la ayuda es mnima. No obstante, lo esencial funciona correctamente y sirve a la perfeccin para nuestropropsito.

    Pinchando en uno de los eventos del desplegable de la cinta de opciones que veamos antes, se abre el editor de macros. Las acciones disponibles varansegn el tipo de macro y el tipo de eventos. Es decir, las macros de datos tienen muchas menos acciones disponibles y los eventos Validar eliminacin yAntes del cambio, menos an. Y, sin embargo, con estas macros se pueden conseguir cosas antes impensables.

    Hemos abierto el editor de macros para el evento Validar eliminacin. A la derecha se muestran todas las acciones disponibles, bien pocas, y a la izquierda

    una ventana de edicin, ms grande con un smbolo mas y un cuadro desplegable en el que podemos elegir la accin que queremos anotar. Si no semostrara el catlogo de acciones, podemos hacerlo visible pulsado en el botn Catlogo de acciones de la cinta de opciones.

    Las acciones se eligen en el cuadro desplegable o se arrastran desde el Catlogo de acciones que tenemos a la derecha. No es un editor donde podamosescribir cdigo, solo elegir entre las opciones que tenemos y tan solo escribiremos algunas expresiones cuando sean parmetros de la accin que hemoselegido.

    Nuestra primera macro

    Vamos a crear nuestra primera macro. En el desplegable elegimos Provocar error.

    Escribimos el valor de los parmetros que nos pide, el Nmero de error, que es el que queramos, y la Descripcin del error, que ser el mensaje que semuestre al producirse el error. Guardamos y ya tenemos nuestra primera macro de datos

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 8/52

    Abra la tabla e intente borrar un registro. Imposible, nos sale el mensaje que hemos puesto en la descripcin del error: Prohibido borrar! y ni en unformulario, ni por cdigo, ni por consulta de eliminacin, ni directamente en la Vista Hoja de datos de la tabla podremos borrar ningn registro.

    Bueno, nos hemos pasado, hemos de dar alguna posibilidad de borrar un registro. Por ejemplo, podemos aadir a la tabla un campo S/No que se llameBorrar, y, si es verdadero, s se puede borrar el registro.

    Ahora, lo que tenemos que hacer con la macro es comprobar el valor del Campo Borrar y, si no es verdadero, provocar el error.

    Vamos a la Vista Diseo de la tabla y abrimos la macro del evento Validar eliminacin. Arrastramos el grupo Si al editor e introducimos las expresiones,para lo cual contamos con la ayuda del estupendo generador de expresiones

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 9/52

    En la condicin escribimos [Borrar] True Entonces, lo que tenemos que hacer es provocar el error, como hemoshecho antes. Pero el cdigo para provocar el error se encuentra despus de Finalizar si, es decir fuera del bloque If..,Endif. Vamos a arreglarlo.

    Observe que el bloque donde estamos introduciendo las expresiones est marcado, delimitado por un cuadrado y con fondo mas oscuro. Si pinchamos conel ratn sobre el bloque de ProvocarError, es ste el que queda marcado y, si movemos el ratn mantenindolo pulsado, el bloque se mueve.

    Pues bien, arrastramos el bloque de ProvocarError dentro del bloque SiFinalizar si y voil, ya tenemos nuestra macro:

    Guardamos la macro, cerramos y comprobamos si podemos borrar. Podremos hacerlo si, previamente, para ese registro hemos marcado el campo Borrarcomo verdadero. Es sencillo y, tal como est, vale para cualquier tabla, por lo que vamos a copiarla para pegar en otras tablas y mandarnos el cdigo porcorreo al trabajo, para hacerlo tambin all.

    Editamos de nuevo la macro.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 10/52

    Como no tenemos marcado ningn bloque, el cdigo se queda mas limpio, mas claro. Podemos observar que nos ha cambiado True por Verdadero, que alas macros les gusta el castellano, incluso a veces no entienden el ingls.

    Arrastramos el ratn para seleccionar el texto, pero no se selecciona nada, en cambio, si pinchamos, se seleccionan los bloques que hemos visto antes. Sitenemos cuidado y/o pulsamos tambin Maysculas o Control al tiempo que el ratn, podemos seleccionar todos los bloques en un bloque nico.

    Buscamos un botn para copiar, pero no existe, pulsamos el botn derecho del ratn y no aparece ningn men (bueno, si tienes instalado tambin Access2013, s aparece) Cmo copiamos? Pues como hacamos antes de los ratones, con Control+C.

    Probamos, abrimos otra macro y pegamos. Se pega correctamente y se replica el texto la macro que habamos copiado.

    Llegados a este punto de lectura, usted ya tiene ganas de probar el editor de macros, pero quiere darse prisa y empezar copiando el cdigo desde este blogDesde dnde, si todo son imgenes? Est bien, ah va el cdigo de la macro:

    [Borrar]True1000Prohibido

    borrar!

    Efectivamente, las macros se guardan como cdigo xml y, si usted copia ese texto y lo pega en el editor de macros, el resultado se mostrar como la macro original. Para pegar, no pinche sobre la ventana de edicin de la macro, sino sobre la pestaa de la ventana.

    Verificar permisos de un usuario

    Ya tenemos nuestra primera macro de datos y consigue algo que resulta imposible en cualquier versin anterior de Access, pero de lo que trata este artculoes de la seguridad a nivel de usuarios y lo que queremos es poder discriminar qu usuarios pueden borrar y cules no. Para ello debemos empezar por unatabla con los permisos de los usuarios, buscar si el usuario actual tiene permiso de borrado y, en caso contrario, provocar un error.

    La cuestin ahora es cmo pasamos a la macro el nombre del usuario para que lo busque en la tabla permisos. Las macros de datos no pueden usarninguna funcin personalizada, ni siquiera Variables Temporales (Variables Locales, que no son globales, s) ni existe ninguna propiedad o funcinincorporada que nos devuelva el usuario de Access o el de Windows y que sea accesible para la macro de datos.

    El truco est en que, aunque no se muestren en el generador de expresiones, se pueden hacer bsquedas en consultas y las consultas pueden utilizar unafuncin personalizada como origen de un campo calculado y que las macros de datos pueden buscar en una consulta igual que en una tabla, aunque, paradespistar, no se muestren en el generador de expresiones ni el Intellisense para las macros. O sea, que podemos tener una consulta que tenga una funcinque devuelva el nombre del usuario y la macro de datos lo lea como si fuera un campo.

    Las macros de datos y las consultas se ejecutan en el Front-End, aunque se alojen en el Back-End, por lo que la funcin que devuelva al usuario debeencontrarse en el Front-End y, si no queremos ir haciendo pruebas mientras diseamos la macro, conviene que el Back-End tenga una copia de estafuncin. Cmo se gestiona el login de cada usuario y cmo se obtiene la funcin que devuelve el nombre del usuario actual es cosa personal de cada cual yno se va a tratar aqu, aunque adelanto que para eso tambin se podran utilizar macros de datos.

    En resumen, la macro debe buscar en una consulta los permisos del usuario actual, obtenido en la consulta mediante una funcin, y si carece de permisopara borrar en esta tabla, producir un error.

    De momento, nos vale con una cosa muy sencillita, basta con que, para cada tabla que queremos proteger, recoja los permisos de cada usuario autorizado.

    Se supone que cada cual tendr construido un slido sistema para el control de los usuarios que pueden entrar en nuestra aplicacin, con usuarios,contraseas, registro de logins, etc., y la forma de recuperar el usuario actual. Sin embargo, para las pruebas no vale cualquier cosa que nos devuelva unusuario, por ejemplo, el usuario de Windows; as que nos hacemos esta funcin.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 11/52

    Public Function fUsuarioActual() fUsuarioActual = Environ("USERNAME") End Function

    Y con la tabla de permisos y la funcin que devuelve el usuario actual, nos podemos montar la consulta que nos devuelva los permisos del usuario actual:

    SELECT tblPermisos.Usuario, tblPermisos.Tabla, tblPermisos.Insertar, tblPermisos.Editar, tblPermisos.Borrar FROM tblPermisos WHERE (((tblPermisos.Usuario)=fUsuarioActual()));

    Y se ve as:

    Macro Validar Eliminacin

    Ahora en nuestra macro Validar eliminacin podemos consultar fcilmente si el usuario actual tiene permiso para borrar y, en caso contrario, se loimpedimos. Esto en una macro, se refleja as:

    Estudiemos un poco la macro, pues hemos metido alguna cosa nueva y, aunque parezca muy sencilla, tiene su intrngulis.

    Est claro que hacemos una bsqueda en la consulta qPermisos con la condicin de que el campo Tabla sea Contactos.

    En vez de comprobar directamente el campo [Borrar], lo hemos pasado a una variable local de nombre PermisoBorrar, que es la que comprobamos despusPorqu?

    Fjese en tenemos en bloques distintos Buscar un registro en y Si Nz(PermisoBorrar. Ocurre que las macros son muy pueteras y hay que tener muchocuidado con dnde va y qu va en cada bloque y, dependiendo de esto, la lgica cambia por completo. Fuera del bloque Buscar un registro en qPermisos,el campo [Permisos].[Borrar] no existe y por eso lo pasamos a una VariableLocal, PermisosBorrar, que tiene alcance en cualquier lugar de la macro.Observe que luego la forma de llamar a la variable es como a un campo, con el nombre entre corchetes.

    Podramos haber metido el bloque de Si Nz(PermisoBorrar. dentro del de Buscar un registro en y as nos ahorrbamos la VariableLocal? Efectivamente,pero ya hemos comentado que al meter un bloque en otro cambia la lgica.

    En un bloque Buscar un registro en las acciones que vayan dentro de l solo se ejecutan si se ha encontrado el registro buscado, de manera que, si noencuentra los permisos del UsuariActual, no se ejecutara el cdigo que provoca el error y el registro se borrara sin ningn problema.

    Puede tener su lgica que los usuarios para los que no se han establecido permisos para una tabla puedan borrar en sta, pero resulta mucho mas seguroal revs, que solo los usuarios a los que expresamente se ha dado permiso puedan borrar en la tabla. Tal como est la macro, si no existe el usuario para latabla Contactos, no se ejecuta lo que hay dentro del bloque Buscar un registro en y, por tanto, no se establece la VariableLocal, de manera que en elsiguiente bloque no la encuentra y Access provoca un error y muestra un msgbox con No se encontr el identificador [PermisoBorrar]., de forma que no

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 12/52

    se puede borrar un registro. Es decir, si no existe el usuario, se produce un error de Access en la macro y no se puede borrar.

    Ya tenemos completa la macro Validar eliminacin y abajo pegamos el cdigo xml. Si quiere trasladar esta macro a cualquier tabla, cpielo al portapapeles,abra la tabla en Vista Diseo, edite la macro, posicione el ratn sobre la pestaa y pulse Control+V. Solo le falta cambiar en la Condicin Where el nombrede la tabla.

    [Borrar]True1000No se

    puede borrar sin haber marcado

    previamente el campo

    [Borrar]qPermisos[Tabla]="Contactos"PermisoBorrarNz([Permisos].[Borrar])Nz([PermisoBorrar])True2000Usted

    no tiene permisos para

    borrar

    Macro Antes del cambio

    Todo lo que hemos contado para la macro Validar eliminacin es vlido para la macro Antes del cambio, por tanto, copiar y pegar y corregir algunascosillas nos puede valer para empezar, aunque en la macro Antes del cambio hay que tener en cuanta alguna cosa mas.

    Copiamos al portapapeles la macro Validar eliminacin, abrimos la macro Antes de cambio, nos posicionamos en la pestaa y pegamos pulsandoControl+V. Borramos el bloque de If Borrar Verdadero... Dentro del bloque Buscar un registro en, cambiamos la variable local PermisoBorrar porPermisoEditar y la expresin Nz([Permisos].[Borrar]) por Nz([Permisos].[Editar]) y, despus, en el bloque If, [PermisoBorrar] por [PermisEditar] y en elmensaje de error borrar por editar, y el cdigo de error por un nmero distinto.

    La macro queda as:

    Con esto debera valernos. Probamos y funciona. Sin embargo, falta algo

    Macro Antes de insertar?

    No. No existe la macro de datos Antes de insertar, pero tenemos que saber de alguna manera si estamos intentando insertar un nuevo registro. Paraello contamos con la propiedad EsInsertar

    Propiedad EsInsertar

    En la macro Antes del cambio (y tambin en la macro Despus de Actualizar) podemos consultar la propiedad EsInsertar. (La escasa informacin quehay sobre macros de datos de Access en internet est ingls, y en ingls es IsInsert, sin embargo, si tratamos de utilizar IsInsert en nuestro Access enCastellano, no lo reconocer)

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 13/52

    Entonces, en nuestra macro Antes del cambio debemos comprobar tambin si se trata de insertar y, en ese caso, comprobar en la tabla permisos si haypermiso para insertar y actuamos en consecuencia.

    No es necesaria una nueva bsqueda. En la misma bsqueda aadimos una variable local mas, PermisoInsertar, y le asignamos el valor del campo insertar..En un bloque siguiente, comprobamos la propiedad EsInsertar y, si es verdadera, verificamos el valor de PermisoInsertar y, si no, el de PermisoEditar y, sino lo hay, provocamos un error.

    Lo probamos y funciona, as que ya podemos pegar el cdigo xml por si alguien mas lo quiere probar.

    qPermisos[Tabla]="Contactos"PermisoEditarNz([Permisos].[Editar])PermisoInsertar[permisos].[insertar][IsInsert]Nz([PermisoInsertar])True4000Usted no tiene permisos para Insertar

    Nz([PermisoEditar])True3000Usted no tiene permisos para Editar

    Lo mismo que con la macro Validar eliminacin, podemos pegarlo en cualquier tabla y solo tendramos que cambiar en la Condicin Where el nombre dela tabla.

    Incluyendo estas dos macros en cualquier tabla, conseguimos que ningn usuario que no est expresamente autorizado pueda insertar, editar o borrarningn registro. Obviamente, antes hay que asegurarse de que no tenga acceso directamente al back-end, pues podra modificar las macros o la tablapermisos, a la que tambin deberamos dar permisos, y de que contamos con un sistema de identificacin de usuario y verificacin del inicio de sesinsuficientemente seguros, pero eso corresponde al lector y va mas all de lo que se puede tratar en este artculo.

    Identificar al usuario que crea cada registro

    Tal como hemos dejado las macros, son suficientes para asegurar una tabla, pero hemos afirmado que bamos a dar un paso mas y lo vamos a hacer.Primero, vamos a identificar en cada registro qu usuario lo ha creado y. luego, vamos a aadir un tercer tipo de permiso, aparte de s o no, que solo elusuario que ha creado el registro pueda editarlo o borrarlo.

    Lo de identificar al usuario es sencillo. Tenemos que aadirle un campo mas a nuestra tabla, que llamaremos CreadoPor. En la macro aadimos unaVariableLocal mas, [Usuario], y, si EsInsertar asignamos a CreadoPor el valor de [Usuario] utilizando la accin de macro EstablecerCampo. As:

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 14/52

    Pero surge una pega: cualquiera podra modificar el valor del campo CreadoPor y, por tanto editar o borrar el registro. Tenemos que evitarlo; si noEsInsertar y alguien intenta modificar el campo CreadoPor debemos provocar un error, pero Cmo saber si se intenta modificar un campo concreto?

    Funcin Actualizado

    En la macro Antes del cambio la funcin Actualizado (Nombre de campo) nos dice si el campo cuyo nombre pasamos en una cadena como argumentose ha cambiado. Entonces, en nuestra macro podemos comprobar, si no EsInsertar, si Actualizado (CreadoPor) es verdadero y, en ese casoprovocamos un error para evitarlo. La parte final de la macro (no cabe entera en la pantalla para copiarla) queda as:

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 15/52

    Objeto Antiguo

    Provocando un error hemos evitado que se cambie el valor de CreadoPor, pero resulta muy poco amable bloquear la edicin de todo un registro porque elusuario ha intentado modificar un campo que no deba A lo mejor ha sido sin querer! Lo que podemos hacer es, en vez de provocar el error, volver el valordel campo a su estado original, y para eso contamos con el objeto Antiguo. Basta con escribir Antiguo. en una expresin y el Intellisense nos muestra loscampos a los que se puede aplicar

    Si queremos se mas amables, podemos sustituir la accin de ProvocarError por una de EstablecerCampo en la que el valor original se sustituye por elAntiguo. El final de la macro modificada queda de la siguiente manera.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 16/52

    Y el cdigo xml:

    qPermisos[Tabla]="Contactos"PermisoEditarNz([Permisos].[Editar])PermisoInsertar[permisos].[insertar]UsuarioActual[permisos].[Usuario][IsInsert]Nz([PermisoInsertar])True4000Usted no tiene permisos para InsertarCreadoPor[UsuarioActual]Nz([PermisoEditar])True3000Usted no tiene permisos para EditarUpdated("Contactos.CreadoPor")CreadoPor[Old].[CreadoPor]

    Permitir cambios solo al usuario que ha creado el registro

    No tiene mucho sentido identificar al usuario que ha creado el registro y que luego lo pueda editar cualquiera. Una alternativa es identificar tambin al usuarioque modifica el registro, para lo necesitaramos un nuevo campo, ModificadoPor, al que le daramos valor de la misma manera que a CreadoPor, solo quecuando no sea EsInsertar (estara bien aadir tambin campos de fecha para la creacin y la modificacin). Otra alternativa, que no es incompatible con laanterior, es crear un sistema de permisos en el que, en los que Borrar y Editar tengan valores equivalentes S, No y Slo los registros creados por m,que es lo que vamos a hacer ahora.

    Empezamos por modificar la tabla de permisos, cambiando Editar y Borrar de S/No a numrico con los valores 0,1,2 (No,S y Los propios)

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 17/52

    Ahora, en la macro tenemos que comprobar, si no es EsInsertar, si tiene permisos para editar todo o solo para editar los registros propios y, en ese caso,verificar el creador del registro.

    La parte de la macro que comprueba los permisos para modificar queda as:

    Y el cdigo xml de la macro definitiva Antes del cmbio es el siguiente:

    qPermisos[Tabla]="Contactos"PermisoEditarNz([Permisos].[Editar])PermisoInsertar[permisos].[insertar]UsuarioActual[permisos].[Usuario][IsInsert]Nz([PermisoInsertar])True4000Usted no tiene permisos para InsertarCreadoPor[UsuarioActual]Nz([PermisoEditar])True[PermisoEditar]=03000Usted no tienepermisos para Editar[PermisoEditar]=2[Contactos].[CreadoPor][usuarioActual]6000Slo puede modificar registros en la tabla 'Contactos' si es el creador del registro

    Updated("Contactos.CreadoPor")CreadoPor[Old].[CreadoPor]

    Ya solo nos queda hacer los cambios en la macro Validar eliminacin para que pueda permitir borrar los registros propios. Como es similar a lo que hemosvisto, me limito a pegar el cdigo xml.

    [Borrar]True1000No se puede borrar sin haber marcado previamente el campo [Borrar]

    qPermisos[Tabla]="Contactos"PermisoBorrarNz([Permisos].[Borrar])UsuarioActualNz([Permisos].[Usuario])Nz([PermisoBorrar])=False2000Usted no tiene permisos para borrar

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 18/52

    [PermisoBorrar]=2[Contactos].[CreadoPor][UsuarioActual]5000Slo puede borrar aquellos registros creados por vd.

    Conclusin

    Las macros en Access 2010 no seran difciles si las utilizramos con frecuencia, pero eso nunca va a ser ocurrir pues, para casi todo, es mas sencillo y mascmodo utilizar VBA con el que, adems, podemos llegar mucho mas lejos. Sin embargo, las macros de datos nos permiten hacer cosas impresionantes,impensables en versiones anteriores de Access e imposibles de hacer con cdigo VBA, por lo tanto, merece la pena pagar el precio de trabajar, aunque seatorpemente, con estas macros pesadas y pueteras e ir aprendiendo algo.

    A las macros de datos les queda recorrido aparte de lo tratado aqu. No hemos vistos nada de las otras macros de datos, las de despus de, ni de lasmacros de datos con nombre. Desde el punto de vista de la seguridad a nivel de usuario, nos permitiran, por ejemplo, hacer un seguimiento de cambios,con registro del usuario que los realiza y del valor anterior. Algn da, espero no tardar tanto como en esta ocasin, escribir sobre ello.

    Publicado por Chea con no commentsArchivado en: Access 2010,Macros de datos,Seguridad30/5/2011 17:28

    Apuntes para una seguridad a nivel de usuario en Access 2010. Proteger el back-end

    Las versiones de Access anteriores a la 2007 incluan un sistema de seguridad a nivel de usuario basado en grupos de trabajo bastante completo salvo porel hecho de que, al menos en los ltimos aos, no serva absolutamente para nada. Resultaba del todo intil identificar usuario y contrasea y asignarpermisos en consecuencia si, con una sencilla bsqueda en intern, encontrbamos varias aplicaciones gratuitas con las que piratear las contraseas. Enconsecuencia, en Access 2007 se abandona esta seguridad tan insegura.

    A cambio, no se ha implementado ningn sistema de seguridad a nivel de usuario, aunque se afirma que la seguridad ha mejorado notablemente, puesahora las bases de datos se pueden proteger por contrasea al tiempo que se cifran por un algoritmo muy seguro. A partir de ese cifrado con contrasea,cada uno debe implementar su propio sistema de seguridad por usuarios. Tambin podramos guardar los datos en SQL-Server o en Sharepoint, utilizar laseguridad de stos y olvidarnos de crear la nuestra propia, pero esto a menudo no es asequible.

    Con archivos accdb, que es de lo que vamos a tratar, una posibilidad interesante es crear un sistema basado en los eventos de datos de Access 2010, deesa manera la lgica de la seguridad se traslada al back-end y se centra en las tablas en vez de hacerlo en la aplicacin que las maneja.

    Pero, para que el sistema sea seguro, tenemos que conseguir que el back-end sea completamente inaccesible para quien no cuente con los permisosnecesarios y que ello no le impida ser accesible desde el fornt-end. La solucin para esto ya est estudiada y vale lo mismo para Access 2007 que paraAccess 2010; ser de lo que tratemos en este artculo y dejaremos para otro posterior cmo usar las macros de eventos de datos de Access 2010 paraasegurar nuestros datos y, en un tercero, veremos cn utilizar las macros de datos para hacer un archivo de seguimiento, un log, de los cambios en losdatos del back-end.

    Proteger el back-end en Access 2007/2010

    A partir de Access 2007, si protegemos nuestros datos con una contrasea, quedan a buen recaudo, puesto que la contrasea es mucho ms segura queen versiones anteriores y, adems, los datos se cifran.

    El problema est en cmo hacer que nuestra aplicacin acceda a esos datos sin que la contrasea quede expuesta. Podemos evitar tener tablas vinculadas yabrir los recordsets de todos los objetos mediante cdigo, pero eso resulta pesado y se pierde la sencillez, que es la principal ventaja de Access. Al vinculartablas de una BD protegida, Access pide la contrasea y la guarda en la propiedad Connect del objeto TableDef correspondiente a esa tabla, de manera quebasta con leer la propiedad Connect de la tabla correspondiente para conocer la contrasea

    Es lo que se plantea en este hilo en UtterAccess http://www.utteraccess.com/forum/Access-2007-security-t1242310.html&p=1243573#entry1243573 y ahmismo proponen una solucin que, aunque luego se complica, es bastante sencilla y es de la que partimos: Las tablas se vinculan sin contrasea, lo cual alintentar abrirlas producira un error, pero al inicio de la aplicacin creamos, mediante cdigo en el que indicamos la contrasea, un recordset que se mantieneabierto toda la aplicacin y, al quedar abierta la conexin con la BD protegida, es innecesario indicarle de nuevo la contrasea, por lo que podemos abrir lastablas vinculadas.

    Ocurre algo parecido cuando utilizamos conexiones ODBC, que la contrasea se guarda y queda accesible, y la solucin es la misma, no guardar la conexincon contrasea, abrir una conexin mediante cdigo y mantenerla abierta durante toda la aplicacin. En http://blogs.office.com/b/microsoft-access/archive/2011/04/08/power-tip-improve-the-security-of-database-connections.aspx, otra vez en guiri, nos cuentan cmo hacerlo.

    El cdigo puede hacerse inaccesible, por ejemplo, convirtiendo la aplicacin en ACCDE y/o protegiendo a su vez, previamente, el proyecto VBA con otracontrasea. De esta manera, las tablas slo se pueden abrir desde nuestra aplicacin y, desde ella, controlamos quin y cmo puede acceder a los datos.Cualquiera podra importar nuestras tablas vinculadas desde otra BD, pero no sabiendo la contrasea, no le servira de nada. Tambin podra, si es unusuario autorizado, abrir directamente a las tablas de nuestra aplicacin y saltarse as los permisos que damos mediante cdigo, pero eso tambin podemosevitarlo, por ejemplo, comprobando que la aplicacin se ejecuta en modo runtime justo antes de abrir el recordset que proporciana la clave al resto de laaplicacin y, cuando sepamos asegurar los datos con macros de datos, ni siquiera podrn modicar nada sin permiso, aunque accedan a las tablas.

    En resumen, los pasos para proteger nuestro back-end de una forma muy sencilla seran los siguientes:

    1- Vincular las tablas del back-end antes de cifrarlo con contrasea (de esa manera la contrasea no se guardar en la propiedad Connect)

    2 - Cifrar con contrasea el back-end

    3 - Al inicio de nuestra aplicacin abrir un formulario invisible (o un mdulo de clase) en el que asignaremos la contrasea mediante cdigo, y quemantendr abierta la conexin con el back-end durante toda la aplicacin.

    Este ltimo punto puede parecer difcil, pero es sencillo hacindolo de la siguiente manera:

    Vinculamos una tabla con datos irrelevantes. Nos pedir contrasea y se guardar, pero ms tarde la borraremos. Como ya existira esa

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 19/52

    misma tabla vinculada, se guardar con el mismo nombre y un ordinal, por ejemplo TablaTonta1.

    A partir de la tabla recin vinculada, creamos el formulario con sus campos.

    Cambiamos la propiedad Origen del registro del formulario para dejarla en blanco.

    En el evento Load del formulario abrimos un recordset que tome los datos de la BD protegida y lo asignamos como recordset delformulario.

    Private Sub Form_Load()

    Dim rs As DAO.Recordset

    Set rs = CurrentDb.OpenRecordset("SELECT TablaTonta.* FROM TablaTonta IN '' [MS Access;PWD=Anchoas de Santoa;DATABASE=C:\Users\Chea\Documents\Back-end protegido.accdb]", dbOpenDynaset)

    Set Me.Recordset = rs

    End Sub

    Probamos que el formulario se abre correctamente y cambiamos la propiead Visible del formulario a No.

    Hay un truco para obtener fcilmente una cadena SQL correcta que abra un recordset de una tabla en una BD externa protegida porcontrasea:

    En el editor de VB abrimos la ventana de inmediato, decimos que nos imprima la propiedad Connect de la tabla que tenemos vinculadacon contrasea y copiamos el texto de la propiedad connect al portapapeles

    Abrimos el asistente para consultas para crear una nueva consulta y, antes de aadir una nueva tabla, copiamos el texto de la propiedadConnect a la propiedad de la consulta Cadena de conexin de origen

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 20/52

    Aadimos ahora la tabla que queramos. Observe que lo que se muestra ahora son las tablas y consultas de la base protegida (S, he dichoconsultas, se puede hacer un Select a una consulta de una BD externa)Seleccionamos los campos que queramos y copiamos el texto SQL resultante.

    Con ese texto SQL podemos crear el recordset que asignaremos como origen de nuestro formulario.

    Borramos la tabla que acabamos de vincular con contrasea: Ya no la necesitas, la nica mencin a la contrasea que existe en nuestraaplicacin est oculta en el cdigo que asigna el recordset al formulario oculto.

    Ya tenemos la manera de abrir una conexin con el back-end protegido que, permaneciendo abierta durante toda la aplicacin, permita abrir otras tablas deese back-end sin necesidad de indicar de nuevo la contrasea. Es decir, tenemos la llave para abrir los datos protegidos, slo queda verificar el usuario antesde usar esa llave, por ejemplo, en el mismo formulario oculto, antes de asignar el recordset, podemos comprobar el usuario y sus permisos y, si no son losadecuados, en vez de asignar el recordset del formulario cerramos la aplicacin. La manera de controlar usuario y permisos depende de cada cul y no tienemayor complicacin, cuanto ms personal sea, ms segura, pero una forma muy sencilla podra ser tener una tabla con usuarios contraseas y permisos enel back-end, con la que abriremos, mediante cdigo, un recordset de la misma manera que hacamos con la tabla tonta, para verificar los permisos,procurando primero haber borrado cualquier vnculo a la tabla.

    Con estos sencillos pasos conseguimos que no se pueda acceder a nuestros datos directamente, sino solo a travs de nuestra aplicacin, de manera quepodemos controlar quin y cmo lo hace. Es bastante seguro para lo fcil que resulta, pero en el propio hilo en UtterAccess que citbamos ms arriba,advierten de posibles grietas y posibles soluciones.

    La pega es que estamos protegiendo, o accediendo, a todo el archivo de back- end a la vez, y, si queremos dar permisos ppersonalizados por usuarios ytablas, debemos hacerlo por cdigo, que slo controla la edicin de datos cuanto se hace a travs de un formulario. El problema ms obvio es que desdeuna instalacin completa de Access, un usuario autorizado para abrir la aplicacin puede pulsaf F11 para hacer que se muestren las tablas y editar los datos,saltndose todo el sistema de autorizaciones que hayamos implementado mediante cdigo en los formularios.

    Si estamos usando Access 2007, se me ocurre la solucin de forzar a que la aplicacin se ejecute en modo runtime, que no muestra las tabla; simplementebastara con verificar en el formulario de apertura si SysCmd(acSysCmdRuntime) es verdadero y, en caso contrario, cerrar la aplicacin. Otra opcin seratener varios archivos de back-end agrupando las tablas por niveles de privilegios.

    En cambio, si usamos Access 2010, cabe otra posibilidad, utilizar macros de datos en el back-end que comprueben los permisos del usuario antes deinsertar, modificar o borrar datos en la tabla y, si carece de ellos, provocar un error que impida la actualizacin. Toda la lgica de la seguridad por usuariosse traslada al back-end, se centraliza y se hace ms sencilla y, por tanto, ms segura. De ello trataremos en un prximos artculo.

    Lo que aqu se ha expuesto no es ms que unos apuntes que puedan servir de punto de partida para que cada cual desarrolle su propio sistema deseguridad; no obstante, sin complicar demasiado las cosas, podemos tomar algunas medidas adicionales:

    Verificar que UserControl sea verdadero para evitar automatizacinComprobar que CodeProject es el mismo que CurrentProject para evitar la carga como libreraProteger con contrasea el proyecto VBA y convertirlo en ACCDE.Sustituir el formulario por un mdulo de clase en el que el recordset sea Friend.Ocultar las tablas utilizando el atributo dbHiddenObject.

    En un prximo artculo veremos, cmo utilizando un back-end cifrado con contrasea, podemos valernos de las macros de eventos de datos de Access2010 para impedir que un usuario no autorizado pueda insertar, modificar o borrar datos, incluso aunque tuviera acceso a las tablas vinculadas del front-ed.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 21/52

    Publicado por Chea con 2 comment(s)Archivado en: Access 2007,Access 2010,Macros de datos,Seguridad23/5/2011 22:49

    Gestin de turnos de trabajo con Access

    En determinadas empresas, o en determinados servicios, se trabajan muchas ms horas a las semana de las que puede hacer un trabajador. Serviciosmdicos, polica, bomberos, fundiciones, funerarias, etc. dan servicio 24 horas al da 7 das a la semana y, como no hay ningn trabajador capaz de tanto,deben hacer distintos turnos que cubran todo el servicio. Tambin es necesario hacerlos en empresas, como centros comerciales, que sin abrir 24 horasabren ms horas, o durante ms das, de lo que corresponde a una jornada laboral normal.

    Los turnos son distintos dependiendo del tipo de trabajo, necesidades de la empresa, etc., por ejemplo, puede resultar que, dado el tipo de trabajo, por lanoche se necesito menos personal, que se cierren los domingos o que no se cierre nunca, que se tenga derecho a ms o menos das de descanso, etc.Dependiendo de esas necesidades, cada empresa organiza sus turnos de una manera distinta pero los resultados tienen cosas en comn: Se elabora unasecuencia de los distintos turnos o tipos de jornada que debe hacer un trabajador y se organiza a los trabajadores en grupos, de manera que empezandocada uno la secuencia en una fecha distinta, se solapen unos con otros y cubran toda la jornada.

    Supongamos un caso muy sencillo: Cuatro trabajadores deben cubrir maana tarde y noche y libran un da de cada cuatro. La secuencia sera maana,tarde, noche, libre MTNL y cada trabajador la iniciara con un da de diferencia.

    Trabajador 1: MTNLMTNLMTNLMTNLMTNL

    Trabajador 2: TNLMTNLMTNLMTNLMTNLM

    Trabajador 3: NLMTNLMTNLMTNLMTNLMT

    Trabajador 4: LMTNLMTNLMTNLMTNLMTN

    Cada columna representa un da y con este esquema se garantiza que todos los das haya un trabajador de tarde, otro de noche y otro librando.

    La mayor parte de los esquemas sern ms complejos que ste, pero lo normal es que todos tengan una secuencia de turnos fija comenzando en distintomomento para cada grupo de trabajadores. Tomando esas secuencias y esos grupos como punto de partida, vamos a proponer una serie de soluciones quefaciliten la gestin de grupos de trabajo utilizando una aplicacin hecha en Access.

    Averiguar el turno para una fecha

    Necesitamos saber qu turno de trabajo le corresponde a un trabajador o grupo en determinada fecha. La primera tentacin puede ser recorrer un buclepartiendo desde un turno conocido, sin embargo, hay otro planteamiento que resulta familiar, pues es el del calendario, es decir, de la misma manera queordenamos las fechas, que son nmeros consecutivos, en 7 columnas, una para cada da de la semana, y luego podemos mediante una funcin saber quda de la semana es una determinada fecha, podemos ordenarlas en tantas columnas como tenga la secuencia.

    Enero:

    M T N L

    1 2 3

    4 4 6 7

    8 9 10 11

    12 13 14 15

    16 17 18 19

    20 21 22 23

    24 25 26 27

    28 29 30 31

    Para averiguar la columna que corresponde a un determinado item, hace aos que descubr el Mediterrneo al hacerme esta funcin:

    '---------------------------------------------------------------------------------------

    ' Procedure : fColumna

    ' DateTime : 17/10/10 15:10

    ' Author : Chea

    ' Purpose : Dada una relacin de nmeros consecutivos ordenados en columnas, devuelve la

    ' columna que le corresponde a un determinado item

    '---------------------------------------------------------------------------------------

    '

    Public Function fColumna(item As Long, Columnas As Long) As Long

    fColumna = 1 + ((item + Columnas - 1) Mod (Columnas))

    End Function

    La funcin vale para resolver muchos problemas si se pueden plantear a partir de nmeros consecutivos ordenados en columnas, pero es algo genrico quepresupone que la primera columna es el nmero 1, lo cual, como en el ejemplo, no siempre es el caso y tenemos que considerar en qu columna seencuentra el nmero 1. Para eso con los turnos de trabajo he creado una funcin especfica.

    '---------------------------------------------------------------------------------------

    ' Procedure : fTurnoFecha

    ' DateTime : 17/10/10 15:12

    ' Author : Chea

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 22/52

    ' Purpose : Dada una determinada cadencia de turnos expresada en una cadena, sCadena, en la que

    ' los turnos vienen separados por comas, obtiene el turno que corresponde a una determinada

    ' fecha, FechaCalculo. Es necesario conocer una fecha de referencia, PrimerDiaTurno,

    ' que coincida con el primer da de la cadencia.

    ' Usando una fecha fija como PrimerDiaturno,podemos pasar un parmetro opcional,

    ' lDesplazamiento, para indicar cuantos das nos desplazamos del PrimerDiaturno.

    ' Por ejemplo, podemos tener distintos grupos, cada uno empezando en un da

    ' distinto, el primero tendr desplazamiento 0, el segundo empezar un da ms tarde, etc.

    '---------------------------------------------------------------------------------------

    '

    Public Function fTurnoFecha(FechaCalculo As Date, sCadencia As String, PrimerDiaTurno As Date, Optional lDesplazamiento As Long) As String

    Dim v As Variant

    Dim lColumnas As Long

    Dim lCompensacion As Long

    v = Split(sCadencia, ",")

    lColumnas = 1 + UBound(v)

    lCompensacion = fColumna(Int(PrimerDiaTurno + lDesplazamiento), lColumnas) - 1

    fTurnoFecha = v(fColumna(Int(FechaCalculo) - lCompensacion, lColumnas) - 1)

    End Function

    A la funcin le pasamos FechaCalculo, que es la fecha para la que queremos obtener el turno, sCadencia, que es una cadena en la que indicamos la secuenciadel turno, con los items separados por comas, por ejemplo M,T,N,L o Maana,Tarde,Noche,Libre. Tambin le pasamos PrimerDiaTurno que es una fechade la que sepamos con certeza que se corresponde con el primer da de la secuencia o, de manera opcional, lDesplazamiento, que podemos utilizar paraindicar cuantos das se desplaza de una fecha fija, por ejemplo 0, el primer da del turno, calculndolo por tanteo.

    Por ejemplo, el da en que, tras una ardua negociacin de empresa y trabajadores, se elaboraron las planillas, se comprob que el trabajador 2 deba iniciarsu secuencia el 4 de enero del 2007 y se anot esta fecha para posteriores clculos, segn esto, para clcular cmo le toca la Nochebuena del 2010, elclculo en la ventana de inmediato sera:

    ? fTurnoFecha (#2010/12/24#,"Maana,Tarde,Noche,Libre",#2007/01/04#) Noche

    Aparte de para hacerle la pueta al trabajador 2, la funcin se puede utilizar en una consulta para obtener una relacin de todos los turnos de todos lostrabajadores para todos los das de un periodo determinado.

    Elaborar un calendario con turnos

    Tomemos una tabla de empleados, con indicacin de a qu grupo pertenecen

    EmpleadosTurnos

    Id Empleado Grupo

    1 Pedro 1

    2 Andrs 1

    3 Jaime 1

    4 Juan 2

    5 Felipe 2

    6 Bartolom 2

    7 Toms 3

    8 Mateo 3

    9 Santiago 3

    10 Judas 4

    11 Simn 4

    13 Matas 4

    Aunque el ltimo ID sea 13, se trata de 12 empleados, pues despidieron a uno por conducta desleal. Estn organizados en 4 grupos cada uno de los cualesse inicia al da siguiente del grupo anterior. Vamos a crear el calendario correspondiente a octubre del 2010 utilizando una consulta.

    Sabemos que si disponemos de una tabla Numeros poblada de numeros consecutivos empezando por el 1, podemos obtener una secuencia de fechas abase de sumar una FechaInicial menos uno al campo Numero. Este truco y el de no relacionar tablas para que el resultado sea un producto cartesiano lovamos a utilizar en la siguiente consulta.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 23/52

    El texto SQL es el siguiente:

    SELECT EmpleadosTurnos.Empleado, [Numero]+CDate("01-10-10")-1 AS FechaVirtual, EmpleadosTurnos.Grupo, fturnofecha([fechavirtual],"Maana,Tarde,Noche, Libre",CDate("04-01-07"),[Grupo]-1)

    FROM Numeros, EmpleadosTurnos

    WHERE ((([Numero]+CDate("01-10-10")-1)

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 24/52

    La consulta la podemos personalizar para pasarle las fechas inicial y final del periodo como parmetros y tambin podemos tomarla como puento de partidapara una consulta de datos anexado o de actualizacin que para cada da del ao y cada empleado deje anotado el turno de trabajo. Aunque no esnecesario volcar los datos en una tabla, pues podemos utilizar la consulta con cualquier periodo de fechas, si resulta muy conveniente, pues adems de losdistintos turnos pueden darse otras situaciones, como bajas, vacaciones, cambios de turno que hacen necesario trabajar con datos guardados.

    A menudo se pretende realizar una planilla que refleje los trabajadores que entran en cada turno cada da, utilizando los das como encabezado de columna.

    qTurnosVirtuales_Tabla de referencias cruzadas

    Empleado Grupo 01/10/10 02/10/10 25/10/10 26/10/10 27/10/10 28/10/10 29/10/10 30/10/10 31/10/10

    Andrs 1 Noche Libre Noche Libre Maana Tarde Noche Libre Maana

    Jaime 1 Noche Libre Noche Libre Maana Tarde Noche Libre Maana

    Pedro 1 Noche Libre Noche Libre Maana Tarde Noche Libre Maana

    Bartolom 2 Tarde Noche Tarde Noche Libre Maana Tarde Noche Libre

    Felipe 2 Tarde Noche Tarde Noche Libre Maana Tarde Noche Libre

    Juan 2 Tarde Noche Tarde Noche Libre Maana Tarde Noche Libre

    Mateo 3 Maana Tarde Maana Tarde Noche Libre Maana Tarde Noche

    Santiago 3 Maana Tarde Maana Tarde Noche Libre Maana Tarde Noche

    Toms 3 Maana Tarde Maana Tarde Noche Libre Maana Tarde Noche

    Judas 4 Libre Maana Libre Maana Tarde Noche Libre Maana Tarde

    Matas 4 Libre Maana Libre Maana Tarde Noche Libre Maana Tarde

    Simn 4 Libre Maana Libre Maana Tarde Noche Libre Maana Tarde

    Evidentemente es fcil de hacer con una consulta de referencias cruzadas.

    El texto SQL sera:

    TRANSFORM First(qTurnosVirtuales.Turno) AS PrimeroDeTurno

    SELECT qTurnosVirtuales.Empleado, qTurnosVirtuales.Grupo

    FROM qTurnosVirtuales

    GROUP BY qTurnosVirtuales.Empleado, qTurnosVirtuales.Grupo

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 25/52

    ORDER BY qTurnosVirtuales.Grupo

    PIVOT qTurnosVirtuales.FechaVirtual;

    Si nuestra consulta de referencias cruzadas la convertimos en un informe y usamos formato condicional, el resultado es la mar de vistoso (o la mar dehortera, segn gustos). En el ejemplo le hemos quitado columnas para que nos quepa bien en la pgina.

    En fin, se trata de una serie de ideas que pueden servir a alguien que debe plantearse la gestin de turnos de trabajo, pero no pretende ser ni la solucinni la forma cannica de plantearlo.

    Publicado por Chea con 8 comment(s)Archivado en: Access,Calendario21/10/2010 20:00

    Hola a Office 365, adis a Office Live Small Business

    Al tiempo que se anunciaba el lanzamiento de la beta de Office 365, el Access Team Blog anunciaba que Office 365 incluir Access Services y, por tanto,Access web Databases y en la comunidad online de Office Live Small Business (OLSB) daban la noticia de que, ante la llegada de Office 365, OLSBdesaperecer en el plazo de un ao.

    Habr un periodo de transicin para migrar de OLSB a Office 365 para pequeas empresas a finales del 2011 o principios del siguiente, con un periodogratuito de tres meses, pero despus habr que pagar por el servicio. Hay quien dice que a Manolete le mat el toro porque la corrida era de beneficencia yeso mismo ha debido pensar Microsoft. Para quienes migren desde OLSB, el precio parece que no ser muy caro, unos 6$ al mes por cuenta, muy poco parauna empresa incluso pequea, pero bastante para sustituir a algo que se prometi como gratis de por vida (claro, de la vida del producto que ahora eliminan

    ).

    Para quienes queremos jugar con las posibilidades de las aplicaciones web de Access 2010 o utilizar Sharepoint como back end de nuestras aplicacionesAccess de escritorio, el anuncio es realmente prometedor pues el rendimiento Access Services es muy superior al de las listas vinculadas en Sharepoint2007, por el volumen de datos que es capaz de gestionar sin problemas y por la velocidad notablemente superior y porque, sencillamente, las aplicacionesweb de Access 2010 son impensables en Sharepoint 2007. Hasta ahora, lo ms barato con Access Services era AccessHosting a partir de 19$ mes el packdeveloper, por lo que el precio de Office 365 para pequeas empresas resulta muy competitivo, menos de un tercio, y eso sin contar con que los AccessServices son la parte ms pequea del paquete de Office 365, que incluye Office Professional, Exchange Online, Sharepoint Online y Lync Online.

    Para quienes hemos utilizado OLSB precisamente porque era un recurso gratuito de por vida, no deja de ser una faena. Algunas aplicaciones de escritorio enAccess 2007 podan compartir unos pocos datos en la web de forma muy sencilla y sin coste alojndolos en OLSB. Algunos nos hemos entretenido endisear en OLSB pginas web sencillas para otros que no se pueden permitir un coste superior a gratis, el pequeo negocio del amigo que empieza, unaactividad del colegio, etc., precisamente porque OLSB ofreca un alojamiento gratuito con una calidad aceptable. Unos y otros, en ambos casos yo, ahora seven decepcionados, pues no necesitaban nada ms y ahora se lo quitan, ofrecindoles a cambio, de pago, lo que no han pedido.

    As que mi entusiasmo por lo uno frena mi decepcin por lo otro y viceversa y, de momento, ando ms bien perplejo.

    Tengo muy claro que contratar Office 365 para la pequea empresa por utilizar los Access Services y para seguir alojando mi pgina, pero para aquellascosas en las que utilizaba OLSB por ser gratuito, empezar a irme pasando a Google Sites Habr valorado Microsoft que esta ltima decisin ser la lgicapara miles de usuarios de OLSB?

    Publicado por Chea con 2 comment(s)Archivado en: Office Live,Sharepoint,Access,Access 2010,Office 365,Sharepoint 201010/1/2010 23:36

    Algunas joyas escondidas en Access 2010

    Access Services

    Estoy impresionado. He aprovechado la oferta de Access Hosting que el otro da anunciaba el Access Team Blog para abrir una cuenta trial de Access Services. He probado a crear y subiruna aplicacin web hecha con una plantilla de Access 2010 y, como era de esperar, ha funcionado a la perfeccin.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 26/52

    Las aplicaciones web funcionando en Sharepoint 2010 son la novedad estrella de Access 2010, sin embargo, lo que me ha impresionado ha sido algo mucho ms simple: He subido unasencilla aplicacin de escritorio y funciona de maravilla, a una velocidad equiparabla a la de cualquier aplicacin web; naturalmente, no se ejecuta en Sharepoint, sino que lousa de Back End, pero hace mucho ms, pues no slo aloja y sirve datos, sino que tambin guarda todos los dems objetos de la aplicacin.

    Navegando por el sitio creado en Sharepoint para nuestra aplicacin, tenemos una opcin para modificar la base de datos:

    Pinchas en ella y, en pocos minutos, se ha descargado una copia de la aplicacin perfectamente operativa que trabaja con los datos alojados en el sitio. La siguiente vez que pinches, slotardar un poco ms de lo que tardaras en abrir la aplicacin en el escritorio. Para conseguir esto, durante el proceso de subida a Access Services se han ido sincronizando no slo tablas yconsultas, sino todos los objetos; as, cuando realizamos una modificacin en nuestra BD, en cualquier objeto, no slo en los datos, el cambio se realiza tambin en el sitio Sharepoint, demanera que siempre est disponible desde la web la ltima versin. Una maravilla.

    Como la opcin para modificar la base de datos es un acceso directo, podemos copiarlo y usarlo directamente o, remitirlo a otros usuarios, en vez de andar navegando por el sitio.

    Esto me ha reconciliado con la proyeccin a la nube de Access 2010. Las listas vinculadas en Access 2007 son una opcin interesante, pero bastante ms limitada y lenta de lo que seprometa, para colmo, lo que tuviramos hecho con listas vinculadas ya no nos vale ahora para los Access Services, de manera que no estaba muy seguro de que el premio mereciera eltrabajo de aprender a manejar las macros, el formulario de navegacin, etc.. Ahora, slo por esta posibilidad de tener los datos en la web de manera fcil u operativa, ya merece la penasubirlos y, ya puestos.

    Access 2010 viene con grandes novedades de las que, desde el inicio de la Vista Previa Tcnica, el Access Team Blog nos viene poniendo al da. Eventos y macros de datos, camposcalculados en tablas, aplicaciones en la web, formularios de navegacin, control WebBrowser vinculado a datos son serias innovaciones que cambiarn la forma de trabajar con Access yque parecen todas orientadas a las aplicaciones web. Haba dejado para cuando estuviera con ms nimo el ir probando todo lo referente a esas novedades estrella, pero, mientras, he idodescubriendo cosas ms terrenales, mejoras sobre cosas que ya se venan usando, que o no se mencionan en los blogs, o lo hacen de pasada, pero que por s solas ya justificaran unanueva versin. A esas pequeas joyas voy a referirme ahora.

    Formato condicional

    Casi parece que no ha cambiado en nada, a simple vista, los asistentes parecen los mismos, pero uno se pone a meter hasta cuarenta y nueve formatos condicionales y no se queja, mientrasque antes vena limitado a tres.

    Si, adems, nos fijamos bien en el asistente, vemos que tiene un desplegable, Seleccionar tipo de regla con una opcin, comparar con otros registros.

    Seleccionamos entre distintas opciones, y el resultado es una barra proporcional a los distintos valores de nuestro formulario o informe, un estilo a lo que ya exista en Excel

    No slo funciona con informes y formularios continuos. Tambin se pueden usar, y funciona correctamente, en formularios estndar

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 27/52

    Texto enriquecido en subformularios

    Aunque parece que lo corregirn en breve, en Access 2007 no era posible editar el texto enriquecido en los subformularios. Ahora s, en cualquier lugar, incluso en subformulario continuos,aunque sean en vista Hoja de Datos.

    SubInformes en formularios

    Estamos tan acostumbrados a que no se puedan meter SubInformes en formularios que hasta cuesta pensar en la utilidad que pueden tener.

    Por ejemplo, haciendo un refrito, en muy pocos minutos hemos convertido el informe Listn de telfonos en panel de navegacin del formulario Detalle de clientes de la BD NorthWind.

    Se me ocurre que navegar de manera semejante por un Diario o un Libro Mayor correctamente formateados en un subinforme, con sus Totales por asiento, Sumas Contnuas, etc., dentro deun formulario para editar los asientos, puede resultar muy vistoso, incluso muy til, y realmente fcil de hacer.

    Se trata de una Vista Informe por lo que faltan las opciones de impresin que tiene la Vista Previa, pero, a cambio, podemos disponer de eventos (Clic, doble-clic) filtros, etc.. Nadacuesta poner un botn en el informe o en el Ribbon para que nos muestre una vista previa

    En otros casos, como corresponde a un SubInforme, est vinculado al Formulario principal por las propiedades LinkChildFields y LinkMasterFields, de manera que, al cambiar de registro elformulario, el subinforme a la vista se filtra segn estos campos.

    Tambin existe la posibilidad contraria, la de mostrar subformularios en informes. El subformulario no es editable por lo que no le veo ninguna ventaja sobre un subinforme en vista informe,salvo ahorrarse el trabajo de crearlo, pero seguro que, entre las muchsimas barrabasadas que se harn con esta posibilidad, alguien le encontrar un uso brillante.

    Plantilla de ajuste de controles

    Se trata de que los controles se ajustan a una plantilla o tabla, como en las hojas de estilo en el diseo web, en la que podemos aadir o quitar filas y columnas, cambiar alto y ancho deceldas, dividir stas o combinar varias entre s.

    Access 2007 ya haba aportado algo a la colocacin de los controles, agrupndolos en formato tabular o apilado, que sigue siendo posible, pero, aunque era una forma muy rpida de ponercierto orden visual, no era una solucin muy lograda, ya que todos los controles apilados en el mismo grupo, tenan el mismo ancho.

    En Access 2010 cuando agrupamos controles, de forma apilada o tabular, podemos moverlos a un lado, encima o debajo, como si aadieramos filas y columnas a una tabla de word; de lamisma manera, podemos combinar o dividir esas celdas y los controles que coloquemos se ajustarn a ellas. Es como si debajo de los controles hubiera una tabla o plantilla invisible. Verlaes fcil utilizando otra de las novedades de Access 2010, las lneas de divisin tambin en formularios.

    Botones con formas, colores y relieves

    Los botones, incluidos los de los TabControls, pueden tener distintas formas colores y texturas. Como muestra, unos pocos:

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 28/52

    El botn Estilos rpidos muestra una galera rpida, pero tambin podemos combinar Cambiar forma, Relleno de forma, Contorno de forma y Efectos de forma para conseguir un montnde posibilidades.

    Las formas y colores de los botones no quitan para que puedan seguir teniendo imgenes y pie de imagen, por lo que podemos conseguir unos botones resultados muy vistosos en los que,adems, se sigue visualizando el efecto de apretar el botn:

    Los botones con formas y colores se ven afectados por el Tema que hayamos elegido. Al cambiar de tema, cambia la galera de Estilos rpidos y, si ya lo hemos creado, tambin cambia laapariencia de nuestro botn.

    Si queremos cambiar la imagen de un viejo formulario Access 2007, de entrada puede que no tengamos habilitadas estas opciones. Se soluciona fcilmente cambiando la propiedad Usartema del control.

    Si nuestra aplicacin es en formato mdb, no existe esta propiedad y, por tanto, tendremos que conformarnos con los botones tradicionales.

    Generador de expresiones

    Cambia la interface del generador de expresiones.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 29/52

    Es ms completa y con grafa que diferencia los objetos, pero lo ms novedoso es que aplica el intellisense en aquellas propiedades en que se puede usar el generador.

    Imgenes compartidas

    Aunque ya en Access 2007 las imgenes se guardan en el tamao del formato original, no deja de ser un desperdicio de espacio repetir la misma imagen, por ejemplo el logotipo de laempresa, en cada formulario o informe. Aunque haba soluciones, sta sque es sencilla de manejar.

    Una vez que para una imagen en la propiedad Tipo de imagen hemos elegido Compartidas, queda guardada y a disposicin de los dems objetos de la aplicacin en la galera que sedespliega al pulsar el botn Insertar imagen.

    Las imgenes compartidas se guardan como datos adjuntos en la tabla MSysResources, de manera que slo ocupan espacio una sla vez. Contiuar existiendo en nuestra BD, y ocupandoese espacio, mientras no la borremos de aqu. Si queremos cambiar el anagrama de nuestra empresa en todos los formularios e informes, basta con que lo cambiemos aqu.

    Ttulo en la barra de navegacin

    Un pequeo detalle, casi insignificante, pero que refleja cmo en Access 2010 nos encontramos con mejoras a cada paso. Con la propiedad Ttulo de navegacin podemos indicar ququeremos que ponga en la barra de navegacin en vez de Registro. Sin pasarse, eh, que el espacio reservado para ello no aumente ;-)

    Publicado por Chea con 15 comment(s)

    Archivado en: Access 201012/6/2009 18:36

    Magia Potagia II: El desenlace

    En el captulo anterior habamos usado ingredientes mgicos de Access 2007 para conseguir crear una serie de calendarios sin apenas usar cdigo. Hoy se trata de licenciarnos como aprendices debrujo haciendo que la magia trabaje para nosotros resolviendo problemas de la vida real.

    Necesitaba crear un subinforme que, para cada uno de los elementos del informe principal, me mostrara un conjunto de fechas representadas en tantos calendarios mensuales como fuerannecesarios para mostrar todo el periodo entre la primera y la ltima. Ms o menos, como en las imgenes.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 30/52

    Evidentemente, ya lo he hecho y el caso real lleva tiempo funcionando correctamente. Hay una demo, la de las imgenes, que se puede descargar en Access siglo XXI.

    La magia en la vida real tiene un problema: que no hay quien entienda cmo funciona. Lo mgico de estos calendarios es que apenas usan cdigo, pero el cdigo se puede leer, est estructurado,se autodocumenta; es como un plano de la aplicacin. Sin cdigo es muy difcil ver cmo est hecho algo, tanto que, para que el que quiera pueda adaptar mi ejemplo, he tenido que incluir unpequeo asistente.

    No obstante, voy a intentar explicar cmo est construido, aunque me temo que ser bastante pesado. Cuando empieces a aburrirte, salta directamente al ltimo punto, al desenlace.

    El punto de partida es una tabla con un campo de fecha y un campo ID numrico, en este caso de usuario, es decir, con un conjunto de fechas, que son las que queremos mostrar en calendario,para cada usuario.

    El idEmpleado es nmerico y si se muestran nombres en la imgen es porque uso un campo de bsqueda.

    En el ejemplo del captulo anterior utilizaba una tabla tipo Calendar, con campos StartDate y EndDate, y mediante una consulta, la converta en un resultado parecido a ste. Sin embargo, aunqueno lo deca, trabajar directamente con la consulta afectaba mucho al rendimiento y sera preferible volcar los resultados en una tabla temporal.

    Obtener todas las fechas de cualquier ao

    El primero de los ingredientes mgicos , es una tabla Numeros, con un campo Num con nmero consecutivos. La ma tiene poco ms de mil.

    A partir de esta tabla, mediante una consulta construimos todas las fechas que se corresponden con las del calendario de fondo

    SELECT [Numero]+DateSerial(nz(TempVars!jbAnyoInicial,Year(Date())),1,1)-1 AS Fecha, Format([Numero]+DateSerial(nz(TempVars!jbAnyoInicial,Year(Date())),1,1)-1,"dddd") AS Dsemana, (Month

    FROM Numeros

    WHERE (((Year([Numero]+DateSerial(nz([TempVars]![jbAnyoInicial],Year(Date())),1,1)-1))=nz([TempVars]![jbAnyoInicial],Year(Date()))));

    Mediante el procedimiento de sumar al campo Num una fecha inicial menos uno y hacer que sea menor o igual que una fecha final, podemos obtener cualquier rango de fechas que no supere eltotal de registros de nuestra tabla Numeros. Pero en el informe podemos superar este lmite usando otro de los ingredientes mgicos de Access 2007, TempVars. Al utilizar una variable TempVarsen el clculo de la fecha inicial, podemos cambiar sta sobre la marcha en el informe de manera que la consulta se vaya recalculando las veces que sea necesario. Ya nos pararemos en ello msadelante; de momento, guardamos esa consulta como jbFechasVirtuales y los resultados sera algo as:

    Resaltar los festivos de cada empleado

    Sobre ese calendario de fondo se trata de resaltar las fechas de nuestra tabla tblFechasEmpleados usando el tercer ingrediente mgico de A2007, el formato de texto enriquecido. Comparamostabla y consulta y en las fechas coincidentes aadimos las etiquetas html necesarias para mostrar el resultado resaltado, en nuestro caso en rojo, tal como habamos visto en el captulo anterior.

    Sin embargo, antes vamos a anticiparnos con un problema con el que nos toparamos ms adelante en el caso real. El objetivo es presentar los calendarios como subinformes, pero si construimos

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 31/52

    y formateamos como calendarios todo el conjunto de datos, al vincular por un campo ID informe y subinforme y, por tanto, filtrar los datos de ste, destrozamos el formato de calendario quehemos dado a todo el conjunto. En resumen, que debemos dar forma de calendario a cada subconjunto en vez de filtrar el conjunto de datos total y para ello la mejor solucin que se me haocurrido es volver a usar TempVars de manera que, cambiando sobre la marcha la variable TempVars!jbID cada vez que cambie el ID del informe principal se recalcula la consulta en la que sebasa el subinforme calendario filtrndose por ese ID.

    As, en vez de usar directamente la tabla tblFechasEmpleados, usar la consulta que he llamado jbqFestivosVirtuales y que tiene el siguiente SQL.

    SELECT tblFechasEmpleados.idEmpleado, tblFechasEmpleados.Fecha

    FROM tblFechasEmpleados

    WHERE (((tblFechasEmpleados.idEmpleado)=[TempVars]![jbID]));

    Ahora ya podemos juntar las dos ltimas consultas para resaltar con formato de texto enriquecido los festivos de los empleados.

    SELECT jbqFechasVirtuales.*, IIf(Not IsNull([jbqFestivosFiltrados].Fecha),"" & Day(jbqFechasVirtuales.fecha) & " ",Day(jbqFechasVirtuales.fecha)) AS Expr1

    FROM jbqFechasVirtuales LEFT JOIN jbqFestivosFiltrados ON jbqFechasVirtuales.Fecha = jbqFestivosFiltrados.Fecha

    ORDER BY IIf(Not IsNull([jbqFestivosFiltrados].Fecha),"" & Day(jbqFechasVirtuales.fecha) & " ",Day(jbqFechasVirtuales.fecha));

    Guardamos la consulta como jbFechasyFestivosVirtuales y el resultado es como en la imagen siguiente (hasta 365 das) donde destaca un campo que en ocasiones pone algo como 10 con el que ms adelante conseguirems que el nmero 10 se muestre en rojo.

    Ya tenemos una secuencia con todas las fechas del ao para un determinado usuario con los festivos formateados para que ms adelante se muestren en rojo. Para que se parezca a uncalendario falta ordenarlo en columnas por das de la semana.

    Dar a los datos forma de calendario

    Ya habamos visto en el captulo anterior que para ordenar en columnas por das de la semana una secuencia de fechas podemos usar una Consulta de Referencias Cruzadas que voy a llamarjbqCalendarioFormateado y que ser el origen de datos del subinforme calendario:

    TRANSFORM Min([jbqFechasyFestivosVirtuales].Expr1) AS MnDeExpr1

    SELECT [jbqFechasyFestivosVirtuales].Mes, [jbqFechasyFestivosVirtuales].Anyo, [jbqFechasyFestivosVirtuales].Fila

    FROM jbqFechasyFestivosVirtuales

    GROUP BY [jbqFechasyFestivosVirtuales].Mes, [jbqFechasyFestivosVirtuales].Anyo, [jbqFechasyFestivosVirtuales].Fila

    PIVOT [jbqFechasyFestivosVirtuales].Dsemana In ("lunes","martes","mircoles","jueves","viernes","sbado","domingo");

    El resultado, algo parecido a esto:

    El subinforme calendario

    Es pequeito, para que me quepan ms calendarios en una hoja, que hay que ahorrar papel,

    El Origen de Datos es la consulta jbaCalendarioFormateado y el truco principal es que los campos Lunes, Martes, Mircoles estn ocultos (en la imagen en amarillo) y sobre ellos se superponensendos campos calculados dLunes, dMartes, dMircoles que tienen por origen el campo que est debajo. Al ser campos calculados, pueden tener formato de Texto enriquecido, que no es posible encampos de texto, de manera que el campo que antes habamos construido con etiquetas html del estilo 10, ahora se mostr como 10.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 32/52

    Tambin estn ocultos los campos Mes y Anyo, que nos van a servir para vincular con el subinforme MesesAnyos.

    Este subinforme no tiene ni una sola lnea de cdigo.

    El subinforme Meses-Ao

    El subinforme anterior muestra un solo calendario, pero necesitamos que nos muestre tantos calendarios como sean necesarios en el subinforme. Por eso lo incrustamos en otro subinforme Meses-Ao que tiene todos los meses necesarios para mostrar las fechas de cada empleado.

    El origen del subinforme es la consulta jbqMesesAnyos y tiene por objetivo obtener tantos registros identificados por mes y ao como sean necesarios para mostrar todas las fechas de unempleado:

    SELECT ((([Numero]-1)\12)) AS Fila, 1+([Numero]-1) Mod 12 AS numMes, MonthName([NumMes]) AS NombreMes, (([Numero]-1)\12)+Year(DMin("[Fecha]","jbqFestivosFiltrados")) AS Anyo, DateSerial(((([Numero]-1)\12))+Year(nz(DMin("[Fecha]","jbqFestivosFiltrados"))),1+([Numero]-1) Mod (12),1)

    FROM Numeros

    WHERE (((DateSerial(((([Numero]-1)\12))+Year(nz(DMin("[Fecha]","jbqFestivosFiltrados"))),1+([Numero]-1) Mod (12),1)) Between nz(DMin("[Fecha]","jbqFestivosFiltrados"))-30 And nz(DMax("[Fecha]","jbqFestivosFiltrados")) And

    La consultita se las trae, pero, resumiendo, obtiene los meses y ao del subconjunto de fechas de un empleado a partir de la tabla Numeros y usando como filtro las fechas mayor y menor de laconsulta jbqFestivosFiltrados. Adems, obtiene el campo jbID, por el que se vincula con el informe principal, de la Variable Temporal TempVars!jbID.

    En la seccion detalle tenemos el subinforme jbSubRptCalendarioFormateado y, cada vez que se formatea esa seccin, cambiamos mediante cdigo la variable temporal TempVars!jbAnyoInicial que,como vimos se usaba en la primera consulta, jbFechasVirtuales, de manera que al cambiarse, esto s que es magia, se se recalcula toda la consulta y se refresca el subinformejbSubRptCalendarioFormateado.

    Este es el todo cdigo del subinforme:

    Option Compare Database

    Option Explicit

    Private Sub Detalle_Format(Cancel As Integer, FormatCount As Integer)

    TempVars!jbAnyoInicial = Me.Anyo.Value

    Me.SubRptCalendario.Requery

    End Sub

    Private Sub Report_Close()

    TempVars.Remove ("jbAnyoInicial")

    End Sub

    Private Sub Report_Open(Cancel As Integer)

    TempVars!jbAnyoInicial = Year(DMin("Fecha", "jbqFestivosFiltrados"))

    End Sub

    El informe principal

    En el informe principal incrustamos el subinforme jbSubRptMesesAnyo y necesitamos un campo ID por el que vincular con ste.

  • 22/06/13 Access

    geeks.ms/blogs/access/default.aspx 33/52

    Es necesario que tengamos una agrupacin por ese campo ID y que ese campo se encuentre en la seccin encabezado de ese grupo.

    Por qu? Por que es la nica forma que he conseguido que me funcione el abracadabrante rizado del rizo:

    Los campos por los que se vinculan informe y subinforme son respectivamente id y jbid.

    En el evento Format de la seccin EncabezadoDelGrupo0 le doy a la variable temporal TempVars!jbID el valor de ese campo ID y, como resulta que el campo jbID del subinforme lo toma de esavariable temporal, estoy asignando sobre la marcha y mediante cdigo en el informe principal el valor del campo del subinforme por el que ste se vincula con el informe principal Con dos c!

    Para ms magia potagia, cambiar por cdigo TempVars!jbID, como forma parte de la primera consulta, jbFechasVirtuales, hace que sta se refresque y haga los clculos slo para el empleadodel ID. Como tambin est en la consulta jbqFestivosFiltrados y del mximo y mnimo de sta depende la consulta jbqMesesAnyo, no slo se restringen los festivos a los del empleado, sino quese recalcula jbqMesesAnyo, que es precisamente el origen del subinforme.

    Todo el cdigo necesario es el siguiente:

    Option Compare Database

    Option Explicit

    Private Sub EncabezadoDelGrupo0_Format(Cancel As Integer, FormatCount As Integer)

    TempVars!jbID = Me.ID.Value

    Me.subRptMesesAnyo.Requery

    End Sub

    Private Sub Report_Close()

    TempVars.Remove ("jbID")

    End Sub

    Private Sub Report_Open(Cancel As Integer)

    TempVars!jbID = DFirst("id", Me.RecordSource)

    End Sub

    El desenlace

    Yo ya advert que iba a ser aburrido. Resumiendo, usando TempVars y consultas basadas en una tabla Numeros, se pueden hacer cosas inimaginables de otra manera.

    Es magia empaquetada. No es necesario entenderla toda ni seguir complicados rituales para usarla en una aplicacin propia pues, de todos los objetos y consultas que utiliza slo es necesariocambiar el informe principal y la consulta jbqFestivosFiltrados. En Access siglo XXI puedes descargarte la aplicacin de ejemplo que, adems, tiene un asistente elemental para modificar esaconsulta y el cdigo del informe principal.

    De dnde he sacado yo estas cosas de mgia? Ni idea, supongo que andar hechizado, aunque algo de inspiracin se me habr pegado de Ramn Poch o de Julin Snchez, aficionados tambina jugar con una tabla Numeros.

    Por cierto Domingun iba a las siete de la maana A contarlo!

    Publicado por Chea con no commentsArchivado en: Access 2007,Informes,Campos Memo,TempVars,Calendario17/5/2009 19:36

    Access 2010- Hermenutica sobre un volcado de pantalla

    Ya tenemos