Vba Access
Vba Access
Vba Access
VBA - Access
Entrega 01
Introduccin
Eduardo Olaz
01 - 2
Planteamiento
Este cursillo nace como respuesta a las continuas demandas por parte de los intervinientes
en los foros de Access, de un manual que permita, desde cero, aprender los fundamentos
de la programacin con VBA.
La idea inicial es ir suministrando sucesivas entregas imprimibles y descargables desde uno
varios enlaces de Internet.
Estos textos se complementarn, si fuese necesario, con ficheros mdb que contendrn el
cdigo y los ejemplos planteados en el curso.
Objetivos
El objetivo que me planteo, espero no ser demasiado ambicioso, es que el lector, tras
seguir el cursillo, adquiera las bases de programacin suficiente como para poder manejar
las herramientas que le suministra VBA de Access, y sea capaz por s mismo de ir
evolucionando y completando sus conocimientos.
Por mi experiencia personal y con alumnos de cursos que he impartido, el problema
fundamental para soltarse en la programacin es conocer los elementos esenciales del
lenguaje y las herramientas que el sistema te ofrece.
En nuestro caso vamos a utilizar el lenguaje Visual Basic para Aplicaciones y su entorno de
desarrollo, orientado principalmente a su utilizacin con Access.
A quin va dirigido?
Va dirigido a todos aquellos que quieran comenzar a programar con VBA.
Como requisitos necesarios, el lector deber haber manejado previamente Access y ser
capaz de crear tablas, formularios, informes y consultas bsicas.
Eduardo Olaz
Entrega 01 Introduccin 01 - 3
Qu es VBA?
VBA quiere decir Visual Basic para Aplicaciones.
Es un conjunto de libreras, (un tipo especial de programas), desarrollado por Microsoft que
incluye, entre otras cosas, un entorno de desarrollo y un lenguaje de programacin.
VBA no es exclusivo de Access; lo podemos encontrar tambin en todas las aplicaciones de
Office como Word o Excel, en otro tipo de programas como Project o Visio, y en programas
que no son de Microsoft y tan diversos como Corel Draw o AutoCad.
Dominando los fundamentos de VBA, se podra desarrollar aplicaciones en cualquiera de
esos aplicativos.
VBA tiene un entorno de programacin que es semejante para todos estos programas.
Por ejemplo:
VBA para Access VBA para Word
Los mdulos
Los mdulos son los objetos en los que se guarda el cdigo que va a utilizar VBA.
Hay tres tipos de mdulos.
Mdulos generales
Mdulos asociados a formularios e informes
Mdulos de Clase.
Manos a la obra: vamos a crear una nueva base de datos con el nombre Entrega01.mdb
Para acceder a los mdulos generales debemos presionar en la pestaa Mdulos de la
Barra de Objetos de Access:
Para crear un mdulo nuevo haga Clic en el botn [Nuevo].
Una vez hecho esto se abre el editor de VBA y nos crea un
mdulo con el original nombre de Mdulo1.
Eduardo Olaz
Entrega 01 Introduccin 01 - 5
Le damos a Aceptar.
-Pero qu es esto?-
Aunque adelantemos conceptos tratar de explicarme.
Cuando empecemos a escribir cdigo, veremos que existen unos elementos que se
llaman variables, a los que podremos asignar valores.
Si tenemos activada la opcin [Requerir declaracin de variables] nos obligar a
declarar las variables antes de poder usarlas. Ms adelante veremos que hay
variables que pueden contener Texto, Nmeros, Fechas, Objetos, etc.
En una entrega posterior aprenderemos a declarar una variable. Esto significa darle
nombre y expresar qu tipo de dato va a contener.
Una vez hecho esto grabamos el mdulo dndole al botn Guardar [Disquete] a la opcin
de men Archivo>Guardar combinando las teclas [Ctrl] + [S]
Aceptamos el nombre por defecto Mdulo1 y cerramos la ventana.
Un poquito de teora
Windows funciona con las llamadas Ventanas. Esas ventanas contienen objetos, y tanto las
ventanas como los objetos pueden mandar unos mensajes para indicar a la aplicacin que
usa Windows, o al propio Windows que han ocurrido determinadas cosas. Esos mensajes se
llaman Eventos. Por cierto; en realidad muchos de los objetos, como los botones, tambin
son ventanas; pero esa es otra guerra.
En nuestro caso tenemos los siguientes objetos:
Formulario Saludo
Etiqueta lblSaludo
Botn cmdSaludo
Cada uno de esos Objetos posee una serie de Propiedades, generan determinados
Eventos y pueden hacer determinadas cosas mediante unos procedimientos propios que se
llaman Mtodos.
Por ejemplo, al presionar el botn cmdSaludo, se genera el evento [Al hacer Clic] (Click).
Podramos capturar ese evento y aprovecharlo para, por ejemplo, cambiar el texto de la
etiqueta lblSaludo.
El texto que aparece en la etiqueta est en la propiedad [Ttulo]; en ingls [Caption].
Ahora la pregunta: dnde y cmo se hace todo eso?
Cada formulario, y veremos ms adelante que tambin cada informe, lleva asociado un
mdulo especial. Se llama mdulo de clase del formulario.
Vamos a verlo.
En el modo Diseo del formulario Saludo, seleccionamos el botn cmdSaludo.
Abrimos la Hoja de propiedades y seleccionamos la pestaa [Eventos], y dentro de stos el
evento [Al hacer clic].
Al poner el cursor sobre l, nos muestra un botoncito con tres puntos.
Pulsamos en l, y seleccionamos [Generador de cdigo] en la ventana que se nos abre.
A continuacin pulsamos en el botn [Aceptar].
Tras esto nos abrir el mdulo de clase del formulario Saludo, con el esquema de cdigo
correspondiente al evento Clic del botn cmdSaludo:
End Sub
End Sub
Este cdigo se corresponde al procedimiento que recoge el evento Clic del botn.
Consta de varias partes:
Private Sub indica que empieza un procedimiento del tipo Sub, ms adelante veremos
en detalle qu es esto.
cmdSaludo_Click() Indica que es el procedimiento al que llama el evento Click del
botn cmdSaludo.
End Sub Indica el punto donde acaba el procedimiento
Eduardo Olaz
Entrega 01 Introduccin 01 - 9
Entre esas dos lneas podemos escribir el cdigo que le dir a Access qu es lo que tiene
que hacer.
Vamos a hacer 2 cosas:
1. Escribiremos en la propiedad [Ttulo] (Caption) de la etiqueta el texto
Hola Mundo.
2. En la propiedad [Ttulo] (Caption) del formulario mostraremos el texto.
Aqu estoy.
Debo modificar el texto del cdigo para que ponga:
Al escribir el texto, se abre una ventana de Ayuda contextual, lo que simplifica en gran
medida la escritura correcta del texto.
Esta ventana te va mostrando las propiedades y mtodos. Para seleccionar uno en concreto
podemos utilizar la tecla [Enter], o mejor an, la tecla [tab] de tabulacin (es la tecla que
suele estar encima de la de Bloqueo de Maysculas).
Me.lblSaludo.Caption = "Hola Mundo!!!"
Lo que hace es pones el texto Hola Mundo!!! En la etiqueta lblSaludo.
Las comillas son para indicar a VBA que lo que hay dentro es un texto.
Me.Caption = "Aqu estoy!" Pone el texto Aqu estoy! en el ttulo
del formulario.
Me es el propio formulario.
Si nos fijamos en la sentencia Me.lblSaludo.Caption est indicando la
propiedad Caption del objeto lblsaludo del formulario actual.
Eduardo Olaz
Comencemos a programar con
VBA - Access
Entrega 02
Entorno de desarrollo
Eduardo Olaz
02 - 2
Entorno de desarrollo
Ya hemos comentado que VBA para Access tiene un entorno de desarrollo similar al de
otras aplicaciones con VBA.
Este entorno recibe el nombre de IDE, que significa algo as como Entorno de Desarrollo
Integrado. En el idioma brbaro se escribe Integrated Development Environment.
Este entorno consta de una serie de ventanas y botones, algunos de los cuales se muestran
en el siguiente grfico.
Eduardo Olaz
Entrega 02 Entorno de desarrollo 02 - 3
Eduardo Olaz
Entrega 02 Entorno de desarrollo 02 - 5
Pero resulta que tras presionar el botn de Reiniciar (el cuadradito azul) resulta que Access
se equivoca y da como resultado 1.
Pues no, Access no se ha equivocado. El exponente b tiene el valor 0, y cualquier nmero
elevado al exponente 0 da como resultado 1.
En realidad ste no es un gran ejemplo, ya que estaramos en el caso singular de 0 elevado
a cero, que no est definido en el campo de los nmeros reales.
Pero no vamos a ser ms papistas que el Papa.
Vamos a hacer ahora otro experimento.
Escribimos en la ventana Inmediato:
a = "2" : b = "4" : ? a + b
Tras presionar la tecla Enter el resultado es chan, chan.!
Si se te ha ocurrido que sera 6 te puedo decir que ests equivocado.
Si tu respuesta ha sido 24, has acertado; pero yo me pregunto No ests perdiendo el
tiempo leyendo este captulo? so listo!.
Bromas aparte expliquemos el resultado.
Como introduccin hemos usado unos elementos que se llaman Operadores.
Los que hemos usado por ahora son:
+ Suma
* Producto
^ Exponenciacin
El smbolo :no es el operador de divisin. En realidad es un simple separador de
instrucciones. El operador de divisin es /.
Hay otros muchos ms que ya iremos viendo poco a poco.
Por qu al escribir a = "2" : b = "4" : ? a + b, nos da 24?
Vamos a fijarnos en estos pequeos detalles a = "2" y b = "4"
La cifra 2 est entre 2 comillas, lo mismo que la cifra 4.
Esto hace que VBA considere el 2 y el 4, no como nmeros, sino como texto, tambin
llamado cadena.
Tras esto el operador + no efecta una suma numrica, sino que enlaza dos cadenas de
texto. Si enlazamos la cadena "2" con la cadena "4", nos da la cadena "24".
Para los listos que ya se saban el resultado, el resto que no haga ni caso de este prrafo,
les informo que esto, en lenguajes ms avanzados, se llama Sobrecarga de Operadores, lo
que equivale a decir que el operador + est Sobrecargado.
En resumidas cuentas, que con nmeros hace la operacin de Suma numrica y con
cadenas de texto la operacin de enlazar cadenas.
Vamos a seguir con pequeas sorpresas.
Escribamos algo tan inocente como:
Print 2,4 * 2
Sorpresa!. Qu ha pasado?
Eduardo Olaz
Entrega 02 Entorno de desarrollo 02 - 7
VBA - Access
Entrega 03
Primeros conceptos
Eduardo Olaz
03 - 2
Primeros conceptos
Ya hemos visto que en la ventana Inmediato podemos efectuar clculos, con valores
directos o con unos elementos a los que les asignamos valores.
Todo esto es interesante, pero todava no podemos hacer grandes cosas, de hecho con una
simple calculadora seramos ms eficientes.
Un poco de paciencia; todo a su tiempo
Si no tenemos abierto un fichero Access, es el momento para hacerlo, por ejemplo crea un
nuevo fichero con el nombre Entrega03.mdb.
Abrimos el apartado [Mdulos] y presionamos el botn [Nuevo].
Pulsamos con el cursor en la ventana de Cdigo y escribimos lo siguiente:
Option Compare Database
Option Explicit
Eduardo Olaz
Entrega 03 Primeros conceptos 03 - 3
Simplemente que estamos intentando asignar un valor a una constante que ya lo tena.
En definitiva una constante slo puede tomar el valor una vez, y a ti te encontr en la calle.
Por definicin una constante no puede cambiar.
Slo mantiene relaciones y se casa una vez.
Y la cosa funcionara
En realidad el declarar as una variable constante, equivale a haber hecho esta otra
declaracin
Public Const Pi As Variant = 3.14159265358979
Public Precio As Variant
Public Nombre As Variant
-Y qu es eso de Variant?-
El Variant es un tipo de dato al que se le puede asignar casi cualquier cosa.
Esto lo hace a costa de consumir ms recursos que otros tipos de variables y por
consiguiente una velocidad ms lenta en la ejecucin.
Procedimientos Sub
Un procedimiento Sub llamado tambin Procedimiento a secas es un conjunto de cdigo
que realiza determinadas tareas.
Suele estar contenido entre las expresiones Sub y End Sub
Eduardo Olaz
Entrega 03 Primeros conceptos 03 - 5
El trmino Sub puede ir precedido de otras expresiones, por ejemplo para delimitar el mbito
en el que puede ser llamado el procedimiento.
Al procedimiento se le pueden pasar una serie de datos para que los use internamente.
A estos datos se les llama Parmetros Argumentos.
Si en la ventana de cdigo escribimos la palabra Sub, le ponemos encima el cursor y
presionamos la tecla [F1], Access nos mostrar la ayuda aplicable a Sub.
En la ayuda podemos entre otras cosas podemos ver:
End Sub
End Sub
End Sub
End Sub
End Sub
Por supuesto que cada opcin genera un cdigo que se comportar de forma diferente.
Es igualmente vlido el que ya hemos usado en la primera entrega.
Private Sub cmdSaludo_Click()
Me.lblSaludo.Caption = "Hola Mundo!!!"
Me.Caption = "Aqu estoy!"
End Sub
Con una salvedad, este ltimo es un tipo especial de Sub. Y es especial porque captura el
evento que se produce cuando de presiona el botn cmdSaludo de su formulario.
Recordemos que un Evento es un mensaje que enva Windows y en este caso es capturado
por Access.
Circunferencia = 15,7079632679489
Crculo = 19,6349540849362 m2
Eduardo Olaz
Entrega 03 Primeros conceptos 03 - 7
-Esto est bien, pero slo puede imprimir los datos de la circunferencia de radio 2,5, lo que
no es gran cosa-.
-Bueno, s. Es un inicio-.
-Ahora, me voy a sacar un conejo de la chistera y modifico el procedimiento Sub, de la
siguiente forma:
Public Sub Circunferencia(Radio As Single)
Debug.Print "Circunferencia = " & 2 * Pi * Radio
Debug.Print "Crculo = " & Pi * Radio ^ 2 & " m2"
End Sub
VBA - Access
Entrega 04
Primeros conceptos 2
Eduardo Olaz
04 - 2
Funciones
En la entrega anterior hemos visto una introduccin a los procedimientos Sub.
Otro de los tipos de procedimientos son los procedimientos Function, que al igual que los
procedimientos Sub estn delimitados por Function y End Function.
La principal diferencia entre un procedimiento Sub y un procedimiento Function es que este
ltimo devuelve un valor.
Entre los dos delimitadores se escribe el cdigo que va a realizar las tareas que deseemos,
y al final devolver algn valor.
Son las llamadas Funciones.
Veamos la forma como lo explica la ayuda de Access.
Si vamos a la ventana Inmediato, escribimos Function, ponemos el cursor en lo escrito y
presionamos [F1], entre otras cosas nos aparece la sintaxis de su declaracin:
End Function
Vemos que para declarar una funcin empezaramos, por ejemplo poniendo la palabra
Public (si quisiramos que la funcin sea accesible desde cualquier parte de Access) a
continuacin la palabra Function, despus abriramos un parntesis y pondramos los
parmetros que necesitramos, cerraramos el parntesis y finalmente pondramos el tipo de
datos que devolvera la funcin.
Supongamos que quisiramos escribir una funcin en la que pasndole el ngulo y el radio,
nos devolviera la longitud de un arco de circunferencia.
La cabecera de esta funcin sera:
Public Function Arco(Angulo As Single, Radio As Single) As Single
Hay un truco para que una lnea con mucho texto se pueda dividir en varias lneas, sin que
deje de ser una nica lnea.
Se coloca al final de la lnea que se quiere dividir un espacio en blanco y la raya de
subrayado.
Con ello la lnea anterior se podra poner as:
Public Function Arco( _
Angulo As Single, _
Radio As Single _
) As Single
Aqu declaramos la funcin como pblica, para que se pueda utilizar desde cualquier parte
de la aplicacin, siempre que se escriba en un mdulo normal.
A continuacin escribimos la palabra Function, seguida de su nombre, en este caso Arco.
[email protected] Eduardo Olaz
Entrega 04 Primeros conceptos 2 04 - 3
Abrimos parntesis y escribimos los dos parmetros que necesitamos, Angulo y Radio,
declarndolos del tipo Single (tipo numrico de coma flotante de 4 Bytes).
Cerramos el parntesis y declaramos la funcin Arco tambin del tipo Single.
Si escribs la cabecera de la funcin en un mdulo normal, veris que VBA, al igual que
pasaba con los procedimientos Sub, os aade automticamente el final correspondiente, es
decir
End Function
Con esto la funcin quedara as:
Public Function Arco( _
Angulo As Single, _
Radio As Single _
) As Single
End Function
Por ahora no es gran cosa, ya que no hace nada.
Permitidme que escriba el cdigo completo de esta funcin y os la explique paso a paso.
Como en la entrega anterior, voy a declarar la constante Pi como pblica en la cabecera del
mdulo, para que pueda ser utilizada por la aplicacin.
Si ya la tuviera declarada en otro mdulo este paso no sera necesario.
El cdigo sera el siguiente:
Tras completar la expresin, y darle a [Enter] nos escribir: 6,283185 que es la longitud
de un arco de radio 1 y ngulo 360, lo que equivale a la circunferencia completa.
Vamos a hacer un experimento: Qu pasa si cambiamos la declaracin de tipo de esta
funcin?
Vamos a cambiar el Single de la declaracin de la cabecera, por Double.
Double es un nmero de coma flotante de ms precisin que single (8 Bytes de Double
frente a 4 de single). La cabecera quedar as:
Public Function Arco( _
Angulo As Single, _
Radio As Single _
) As Double
Para ello escribiremos ? Arco(360,1) en la ventana Inmediato, y presionamos [Enter].
Efectivamente la precisin ha aumentado, ya que el valor escrito ha sido:
6,28318530717958
Por ello si cambiamos ahora la cabecera:
Public Function Arco( _
Angulo As Double, _
Radio As Double _
) As Double
Se supone que los clculos sern ms precisos.
Efectivamente as es, pero en una aplicacin crtica deberamos jugar que el tipo de
precisin adecuada, para hacer la aplicacin lo ms ligera posible.
Si probamos a hacer el cambio vemos que en nuestra funcin, con los datos anteriores
apenas cambia el resultado. Pero qu pasara si estuviramos programando la rbita de
una nave con destino a Marte? En este caso la precisin sera un elemento clave.
Funciones en formularios
Vamos a hacer una pequea y elemental calculadora que nos permita sumar dos cifras.
Cerramos los mdulos y creamos, abrimos un formulario en modo diseo.
Este formulario no lo enlazamos con ninguna tabla ni consulta.
Ahora vamos a deshabilitar el asistente para controles.
En la barra de controles, pulsamos en la Varita mgica para deshabilitarla.
Deber quedar sin resaltar, como se indica en el grfico con las flechas rojas.
A lo que bamos.
Tenemos en un formulario los siguientes elementos:
txtSumando_1 Cuadro de texto
txtSumando_2 Cuadro de texto
cmdSumar Botn de comando
Probablemente al poner los cuadros de texto se nos hayan colocado dos etiquetas.
De momento no vamos a cambiar su nombre, pero les vamos a poner como Ttulo
Operando 1
Operando 2
Ahora vamos a poner una etiqueta nueva, con ttulo Resultado, y de nombre lblResultado.
Ms de uno se habr dado cuenta que lbl viene de Label (etiqueta en ingls), txt de Text y
cmd de Command.
A esta etiqueta le vamos a poner un texto un poco ms grande y como color de texto el rojo.
Pero qu quieres que hagamos con todo esto?
Tan simple como tener un formulario en el que escribir dos nmeros en las correspondientes
casillas, y que al pulsar un botn nos muestre su suma.
Y cmo sabe Access cuando se ha pulsado el botn y qu es lo que tiene que hacer?
Para eso utilizaremos el Evento Clic del botn cmdSumar.
Ya he comentado que un Evento es un mensaje que manda Windows, cuando pasa algo,
que puede ser captado por Access y a su vez reenviado a Windows con un cdigo que se
tiene que ejecutar.
Seleccionamos el botn, y en la [Hoja de Propiedades] pulsamos en la pestaa Eventos.
Seleccionamos el cuadro correspondiente a Al hacer clic y pulsamos en el pequeo botn
con tres puntos que nos aparece.
A continuacin veremos una pequea pantalla que nos permite seleccionar entre
Generador de expresiones
Generador de macros
Generador de cdigo
Lgicamente seleccionamos Generador de cdigo, y pulsamos [Aceptar] doble clic en
[Generador de cdigo].
Inmediatamente se nos abre el editor de cdigo con el siguiente cdigo
Option Compare Database
Option Explicit
End Sub
El cursor estar seguramente posicionado entre las dos lneas.
Qu es esto?
Es el procedimiento que captura el evento Clic del botn cmdSumar.
Ahora lo que quiero es que tras poner un valor en cada uno de los cuadros de texto, si
pulsamos el botn, nos muestre el resultado de la suma en la etiqueta lblResultado.
El contenido de un cuadro de texto lo maneja su propiedad Value, que se puede leer y
escribir.
El contenido de una etiqueta (su ttulo) lo maneja su propiedad Caption, y tambin es de
lectura y Escritura.
Vamos al curro.
Escribimos lo siguiente
Private Sub cmdSumar_Click()
Me.lblResultado.Caption = Me.txtSumando_1.Value + Me.txtSumando_2.Value
End Sub
Que traducido al cristiano quiere decir:
Cuando se presione sobre el botn cmdSumar (evento clic) pon como ttulo de la etiqueta
lblResultado (propiedad caption) el resultado de sumar el contenido (propiedad Value)
del cuadro de texto txtSumando_1 y del cuadro de texto txtSumando_2.
El control Cuadro de texto es un TextBox y la Etiqueta un control Label.
Bueno, grabamos el cdigo y el formulario y lo abrimos.
Nos quedar algo as como
Qu ha pasado?.
Por qu en vez de un 5 nos da 23? al fin y al cabo 2 ms 3 son 5
Comencemos a programar con VBA - Access
04 - 8
Ahora vamos a ejecutar el formulario, pero antes de presionar el botn de sumar dejamos
uno de los cuadros de texto sin nada escrito en l.
Un nuevo problema!...
Como uno de los cuadros de texto tena el valor Nulo (Null), VBA no puede sumarlo al
contenido del otro cuadro de texto. Podramos decir que un nulo no se puede sumar con
nada.
Pero qu tenemos que hacer para poder sumar los datos?
Primero deberamos convertir los valores contenidos en los cuadros de texto a valores
numricos.
Para efectuar esa conversin existe una funcin de VBA llamada Val(Valor)
Si escribimos en la ventana inmediato la palabra Val, ponemos en ella el cursor y
presionamos [F1] nos aparece la ayuda de la funcin Val.
Con la siguiente informacin:
Devuelve los nmeros contenidos en una cadena como un valor numrico del tipo
adecuado.
Sintaxis
Val(cadena)
El argumento obligatorio cadena es cualquier expresin de cadena vlida.
Vamos a hacer pruebas en la ventana Inmediato.
Escribimos las sucesivas expresiones y presionamos [Enter]
Expresin Resultado impreso
? "2" + "3" 23
?2+3 5
? Val("2") + Val("3") 5
? Val("12.234") 12,234
? Val(" 23 Caballos") 23
? Val(" 3,1416") 3
? Val(Pepe) 0
? Val(Null) Genera un error
(Nulo no tiene un valor numrico)
? Val(Nz(Null,"")) 0
? Nz(Null,Valor Nulo) Valor Nulo
? Nz(Pepe,Valor Nulo) Pepe
Despus de estos pequeos experimentos dejo que saquis vuestras propias conclusiones.
Vemos aqu una cosa nueva, la funcin Nz(Valor).
Vamos a escribir Nz en la ventana Inmediato y pulsamos [F1].
Pone algo semejante a esto
Nz(ValorVariant[,ValorSiEsNulo])
El resumen de la informacin es que la funcin Nz devuelve uno de esto dos tipos de datos.
Si el primer argumento no es nulo, devuelve el primer argumento.
Si fuera nulo, devolvera el valor del segundo argumento.
[email protected] Eduardo Olaz
Entrega 04 Primeros conceptos 2 04 - 11
Si ahora no escribimos nada en alguno, o los dos cuadros de texto, ya no nos genera el
error.
Igualmente si escribimos valores numricos, nos muestra el dato correcto.
Si escribimos un dato no numrico lo cambia al valor Cero, al resultado de Val(Expresin).
Tenemos una nueva funcin.
En la penltima lnea del cdigo vemos:
lblResultado.Caption = CStr(dblSumando1 + dblSumando2)
La funcin CStr(Valor) convierte un valor numrico a un texto, para asignarlo a la
propiedad caption de la etiqueta lblResultado., que slo admite textos.
Este ltimo paso no es estrictamente necesario, ya que VBA efecta implcitamente la
conversin.
Fijaros ahora que en el cdigo repetimos dos veces la expresin Val(Nz(...
Si pensamos un poco vemos que nos resultara interesante crearnos una funcin ms
avanzada que Val, que nos devolviera un valor numrico como sta pero que no diera error
si se le pasa un valor nulo.
Podramos llamarla ValorNumerico(Valor) y devolvera, por ejemplo un valor de tipo coma
flotante Doble.
Como deseamos que se pueda utilizar desde cualquier parte de Access la haremos pblica
y la escribiremos en un mdulo Estndar y el cdigo sera algo as:
Public Function ValorNumerico ( _
Valor As Variant _
) As Double
ValorNumerico = Val(Nz(Valor,))
End Function
Por cierto, las dos comillas seguidas equivalen a una cadena de texto de longitud 0.
No confundir con Null. Ya se que es lioso, pero por ahora creedme.
Esta funcin devuelve el valor Cero cuando le pasamos un valor que sea texto no numrico,
o un valor nulo.
El parmetro Valor se declara como Variant para que pueda admitir tanto Cadenas de
Texto, como Nmeros e incluso el valor Null.
Os recuerdo que la funcin la debis escribir en un mdulo estndar si la queris usar desde
cualquier otra parte de Access.
Tras esto podramos simplificar el cdigo del formulario y cambiarlo por el siguiente:
Private Sub cmdSumar_Click()
Dim dblSumando1 As Double
Dim dblSumando2 As Double
dblSumando1 = ValorNumerico(txtSumando_1)
dblSumando2 = ValorNumerico(txtSumando_2)
lblResultado.Caption = CStr(dblSumando1 + dblSumando2)
End Sub
Ya se que todo esto os puede resultar un poco indigesto, pero haciendo pruebas es como
mejor lo podris asimilar.
VBA - Access
Entrega 04
Primeros conceptos 2
Eduardo Olaz
04 - 2
Funciones
En la entrega anterior hemos visto una introduccin a los procedimientos Sub.
Otro de los tipos de procedimientos son los procedimientos Function, que al igual que los
procedimientos Sub estn delimitados por Function y End Function.
La principal diferencia entre un procedimiento Sub y un procedimiento Function es que este
ltimo devuelve un valor.
Entre los dos delimitadores se escribe el cdigo que va a realizar las tareas que deseemos,
y al final devolver algn valor.
Son las llamadas Funciones.
Veamos la forma como lo explica la ayuda de Access.
Si vamos a la ventana Inmediato, escribimos Function, ponemos el cursor en lo escrito y
presionamos [F1], entre otras cosas nos aparece la sintaxis de su declaracin:
End Function
Vemos que para declarar una funcin empezaramos, por ejemplo poniendo la palabra
Public (si quisiramos que la funcin sea accesible desde cualquier parte de Access) a
continuacin la palabra Function, despus abriramos un parntesis y pondramos los
parmetros que necesitramos, cerraramos el parntesis y finalmente pondramos el tipo de
datos que devolvera la funcin.
Supongamos que quisiramos escribir una funcin en la que pasndole el ngulo y el radio,
nos devolviera la longitud de un arco de circunferencia.
La cabecera de esta funcin sera:
Public Function Arco(Angulo As Single, Radio As Single) As Single
Hay un truco para que una lnea con mucho texto se pueda dividir en varias lneas, sin que
deje de ser una nica lnea.
Se coloca al final de la lnea que se quiere dividir un espacio en blanco y la raya de
subrayado.
Con ello la lnea anterior se podra poner as:
Public Function Arco( _
Angulo As Single, _
Radio As Single _
) As Single
Aqu declaramos la funcin como pblica, para que se pueda utilizar desde cualquier parte
de la aplicacin, siempre que se escriba en un mdulo normal.
A continuacin escribimos la palabra Function, seguida de su nombre, en este caso Arco.
[email protected] Eduardo Olaz
Entrega 04 Primeros conceptos 2 04 - 3
Abrimos parntesis y escribimos los dos parmetros que necesitamos, Angulo y Radio,
declarndolos del tipo Single (tipo numrico de coma flotante de 4 Bytes).
Cerramos el parntesis y declaramos la funcin Arco tambin del tipo Single.
Si escribs la cabecera de la funcin en un mdulo normal, veris que VBA, al igual que
pasaba con los procedimientos Sub, os aade automticamente el final correspondiente, es
decir
End Function
Con esto la funcin quedara as:
Public Function Arco( _
Angulo As Single, _
Radio As Single _
) As Single
End Function
Por ahora no es gran cosa, ya que no hace nada.
Permitidme que escriba el cdigo completo de esta funcin y os la explique paso a paso.
Como en la entrega anterior, voy a declarar la constante Pi como pblica en la cabecera del
mdulo, para que pueda ser utilizada por la aplicacin.
Si ya la tuviera declarada en otro mdulo este paso no sera necesario.
El cdigo sera el siguiente:
Tras completar la expresin, y darle a [Enter] nos escribir: 6,283185 que es la longitud
de un arco de radio 1 y ngulo 360, lo que equivale a la circunferencia completa.
Vamos a hacer un experimento: Qu pasa si cambiamos la declaracin de tipo de esta
funcin?
Vamos a cambiar el Single de la declaracin de la cabecera, por Double.
Double es un nmero de coma flotante de ms precisin que single (8 Bytes de Double
frente a 4 de single). La cabecera quedar as:
Public Function Arco( _
Angulo As Single, _
Radio As Single _
) As Double
Para ello escribiremos ? Arco(360,1) en la ventana Inmediato, y presionamos [Enter].
Efectivamente la precisin ha aumentado, ya que el valor escrito ha sido:
6,28318530717958
Por ello si cambiamos ahora la cabecera:
Public Function Arco( _
Angulo As Double, _
Radio As Double _
) As Double
Se supone que los clculos sern ms precisos.
Efectivamente as es, pero en una aplicacin crtica deberamos jugar que el tipo de
precisin adecuada, para hacer la aplicacin lo ms ligera posible.
Si probamos a hacer el cambio vemos que en nuestra funcin, con los datos anteriores
apenas cambia el resultado. Pero qu pasara si estuviramos programando la rbita de
una nave con destino a Marte? En este caso la precisin sera un elemento clave.
Funciones en formularios
Vamos a hacer una pequea y elemental calculadora que nos permita sumar dos cifras.
Cerramos los mdulos y creamos, abrimos un formulario en modo diseo.
Este formulario no lo enlazamos con ninguna tabla ni consulta.
Ahora vamos a deshabilitar el asistente para controles.
En la barra de controles, pulsamos en la Varita mgica para deshabilitarla.
Deber quedar sin resaltar, como se indica en el grfico con las flechas rojas.
A lo que bamos.
Tenemos en un formulario los siguientes elementos:
txtSumando_1 Cuadro de texto
txtSumando_2 Cuadro de texto
cmdSumar Botn de comando
Probablemente al poner los cuadros de texto se nos hayan colocado dos etiquetas.
De momento no vamos a cambiar su nombre, pero les vamos a poner como Ttulo
Operando 1
Operando 2
Ahora vamos a poner una etiqueta nueva, con ttulo Resultado, y de nombre lblResultado.
Ms de uno se habr dado cuenta que lbl viene de Label (etiqueta en ingls), txt de Text y
cmd de Command.
A esta etiqueta le vamos a poner un texto un poco ms grande y como color de texto el rojo.
Pero qu quieres que hagamos con todo esto?
Tan simple como tener un formulario en el que escribir dos nmeros en las correspondientes
casillas, y que al pulsar un botn nos muestre su suma.
Y cmo sabe Access cuando se ha pulsado el botn y qu es lo que tiene que hacer?
Para eso utilizaremos el Evento Clic del botn cmdSumar.
Ya he comentado que un Evento es un mensaje que manda Windows, cuando pasa algo,
que puede ser captado por Access y a su vez reenviado a Windows con un cdigo que se
tiene que ejecutar.
Seleccionamos el botn, y en la [Hoja de Propiedades] pulsamos en la pestaa Eventos.
Seleccionamos el cuadro correspondiente a Al hacer clic y pulsamos en el pequeo botn
con tres puntos que nos aparece.
A continuacin veremos una pequea pantalla que nos permite seleccionar entre
Generador de expresiones
Generador de macros
Generador de cdigo
Lgicamente seleccionamos Generador de cdigo, y pulsamos [Aceptar] doble clic en
[Generador de cdigo].
Inmediatamente se nos abre el editor de cdigo con el siguiente cdigo
Option Compare Database
Option Explicit
End Sub
El cursor estar seguramente posicionado entre las dos lneas.
Qu es esto?
Es el procedimiento que captura el evento Clic del botn cmdSumar.
Ahora lo que quiero es que tras poner un valor en cada uno de los cuadros de texto, si
pulsamos el botn, nos muestre el resultado de la suma en la etiqueta lblResultado.
El contenido de un cuadro de texto lo maneja su propiedad Value, que se puede leer y
escribir.
El contenido de una etiqueta (su ttulo) lo maneja su propiedad Caption, y tambin es de
lectura y Escritura.
Vamos al curro.
Escribimos lo siguiente
Private Sub cmdSumar_Click()
Me.lblResultado.Caption = Me.txtSumando_1.Value + Me.txtSumando_2.Value
End Sub
Que traducido al cristiano quiere decir:
Cuando se presione sobre el botn cmdSumar (evento clic) pon como ttulo de la etiqueta
lblResultado (propiedad caption) el resultado de sumar el contenido (propiedad Value)
del cuadro de texto txtSumando_1 y del cuadro de texto txtSumando_2.
El control Cuadro de texto es un TextBox y la Etiqueta un control Label.
Bueno, grabamos el cdigo y el formulario y lo abrimos.
Nos quedar algo as como
Qu ha pasado?.
Por qu en vez de un 5 nos da 23? al fin y al cabo 2 ms 3 son 5
Comencemos a programar con VBA - Access
04 - 8
Ahora vamos a ejecutar el formulario, pero antes de presionar el botn de sumar dejamos
uno de los cuadros de texto sin nada escrito en l.
Un nuevo problema!...
Como uno de los cuadros de texto tena el valor Nulo (Null), VBA no puede sumarlo al
contenido del otro cuadro de texto. Podramos decir que un nulo no se puede sumar con
nada.
Pero qu tenemos que hacer para poder sumar los datos?
Primero deberamos convertir los valores contenidos en los cuadros de texto a valores
numricos.
Para efectuar esa conversin existe una funcin de VBA llamada Val(Valor)
Si escribimos en la ventana inmediato la palabra Val, ponemos en ella el cursor y
presionamos [F1] nos aparece la ayuda de la funcin Val.
Con la siguiente informacin:
Devuelve los nmeros contenidos en una cadena como un valor numrico del tipo
adecuado.
Sintaxis
Val(cadena)
El argumento obligatorio cadena es cualquier expresin de cadena vlida.
Vamos a hacer pruebas en la ventana Inmediato.
Escribimos las sucesivas expresiones y presionamos [Enter]
Expresin Resultado impreso
? "2" + "3" 23
?2+3 5
? Val("2") + Val("3") 5
? Val("12.234") 12,234
? Val(" 23 Caballos") 23
? Val(" 3,1416") 3
? Val(Pepe) 0
? Val(Null) Genera un error
(Nulo no tiene un valor numrico)
? Val(Nz(Null,"")) 0
? Nz(Null,Valor Nulo) Valor Nulo
? Nz(Pepe,Valor Nulo) Pepe
Despus de estos pequeos experimentos dejo que saquis vuestras propias conclusiones.
Vemos aqu una cosa nueva, la funcin Nz(Valor).
Vamos a escribir Nz en la ventana Inmediato y pulsamos [F1].
Pone algo semejante a esto
Nz(ValorVariant[,ValorSiEsNulo])
El resumen de la informacin es que la funcin Nz devuelve uno de esto dos tipos de datos.
Si el primer argumento no es nulo, devuelve el primer argumento.
Si fuera nulo, devolvera el valor del segundo argumento.
[email protected] Eduardo Olaz
Entrega 04 Primeros conceptos 2 04 - 11
Si ahora no escribimos nada en alguno, o los dos cuadros de texto, ya no nos genera el
error.
Igualmente si escribimos valores numricos, nos muestra el dato correcto.
Si escribimos un dato no numrico lo cambia al valor Cero, al resultado de Val(Expresin).
Tenemos una nueva funcin.
En la penltima lnea del cdigo vemos:
lblResultado.Caption = CStr(dblSumando1 + dblSumando2)
La funcin CStr(Valor) convierte un valor numrico a un texto, para asignarlo a la
propiedad caption de la etiqueta lblResultado., que slo admite textos.
Este ltimo paso no es estrictamente necesario, ya que VBA efecta implcitamente la
conversin.
Fijaros ahora que en el cdigo repetimos dos veces la expresin Val(Nz(...
Si pensamos un poco vemos que nos resultara interesante crearnos una funcin ms
avanzada que Val, que nos devolviera un valor numrico como sta pero que no diera error
si se le pasa un valor nulo.
Podramos llamarla ValorNumerico(Valor) y devolvera, por ejemplo un valor de tipo coma
flotante Doble.
Como deseamos que se pueda utilizar desde cualquier parte de Access la haremos pblica
y la escribiremos en un mdulo Estndar y el cdigo sera algo as:
Public Function ValorNumerico ( _
Valor As Variant _
) As Double
ValorNumerico = Val(Nz(Valor,))
End Function
Por cierto, las dos comillas seguidas equivalen a una cadena de texto de longitud 0.
No confundir con Null. Ya se que es lioso, pero por ahora creedme.
Esta funcin devuelve el valor Cero cuando le pasamos un valor que sea texto no numrico,
o un valor nulo.
El parmetro Valor se declara como Variant para que pueda admitir tanto Cadenas de
Texto, como Nmeros e incluso el valor Null.
Os recuerdo que la funcin la debis escribir en un mdulo estndar si la queris usar desde
cualquier otra parte de Access.
Tras esto podramos simplificar el cdigo del formulario y cambiarlo por el siguiente:
Private Sub cmdSumar_Click()
Dim dblSumando1 As Double
Dim dblSumando2 As Double
dblSumando1 = ValorNumerico(txtSumando_1)
dblSumando2 = ValorNumerico(txtSumando_2)
lblResultado.Caption = CStr(dblSumando1 + dblSumando2)
End Sub
Ya se que todo esto os puede resultar un poco indigesto, pero haciendo pruebas es como
mejor lo podris asimilar.
VBA - Access
Entrega 05
Tipos de datos y
Declaraciones
Eduardo Olaz
05 - 2
Declaracin de variables
En entregas anteriores hemos visto cmo se declaran las variables. En esta entrega vamos
a ampliar conceptos.
Una variable es un elemento del cdigo que apunta a una direccin de memoria en donde
se almacena un dato.
Haciendo referencia a la variable se puede devolver el dato al que apunta e incluso
modificarlo.
Las constantes son similares a las variables, slo que su contenido se le asigna en el
momento en el que se declaran, y despus no es posible cambiarlo.
Hay tres temas que debemos considerar en una variable
El nombre de la variable
El tipo de dato al que apunta
El mbito en el que es visible.
Construccin del nombre de una variable (o constante).
Nombre
El nombre de una variable est compuesto por caracteres ASCII.
Para su construccin hay que ceirse a las siguientes reglas:
No se pueden usar caracteres que tienen un uso especial en Access, como son el
Punto .,los parntesis ( ), la barra vertical |, o los caracteres que se
pueden utilizar como operadores; entre ellos
+ - / * < >.
Una variable debe empezar por una letra por el signo de subrayado
Estos nombres seran correctos, lo que no quiere decir que sean aconsejables.
A123456 _Pepe R2P2
El nombre de una variable no puede tener espacios en blanco.
Por ejemplo no sera vlido el nombre Apellidos Nombre.
En cambio s sera vlido Apellidos_Nombre ApellidosNombre.
Una variable puede terminar con un carcter de declaracin de tipo
% & ! # @ $
Estos caracteres slo se pueden usar al final del nombre de la variable.
Nota: Estos caracteres tambin se pueden usar para declarar el tipo de dato que
devuelve una funcin.
Por ejemplo esta cabecera de funcin sera vlida:
Public Function Nombre$()
Que sera equivalente a:
Public Function Nombre() As String
No se puede usar como nombre de variable una palabra reservada de VBA.
Por ejemplo no se pueden usar String, integer, For, If como nombres de variable.
El nombre de una variable puede tener hasta 255 caracteres - aunque yo de ti no lo
intentara forastero -.
No se pueden declarar dos variables con el mismo nombre dentro del mismo
procedimiento o en la cabecera de un mismo mdulo.
Tipos de datos
Adems de las Variables hay otra serie de elementos que manejan datos, como son las
Constantes, Procedimientos Sub y procedimientos Function que son capaces de manejar
datos de distintos tipos, e incluso las funciones que devuelven datos.
Pero qu tipos de datos podemos manejar? Y qu caractersticas tienen?
Hay varios tipos de datos.
Entre ellos podemos definir
Numricos
Booleanos
Fecha / Hora
De texto (cadenas)
Variant
De objeto
Registros de datos definidos por el usuario, . . .
Datos numricos
Existen dos familias de datos numricos.
Datos numricos de nmero entero
Datos numricos de coma flotante.
Como datos enteros tenemos los siguientes tipos:
Nombre del Tipo Tamao Valor inferior Valor Superior Sufijo Prefijo
Byte 1 Byte 0 255 byt
Integer 2 Bytes -32.768 32.767 % int
Long 4 Bytes -2.147.483.648 2.147.483.647 & lng
Por Sufijo entendemos un carcter de definicin de tipo que se puede aadir a la Variable
Constante, para definir el tipo al que pertenece.
Por ejemplo Dim ValorLong& declara implcitamente la variable ValorLong
como Long.
Esta declaracin equivale a la siguiente
Dim ValorLong as Long
Si hubiramos hecho Dim ValorLong a secas, la variable ValorLong se hubiera
declarado como Variant.
El uso de estos caracteres de definicin de tipo, es una herencia del Basic primitivo.
Esos caracteres Sufijo se pueden tambin aplicar a las declaraciones de constantes
Public Const MesesAo As Integer = 12
Equivale a Public Const MesesAo% = 12
Si se utilizan estos caracteres, no hay que utilizar la declaracin explcita de tipo.
Comencemos a programar con VBA - Access
05 - 4
Por ejemplo
Dim Asistentes% As Integer
Dara error ya que sera una declaracin redundante porque Dim Asistentes% ya ha
definido Asistentes como Integer.
El uso del sufijo es aplicable tambin a los valores. Esto puede ser muy til en determinadas
circunstancias.
Por ejemplo intenta hacer lo siguiente:
Abre el editor de cdigo, ponte en la ventana Inmediato y escribe lo siguiente:
a = 256 * 256 : Print a
Un comentario: los dos puntos actan como separador de las dos sentencias.
Al presionar la tecla [Intro] nos aparece un bonito mensaje de error de desbordamiento.
Modifiquemos la lnea anterior y pongamos lo siguiente (siempre en la ventana inmediato).
a = 256& * 256 : Print a
Ahora s nos imprime 65536
El error se produce porque VBA deduce que en la primera expresin debe producir como
mximo un valor del tipo Integer y 65536, que es su resultado, est por encima del
mximo admitido para un Integer.
No me preguntis por qu lo hace, alguien de Microsoft tom esta decisin en su momento.
En la segunda expresin, al poner uno de los trminos como Long usando 256&, hace que
la expresin la considere como Long, que admite perfectamente el valor resultante.
Para ver que el error no lo produce a, sino la expresin, escribe directamente en la ventana
inmediato lo siguiente:
Print 256 * 256
Se produce exactamente el mismo error.
En cambio si escribimos
Print 256 * 256&
El error desaparece.
Prefijo
Por prefijo entenderemos el conjunto de letras que es aconsejable poner delante del
nombre de una variable, para indicarle a la persona que escribe, lee, el cdigo, el tipo de
dato que contiene una variable.
Aqu voy a tratar de seguir, no de forma absoluta, algunas de las llamadas
Convenciones de nombres de Leszynski para Microsoft Access.
Incluyo un resumen de las normas de Leszynski en el Apndice 02.
Tambin puedes encontrar una descripcin sucinta del convenio de Leszynski entre
las pginas 19 y 27 de este documento.
http://guajiros.udea.edu.co/fnsp/Documentos/Direccion/SII/Normalizacion.pdf
Adems incluye interesantes reglas sobre normas para el desarrollo de programas.
Tambin podis encontrar informacin en el sitio de McPegasus:
http://www.iespana.es/mcpegasus/CONTENT/leszynski.htm
En las pginas del MSDN de Microsoft podis encontrar informacin muy interesante
sobre la normativa de codificacin:
http://msdn.microsoft.com/library/spa/default.asp?url=/library/SPA/vbcn7/html/vbconP
rogrammingGuidelinesOverview.asp
La ventaja de utilizar estos mtodos se aprecia inmediatamente. As, slo con leer que una
tiene como nombre lngDiasTrabajados podramos deducir que es una variable de tipo
Long que probablemente sirva para manejar los das trabajados.
Si en una lnea de cdigo aparece el nombre cmdSalir, podramos deducir que es un botn
de comando que probablemente sirva para salir de un formulario u otro sitio.
Igualmente lblNombre es una etiqueta y txtApellido1 es un cuadro de texto. Ya iremos
viendo estas cositas poco a poco.
Repito que los prefijos, int, lng, txt, lbl, cmd, etc. no modelan el tipo de contenido de la
variable, sino que sirven como informacin adicional para la persona que escribe lee el
cdigo.
Por Sufijo entendemos un carcter de definicin de tipo que se puede aadir a la Variable
Para el manejo de valores monetarios se suele utilizar el tipo Currency.
Este tipo no da errores de redondeo y permite manejar hasta magnitudes de 15 dgitos
exactos en su parte entera. En posteriores captulos haremos mencin a algunos errores de
redondeo que pueden llegar a dar los tipos de coma flotante.
Tipo Decimal
El tipo Decimal es un tipo muy especial.
Permite trabajar con hasta 29 dgitos enteros exactos hasta con 28 dgitos exactos en su
parte decimal.
Es un tipo con muy poco uso en Access, ya que normalmente no se necesita ese tipo de
precisin, y adems resulta engorroso su uso.
Algunas de sus peculiaridades se explican en el Apndice 01.
Tipo Date
El tipo Date es un tipo de dato adecuado para manejar datos de tipo Fecha / Hora.
Puntualizaciones:
Ya os habris dado cuenta que VBA utiliza el Ingls como lenguaje, y ms concretamente el
Ingls americano. Esto hace que los datos usen ese mismo modelo.
Por ejemplo, la coma flotante nuestra, ellos la cambian por el punto.
Algo as pasa con las fechas. El formato americano de fecha usa el siguiente orden:
Mes / Da / Ao
Por eso en la lnea
datFechaActual = #1/20/2005 6:15:30 PM#
se pone 1/20/2005, en vez de 20/1/2005 como hacemos nosotros.
Esto es importante recordarlo ya que nos evitar futuros errores.
Adems VBA tiene un comportamiento que puede despistar.
Si hubiramos hecho
datFechaActual = #20/1/2005 6:15:30 PM#
Hubiera funcionado exactamente igual, ya que VBA deducira que el 20 no puede referirse al
mes, pues existen slo 12 meses, por lo que deduce por su cuenta que lo que en realidad
queramos era introducir el 20 como da y el 1 como mes.
Estos comportamientos que a veces tiene VBA de tomar decisiones por su cuenta es algo
que me saca de quicio (nada ni nadie es perfecto).
Resumiendo
La forma de construir una fecha / hora es
# Mes / Da / Ao Horas:Minutos:Segundos #
Dependiendo de la configuracin de Windows que tengas, si por ejemplo introduces
datFechaActual = #1/20/2005 18:15:30#
VBA te lo puede convertir automticamente a
datFechaActual = #1/20/2005 6:15:30 PM#
aadindole por su cuenta el PM
Y no slo toma decisiones de ese tipo.
Si escribes
datFechaActual = #1-20-2005#
VBA te cambia automticamente a
datFechaActual = #1/20/2005#
Para construir una fecha no es necesario introducirle la hora.
Tampoco es necesario introducirle el ao entero.
Estas fechas son perfectamente vlidas
#1/20/2005 18:15:30#
#1/20/2005 6:15:30 PM#
#1/20/2005#
#1/20/05#
#01/20/05#
#18:15:30#
Puedes obtener ms informacin en la ayuda de Access.
Hay toda una batera de funciones de VBA para el manejo y manipulacin de fechas.
Estas funciones las veremos ms adelante.
blnDatoBoleano = True
Debug.Print "Valor True " & blnDatoBoleano
blnDatoBoleano = False
Debug.Print "Valor False " & blnDatoBoleano
blnDatoBoleano = -1
Debug.Print "Valor -1 " & blnDatoBoleano
blnDatoBoleano = 0
Debug.Print "Valor 0 " & blnDatoBoleano
blnDatoBoleano = 4
Debug.Print "Valor 4 " & blnDatoBoleano
Debug.Print "Valor entero de Verdadero " & CInt(blnDatoBoleano)
End Sub
VBA - Access
Entrega 06
Estructuras de datos
Eduardo Olaz
06 - 2
Matrices Arrays
Una matriz en VBA es un conjunto de variables del mismo tipo, a las que se puede acceder
mediante un ndice, que indica su posicin en ella.
Imaginemos que queremos almacenar en el cdigo, para su posterior utilizacin, el nmero
de das de cada mes del ao.
Por ejemplo, podemos hacer esto
Public Mes01 As Integer, Mes02 As Integer
Public Mes03 As Integer, Mes04 As Integer
Public Mes05 As Integer, Mes06 As Integer
Public Mes07 As Integer, Mes08 As Integer
Public Mes09 As Integer, Mes10 As Integer
Public Mes11 As Integer, Mes12 As Integer
Mes(10) = 31
Mes(11) = 30
Mes(12) = 31
End Sub
Para asignar los valores a los elementos de la matriz, ejecutaremos el procedimiento
CargarMeses
La tercera forma an resulta ms directa
Dim Mes() As Variant
A veces, por facilidad de lectura del cdigo, interesa distribuir la escritura de una
nica lnea de cdigo, en varias lneas fsicas. Para ello se pone al final de la lnea un
espacio en blanco seguido de la barra baja, como se ve en el ejemplo anterior.
Para acceder a los das de un mes, por ejemplo Julio, en el ejemplo primero tenemos que
utilizar directamente la variable
Mes07
Para hacer lo mismo en los ejemplos 2 y 3, tenemos que tomar en cuenta que la variable
Mes contiene los doce valores de los das del mes.
Mes(7)
Este mtodo es mucho ms prctico y da muchas ms posibilidades para usar estructuras
de bucle, como veremos ms adelante.
Pero, por qu he puesto Mes = Array(0, 31, . . .?
Por defecto las matrices, si no se indica el rango de sus ndices, empiezan con el ndice 0.
Lo de aadir un valor ms al principio como valor de Mes, en este caso 0 aunque podra
haber puesto cualquier otro valor, es para que haya una coherencia entre los casos 2 y 3,
y que por ejemplo Mes(7) sea el valor de Julio en las dos matrices.
La declaracin Dim Mes(12) As integer genera trece variables, accesibles desde el
ndice 0 Mes(0) al ndice 12 Mes(12).
Una segunda puntualizacin:
La lnea de cdigo
Mes = Array(0, 31, 28, 31, 30, 31, 30, _
31, 31, 30, 31, 30, 31)
hace que, Mes(i), para cualquiera de los valores de i, sea del tipo integer.
Si quisiramos que Mes(i) devolviera un tipo Long, deberamos poner el sufijo de
declaracin de tipo Long & detrs de cada nmero:
Mes = Array(0&, 31&, 28&, 31&, 30&, 31&, 30&, _
31&, 31&, 30&, 31&, 30&, 31&)
Si quisiramos que las matrices por defecto comenzaran con el ndice 1, deberamos
escribir en uno de los mdulos, antes que cualquier procedimiento o declaracin de matriz,
la instruccin Option Base 1
Si hubiramos escrito en la cabecera del mdulo
Option Base 1
Y a continuacin Dim Mes(12) As integer se puede acceder a la variable Mes
mediante ndices que van del 1 al 12.
Existe la posibilidad de incluir en la declaracin el rango de ndices que va a manejar una
matriz. La forma de hacerlo es
Delimitador NombreDeMatriz(IndiceInferior To IndiceSuperior)
En nuestro caso podramos haber hecho
Public Mes(1 to 12) As integer
En los casos que hemos visto hasta ahora, estamos utilizando Matrices unidimensionales,
cuyos elementos son accesibles mediante 1 nico ndice.
Son del tipo Matriz(Indice)
Matrices dinmicas
Supongamos que estamos haciendo un programa de ventas y que uno de sus condiciones
es poder tener controladas en memoria, una vez seleccionado un tipo de producto, las
referencias que existen del mismo.
Nos podremos encontrar tipos de producto con 1 referencia, otros con 4 con cualquier
nmero de ellas.
A priori desconocemos el nmero de referencias que puede tener un tipo de producto, es
ms su nmero puede cambiar con el tiempo.
Para solucionar este tipo de problemas existen las llamadas Matrices Dinmicas.
Una matriz dinmica debe ser declarada, a nivel de mdulo o de procedimiento, sin ndices.
En nuestro caso se hara
Dim Referencias() As String
Ms adelante, en un procedimiento, podramos asignarle el nmero de elementos.
Debug.Print
n = 5
ReDim Referencias(1 To n)
Referencias(5) = "Referencia 05"
Debug.Print Referencias(5)
n = 8
ReDim Referencias(1 To n)
Debug.Print
Debug.Print "Tras Redim"
Debug.Print "Los datos se han borrado"
Debug.Print """" & Referencias(5) & """"
Debug.Print
Referencias(5) = "Referencia 05"
Referencias(8) = "Referencia 08"
Debug.Print "Los datos se han cargado"
Debug.Print """" & Referencias(5) & """"
Debug.Print """" & Referencias(8) & """"
Debug.Print
n = 10
ReDim Preserve Referencias(1 To n)
Debug.Print "Tras Redim con Preserve"
Debug.Print "los datos se han conservado"
Debug.Print """" & Referencias(5) & """"
Comencemos a programar con VBA - Access
06 - 6
Referencia 05
Tras Redim
Los datos se han borrado
""
Instruccin Erase
Si tenemos declarada una matriz dinmica, VBA reserva una zona de memoria para guardar
sus datos.
Si quisiramos dejar libre, de forma explcita esa memoria una vez utilizada esa matriz,
podemos usar la instruccin Erase.
Si consultamos la ayuda de VBA indica que Erase Vuelve a inicializar los elementos de
matrices de tamao fijo y libera el espacio de almacenamiento asignado a matrices
dinmicas.
Esto quiere decir que si tenemos declarada una matriz de tamao fijo por ejemplo:
Dim MatrizFija(10) As String
Dim MatrizFija2(10) As Long
La instruccin
Erase MatrizFija, MatrizFija2
No liberar la memoria ocupada, slo reinicializar la matriz MatrizFija a cadenas
vacas y la matriz MatrizFija2 a ceros.
En cambio si tenemos ReDim Referencias(1 To 5)
Erase Referencias, libera la memoria ocupada por la matriz Referencias.
Debug.Print.Nombre _
& " "; .Apellido1 _
& " "; .Apellido2
Debug.Print "Telfono " _
& .Telefono
End With
End Sub
La instruccin With
Si observamos el cdigo del procedimiento PruebaRegistro de la pgina anterior,
vemos que, tanto para asignar valores a los atributos de la variable Vendedor, he utilizado
la instruccin With, acompaada de su complemento End With.
Esto nos permite evitarnos tener que repetir de reiterativamente el nombre Vendedor en
cada lnea de asignacin lectura.
Entre With Vendedor y End With al escribir el punto se supone que estamos
utilizando atributos del registro Vendedor.
Este tipo de sintaxis ayudados por la instruccin With, se puede utilizar no slo con
Variables Registro, sino tambin con todo tipo de objetos, como veremos posteriormente.
Matrices de Registros
Adems de los tipos de datos estudiados tambin podemos declarar matrices de Estructuras
tipo Registro, incluso Matrices Dinmicas.
Por ejemplo podramos declarar en la cabecera de un formulario lo siguiente:
Private Trabajadores() As Persona
Y en alguno de los procedimientos del formulario podramos reinicializarla; por ejemplo en el
evento Al cargar.
Private Sub Form_Load()
ReDim Trabajadores(100)
End Sub
A partir de este momento podramos cargar y leer datos en la matriz desde cualquiera de los
procedimientos del formulario.
Para ello deberemos pasarle el ndice de la matriz a la variable Trabajadores, y el nombre
del atributo.
Trabajadores(1).Nombre = "Pepe"
Trabajadores(1).Apellido1 = "Gotera"
Trabajadores(2).Nombre = "Otilio"
E incluso podramos utilizar la instruccin With
With Trabajadores(1)
Debug.Print .Nombre
Debug.Print .Apellido1
End With
En el siguiente captulo veremos unos Objetos muy utilizados internamente por Access.
Son las Colecciones.
Estas estructuras del tipo Collection aparecen en muchos elementos de Access:
Formularios
Informes
Controles
ADO
DAO
Etc
VBA - Access
Entrega 07
Colecciones y Objetos
Eduardo Olaz
07 - 2
Podemos incluso definir una palabra clave para acceder despus a un elemento dado de la
coleccin.
NombreDeLaColeccin.Add Elemento, "Clave"
Si utilizamos una clave, podemos tambin colocarlo antes despus de un elemento dado.
Ejemplo:
Supongamos que tenemos la coleccin Productos.
Para aadir elemento "Llave fija de de 7-8 mm." podemos hacer:
Productos.Add "Llave fija de de 7-8 mm."
Si ahora queremos aadir "Destornillador Philips de 9 mm." con la clave
"DestPhi009"
Productos.Add "Destornillador Philips de 9 mm.", "DestPhi009"
Vamos ahora a aadir un nuevo producto en la posicin N 2
Productos.Add "Martillo Carpintero 4", "MrtCrp004", 2
Vamos ahora a aadir un nuevo producto despus de la posicin N 2
Productos.Add "Martillo Carpintero 6", "MrtCrp006", , 2
Para saber cuntos elementos hay en una coleccin tenemos el mtodo Count.
lngElementos = Productos.Count
Podemos obtener un elemento de la coleccin mediante su ndice su Clave.
Para eliminar un elemento de una coleccin se utiliza el mtodo Remove, indicando su
ndice su clave.
Productos.Remove (3)
Productos.Remove ("DestPhi009")
Vamos ahora a probar todo.
Escribimos en un mdulo estndar lo siguiente
Public Sub PruebaColeccion1()
Dim Productos As Collection
Productos.Remove (3)
Productos.Remove ("DestPhi009")
With Clientes
.Add "Antonio Urrutia Garastegui", "Urrutia"
.Add "Ibn Arregui Viana", "Arregui"
.Add "Pedro Martnez Vergara", "Martnez"
End With
End Sub
[email protected] Eduardo Olaz
Entrega 07 Colecciones 07 - 5
Colecciones de Controles
Las colecciones las podemos encontrar en muchas partes de Access.
Por ejemplo los formularios e informe tienen una serie de controles; pues bien, tambin cada
formulario, o informe, posee una coleccin que es la coleccin Controls.
Esta coleccin guarda las referencias de los controles del formulario, o informe.
Vamos a ver cmo podemos leer datos de los Objetos de esta coleccin.
Para ello vamos a utilizar la estructura
For Each Objeto in Me.Controls
Next Objeto
Manos a la obra:
Los objetos del formulario (controles) los almacenaremos en la coleccin Objetos.
Vamos a crear un nuevo formulario, y habiendo desactivado el asistente de controles, como
se explicaba en la entrega 01, vamos a colocar varios controles. Da igual cules sean.
He colocado una Etiqueta, un Cuadro de Texto, un Botn de Opcin, un Cuadro Combinado,
un Cuadro de Lista y un Botn de Comando.
Los cinco ltimos, excepto el botn de comando, llevan a su vez asociada una etiqueta.
El mdulo de clase del formulario es el que se abre desde el modo diseo del formulario, al
presionar en el men Ver y a continuacin la opcin Cdigo.
Tambin se puede presionar el botn [Cdigo]
Ahora, en el mdulo de clase del formulario vamos a escribir lo siguiente
Private Sub Form_Load()
Caption = " Controles en " & Me.Name
MostrarControles
End Sub
MostrarControles
End Sub
Toma, uno a uno, todos los objetos Control que encuentres en la coleccin Controls
del formulario actual y los vas asignando a la variable ctrl.
Con esto se consigue que ctrl vaya adquiriendo sucesivamente la posibilidad de manejar
cada uno de los controles de la coleccin Controls, lo que equivale a poder manejar
todos los controles del formulario.
En este cdigo, cuando ctrl apunta a un control, puede leer modificar algunas de las
propiedades del control al que apunta. Por ejemplo puede leer su propiedad Name y
escribirla en la cadena strMensaje. A continuacin llega a la siguiente lnea que le hace
buscar el siguiente control de la coleccin Controls.
Estas dos lneas son:
strMensaje = strMensaje & ctrl.Name & vbCrLf
Next ctrl
Como elemento nuevo puedo mencionar vbCrLf .
vbCrLf es una constante definida por VBA. Es una constante de texto que contiene dos
caracteres, en concreto el carcter que produce un Retorno de Carro (ASCII 13) y el
carcter que genera un Salto de Lnea (ASCII 10).
Forma parte de las llamadas Constantes Intrnsecas.
En resumen va asignando uno a uno los controles de Controls a la variable ctrl,
leemos su propiedad Name que escribimos en la variable strMensaje y vamos repitiendo
el proceso y escribiendo al principio de la lnea siguiente.
A continuacin mostramos el valor de la variable strMensaje en un cuadro de mensaje.
Este es un ejemplo que nos muestra cmo podemos ir asignando los elementos de una
coleccin de controles a una variable del tipo control.
Las colecciones Controls las crea implcitamente Access en los formularios e informes.
Apellido2 As String
FechaNacimiento As Date
Telefono As String
End Type
Est bien; pero estara mejor si por ejemplo, tras introducir la fecha de nacimiento,
pudiramos obtener adems la Edad de la persona de forma automtica.
Para ello el tipo Persona, debera tener un procedimiento que nos devolviera la edad, en
funcin de la fecha de nacimiento.
Esto no se puede hacer con los tipos Registro.
Para poder hacerlo podemos utilizar una clase.
Para crear una clase primero debemos crearnos un mdulo de clase.
Para ello, desde la ventana del editor de cdigo hacemos lo siguiente.
Desde la opcin de men Insertar seleccionamos la opcin Mdulo de clase.
Tambin podramos haber presionado la flecha Hacia abajo del botn [Agregar mdulo] y
seleccionar Mdulo de clase.
Se nos abre el editor en la ventana del nuevo mdulo, y aparece ste en la ventana del
Explorador del proyecto. Esta ventana normalmente aparecer en la parte izquierda de la
pantalla.
Fijaros que aparece un icono con el nombre Clase1 a su derecha.
Este es un icono especial que llevan los mdulos de clase.
En VBA de Access, y tambin en el de Visual Basic, cada clase debe tener su propio
mdulo. Lo que equivale a decir que en un mdulo de clase slo puede haber una clase.
Vamos a cambiar el nombre de la clase y llamarla CPersona.
Para ello podemos, por ejemplo presionar el botn de [Guardar].
En esta entrega vamos a utilizar una parte muy pequea de las posibilidades de las clases,
pero es una forma de empezar.
Empezando:
Vamos a introducir este cdigo en el mdulo de clase:
Option Compare Database
Option Explicit
End If
End Function
.Nombre = "Antonio"
.Apellido1 = "Urrutia"
.Apellido2 = "Garastegui"
.FechaNacimiento = #2/24/1965#
.Telefono = "998111111"
End With
' Aadimos el contenido de la variable a la coleccin
Empleados.Add psnEmpleado, "Urrutia"
End With
Next Empleado
VaciaColeccion Empleados
End Sub
VBA - Access
Entrega 08
Eduardo Olaz
08 - 2
.Telefono = "696969696"
End With
' Ya no es un Sin Papeles
' est documentado y nos saluda.
Antes de que se termine el procedimiento, existen tres variables que hacen referencias a
objetos de la clase CPersona.
Tras las lneas
Set Friki = Nothing
Set Alienigena1 = Nothing
Set Alienigena2 = Nothing
Destruimos los objetos, al eliminar las referencias que se hacen a ellos.
Un objeto existir en memoria mientras quede alguna variable que haga referencia a
l; es decir Apunte al objeto.
Si tenemos declarado el objeto Friki y hacemos:
Set Alienigena1 = Friki
Set Alienigena2 = Friki
En ese momento, en realidad slo habr un objeto, el que haca referencia la variable
Friki, y tres variables que hacen referencia a l.
Cualquier cambio en las propiedades que hagamos en cualquiera de las variables, se
reflejar inmediatamente en las otras dos, ya que estamos cambiando las propiedades del
mismo objeto.
Recordemos que es un nico objeto con tres referencias diferentes (no caigo qu, pero
esta frase me recuerda a algo)
VBA - Access
Entrega 09
Estructuras de Control
Eduardo Olaz
09 - 2
Estructuras de Control.
Las estructuras de control son segmentos de cdigo que nos permiten tomar decisiones en
base a unos datos dados, o repetir procesos (bucles) mientras sucedan determinadas
condiciones en los parmetros controlados por el cdigo.
Ya hemos comentado algunas de ellas en las entregas anteriores.
Estas estructuras vienen determinadas por una serie de instrucciones, entre las que
destacaremos:
Estructuras de Decisin
If . . . . Then
If . . . . Then . . . . Else
IIF
Select . . . . Case
Estructuras de Bucle
For . . . . Next
For Each . In . . . . Next
While . . . . Wend
Do . . . . Loop
Instruccin de Salto
Goto
Nota:
Antes de seguir adelante, adoptar el sistema habitual para las expresiones de la sintaxis de
una sentencia.
Las partes de cdigo situadas entre corchetes [] son opcionales.
De las partes contenidas entre Llaves {} hay que seleccionar una de ellas.
Estructuras de Decisin.
La Instruccin If
Permite ejecutar un grupo de instrucciones de cdigo, en funcin de que el valor de una
expresin sea Cierta o Falsa True / False.
La forma ms bsica de esta instruccin es:
If condicin Then [instrucciones]
Condicin debe ser una expresin, numrica, relacional lgica que devuelva True
False.
Por ejemplo:
If Divisor<>0 then Cociente = Dividendo/Divisor
Si el valor de la variable Divisor es diferente a Cero, entonces haz que la variable
Cociente tome el valor de la divisin entre la variable Dividendo y la variable
Divisor.
Esta forma de la instruccin If slo se puede poner en una nica lnea de cdigo, aunque
admite mltiples instrucciones separadas por los dos puntos ":".
If Divisor<>0 then C = Dividendo/Divisor : Debug.print C
Segunda forma
If condicin Then
[instrucciones]
End If
El ejemplo anterior podra haberse escrito:
If Divisor<>0 then
Cociente = Dividendo/Divisor
End If
Esta forma permite la ejecucin de varias lneas de sentencias entre Then y End If.
Esta sintaxis es preferible a la primera, ya que genera un cdigo ms claro de interpretar.
La instruccin If permite ejecutar otro grupo de sentencias, si el resultado de la evaluacin
de la expresin fuera falso.
If condicin Then
[instrucciones para el caso de que condicin sea
True]
Else
[instrucciones para el caso de que condicin sea
False]
End If
Ejemplo:
Public Sub PruebaIf01()
Dim Dividendo As Single
Dim Divisor As Single
Dim Cociente As Single
Dividendo = 4
Divisor = 2
End Sub
Comencemos a programar con VBA - Access
09 - 4
En este caso, como Divisor <> 0 devuelve False, se ejecutar la lnea que aparece
entre Else y End If, con lo que mostrar el mensaje de error.
Estas sentencias admiten an un modo adicional, y es usar Else If. Es una nueva
evaluacin tras una anterior que da como resultado falso.
Supongamos que queremos hacer una funcin que devolviera el Nombre de provincia en
funcin de un cdigo. Acepto por adelantado que habra otras formas ms adecuadas, pero
es slo un ejemplo.
Ejemplo:
Public Function Provincia(ByVal Codigo As Long) As String
If Codigo < 1 Or Codigo > 52 Then
Provincia = "Cdigo de provincia incorrecto"
ElseIf Codigo = 1 Then
Provincia = "lava"
ElseIf Codigo = 8 Then
Provincia = "Barcelona"
ElseIf Codigo = 20 Then
Provincia = "Guipuzcoa"
ElseIf Codigo = 28 Then
Provincia = "Madrid"
ElseIf Codigo = 31 Then
Provincia = "Navarra"
ElseIf Codigo = 31 Then
Provincia = "Navarra"
ElseIf Codigo = 26 Then
Provincia = "La Rioja"
ElseIf Codigo = 48 Then
Provincia = "Vizcaya"
ElseIf Codigo = 50 Then
Provincia = "Zaragoza"
Else
Provincia = "Otra Provincia"
End If
End Function
End If
La Funcin IIf
Es una funcin similar a la estructura If . . Then . . Else
Devuelve uno de entre dos valores, en funcin del resultado de una expresin:
Su sintaxis es
IIf(expresin, ValorTrue , ValorFalse)
Se evala la expresin y si es True, devuelve ValorTrue; caso contrario devuelve
ValorFalse.
Por ejemplo
Public Function EsPar(ByVal Numero As Long) As Boolean
EsPar = IIf(Numero Mod 2 = 0, True, False)
End Function
[Case Else
[instrucciones_else]]
End Select
expresin_prueba debe ser una variable, o expresin que devuelva una cadena un
nmero.
lista_expresion son una serie de valores, del tipo que da expresin_prueba.
Si expresin_prueba coincide con alguno de los valores de lista_expresion, se
ejecutarn las instrucciones que existen a continuacin, hasta llegar al siguiente Case,
End Select.
A partir de este punto se saldra de la estructura y se seguira con el siguiente cdigo.
Si no se cumpliera la condicin de ninguno de los Case lista_expresion, y hubiera
un Case Else, se ejecutaran las lneas de cdigo contenido a partir de Case Else.
Ejemplo de las expresiones que pueden estar contenidas en las lista_expresion:
Case 3
Case 3, 5, 6, 7
Case 1 To 8, 0, -5
Case Is < 8
Case Is > 3
Case Is >= lngDias
Case "A", "B", "C", "Z"
Voy a poner un ejemplo para clarificarlo:
Supongamos que queremos crear una funcin que nos cualifique el tipo de los pagars de
los clientes en funcin del tiempo que queda hasta su cobro.
La funcin recibir como parmetro la fecha del vencimiento. Si la fecha es anterior al da de
hoy, deber devolver la cadena Pago vencido. Si es del da de hoy Vence hoy, si
quedan entre 1 y 3 das Cobro inmediato, si menos de 31 das Corto Plazo si son
menos de 181 das Medio Plazo y si es mayor Largo Plazo
La funcin podra ser sta:
Public Function TipoVencimiento( _
Vencimiento As Date _
) As String
Dim lngDias As Long
' Date devuelve la fecha de hoy
lngDias = Vencimiento - Date
Case 4 To 30 ' De 4 a 30
TipoVencimiento = "Corto Plazo"
Case 31 To 180 ' De 31 a 180
TipoVencimiento = "Medio Plazo"
Case Else ' Si ninguno de los anteriores
TipoVencimiento = "Largo Plazo"
End Select
End Function
Aqu mostramos algunas de las posibilidades de elaboracin de la lista_expresion.
Case Is < 0
Is se puede utilizar junto con operadores de comparacin.
Estos operadores son
= Igual a
< Menor que
<= Menor igual que
> Mayor que
>= Mayor igual que
<> Diferente que
Se pueden poner diferentes expresiones separadas por comas
Esta lnea sera vlida:
Case Is < 0, 4, 8, is > 10
Se ejecutaran las lineas correspondientes al Case para cualquier valor que sea menor que
0, mayor que 10 si su valor es 4 u 8.
Este sistema tambin puede aplicarse a cadenas de texto.
Supongamos que queremos clasificar a los alumnos de un colegio en 4 grupos, en funcin
de su apellido.
Aqullos cuyo apellido empiece por una letra comprendida entre la A y la D pertenecern al
grupo 1, entre la E y la L al grupo 2, entre la M y la P al 3 y entre la Q y la Z al 4.
La funcin sera
Public Function Grupo( _
ByVal Apellido As String _
) As Long
Apellido = Trim(UCase(Apellido))
Select Case Apellido
Case Is < "E"
Grupo = 1
Case "E" To "LZZZZ"
Grupo = 2
Case "M" To "PZZZZ"
Grupo = 3
Case "Q" To "TZZZZ"
Grupo = 3
Case Is >= "U"
Grupo = 4
End Select
End Function
Nota:
Hemos utilizado, como auxiliares dos funciones de VBA. En concreto en la lnea
Apellido = Trim(UCase(Apellido))
Primero se aplica la funcin Ucase sobre el parmetro Apellido y despus la funcin Trim.
Ucase convierte las minsculas que pueda haber en Apellido a Maysculas
Trim elimina los posibles espacios en blanco que pudiera haber a la izquierda y a la
derecha de Apellido.
En concreto, si Apellido contuviera el valor " Olaz ", lo convertira a "OLAZ".
La funcin Grupo(" Olaz "), devolvera el valor 3.
Al ser "OLAZ" mayor que "M" y menor que "PZZZZ" ejecutara la lnea
Grupo = 3
Nota:
Para que dos cadenas sean iguales, deben tener los mismos caracteres.
Una cadena A es menor que otra B si aplicando los criterios de ordenacin, A estara antes
que B. En este caso podemos decir que B es mayor que A porque si estuvieran en una lista
ordenada alfabticamente, B estara despus que A.
El definir si "OLAZ" es menor que "Olaz" es igual, se especifica en la primera lnea que
aparece en el mdulo.
Option Compare Database|Text|Binary
A continuacin de Compare podemos poner Database, Text Binary
Si aparece Text, Olaz sera igual a OLAZ
Si aparece Binary Olaz sera mayor que OLAZ
Si aparece Database utilizara el criterio de ordenacin por defecto de la base de datos.
Option Compare Database es especfico de Access.
Por ejemplo Visual Basic no lo contempla.
La expresin CadenaInferior To CadenaSuperior se utiliza de forma similar a
ValorNumericoInferior To ValorNumericoSuperior
En la funcin TipoVencimiento tenamos la siguiente lnea
Case 1, 2, 3 ' De 1 a 3
Esto haca que si la diferencia de das fuese de 1, 2 3 se ejecutara el cdigo de ese Case.
Esta forma de generar una lista de comparaciones tambin se puede realizar con caracteres
de texto. Sera vlido, por ejemplo Case "A","B","C"
Estructuras de Bucle.
Las Instrucciones For - - - Next
Supongamos que tenemos que construir una funcin que nos devuelva el Factorial de un
nmero.
Os recuerdo que Factorial de n es igual a 1*2*3* . . . *(n-1)*n, para n entero y
mayor que cero.
Adicionalmente se define que Factorial de Cero tiene el valor 1.
Cmo se hara esta funcin:
Public Function Factorial(ByVal n As Integer) As Long
Dim i As Integer
Factorial = 1
For i = 1 To n
Factorial = Factorial * i
Next i
End Function
Efectivamente funciona, ya que Factorial devuelve resultados correctos para valores de
n entre 0 y 12.
Pero esta funcin no sera operativa para un uso profesional ya que tiene una serie de
fallos. Por ejemplo, si hacemos Factorial(-4) devuelve el valor 1, lo que no es
correcto, ya que no existe el factorial de un nmero negativo. Igualmente podemos pasarle
valores superiores a 12, que nos daran un error de desbordamiento, ya que 13! Supera el
alcance de los nmeros Long. Probad haciendo en la ventana inmediato
? Factorial(13).
Observad este cdigo:
Public Function Factorial(ByVal n As Integer) As Long
Dim i As Integer
Select Case n
Case Is < 0
MsgBox "No existe el factorial de un nmero negativo", _
vbCritical + vbOKOnly, _
" Error en la funcin Factorial"
Exit Function
Case 0
Factorial = 1
Exit Function
Case 1 To 12
Factorial = 1
For i = 1 To n
Factorial = Factorial * i
Comencemos a programar con VBA - Access
09 - 10
Next i
Case Else
MsgBox "Nmero demasiado grande", _
vbCritical + vbOKOnly, _
" Error en la funcin Factorial"
Exit Function
End Select
End Function
He puesto una serie de sentencias Case para filtrar los valores que daran resultados
incorrectos, o produciran error, avisndole al usuario de que ha tratado de utilizar la funcin
Factorial con unos valores fuera de su rango vlido.
As el mayor valor lo obtenemos de
12! = 479.001.600
El tener como rango vlido del 0 a 12 no resulta un poco corto ?.
Dependiendo para qu, s.
Supongamos que estemos programando un sistema estadstico que hace uso de clculos
combinatorios grandes. Probablemente esta funcin no servira, aunque se podran usar
trucos para saltarse sus limitaciones.
El problema surge porque el resultado supera el rango de los nmeros Long, pero en el
Captulo 5, y tambin en el Apndice 01, vemos que existen dos tipos de nmeros que
superan esa limitacin. Uno es el de los Currency y el otro el de los Decimal.
Vamos a cambiar el cdigo para trabajar con Currency:
Public Function FactorialCurrency(ByVal n As Integer) As
Currency
Dim i As Integer
Select Case n
Case Is < 0
MsgBox "No existe el Factorial de un nmero negativo", _
vbCritical + vbOKOnly, _
" Error en la funcin FactorialCurrency"
Exit Function
Case 0
FactorialCurrency = 1
Exit Function
Case 1 To 17
FactorialCurrency = 1
For i = 1 To n
FactorialCurrency = FactorialCurrency * i
Next i
Case Else
MsgBox "Nmero demasiado grande", _
vbCritical + vbOKOnly, _
Select Case n
Case Is < 0
MsgBox "No existe el factorial de un nmero negativo", _
vbCritical + vbOKOnly, _
" Error en la funcin Resultado"
Exit Function
Case 0
FactorialDecimal = 1
Exit Function
Case 1 To 27
Resultado = 1
For i = 1 To n
Resultado = Resultado * CDec(i)
Next i
Case Else
MsgBox "Nmero demasiado grande", _
vbCritical + vbOKOnly, _
" Error en la funcin FactorialDecimal"
Exit Function
End Select
Comencemos a programar con VBA - Access
09 - 12
FactorialDecimal = Resultado
End Function
Los bucles del tipo For - - Next se pueden anidar (Poner unos dentro de otros).
Por ejemplo, supongamos que tenemos que generar un procedimiento que nos imprima las
tablas de multiplicar que van del 1 al 10.
Public Sub TablasDeMultiplicar()
Dim n As Integer, m As Integer
For n = 1 To 10
Debug.Print "-----------"
For m = 1 To 10
Debug.Print n & " x " & m & " = " & n * m
Next m
Next n
End Sub
Para cada valor que tomara n, ejecutara el bucle completo de For m --- Next m.
imprimiendo en la ventana Inmediato los resultados de las tablas
- - -
- - -
9 x 8 = 72
9 x 9 = 81
9 x 10 = 90
-----------
10 x 1 = 10
10 x 2 = 20
10 x 3 = 30
10 x 4 = 40
10 x 5 = 50
10 x 6 = 60
10 x 7 = 70
10 x 8 = 80
10 x 9 = 90
10 x 10 = 100
En los ejemplos anteriores hemos utilizado la estructura ms tpica de VBA para la creacin
de Bucles.
La instruccin For m --- Next m., repite el cdigo contenido entre la lnea que contiene
la palabra For y la lnea que contiene a su correspondiente Next.
[email protected] Eduardo Olaz
Entrega 09 Estructuras de Control 09 - 13
Su sintaxis es
For contador = principio To fin [Step incremento]
[instrucciones]
[Exit For]
[instrucciones]
Next [contador]
Contador es una variable numrica que ir tomando sucesivos valores, con incrementos
decrementos iguales al valor de incremento.
Si no se pusiera el valor incremento, contador ira creciendo en una unidad cada
vuelta.
El cdigo se ir repitiendo hasta que contador tome el valor de fin, se encuentre con la
instruccin Exit For.
En el siguiente ejemplo, el bucle For Next se ejecutar hasta que lngSuma sea mayor
que 100, momento en que saldr del bucle o se imprima el nmero de impares especificado
en el parmetro Numero. Si el parmetro Numero fuese cero menor, se sale
directamente del procedimiento sin ejecutarse el bucle.
Public Sub ImprimeImpares(Numero As Long)
Dim i As Long
Dim lngImpar As Long
Dim lngSuma As Long
If Numero < 1 Then
Exit Sub
End If
For i = 1 To Numero
lngImpar = 2 * i - 1
lngSuma = lngSuma + lngImpar
If lngSuma > 100 Then
Exit For
End If
Debug.Print i & " - " & lngImpar & " - " & lngSuma
Next i
End Sub
VBA - Access
Entrega 10
Estructuras de Control II
Eduardo Olaz
10 - 2
intFichero = FreeFile
Open Fichero For Input As #intFichero
While Not EOF(intFichero)
Line Input #intFichero, strLinea
Debug.Print strLinea
Wend
End Sub
ste es el clsico cdigo para leer el contenido de un fichero secuencial.
Vamos a fijarnos en la estructura While - - Wend.
Traducido a lenguaje humano quiere decir:
Mientras no llegues al final del fichero #intFichero
Lee la lnea del fichero, hasta que encuentres un retorno de carro y asgnaselo a la
variable strLinea.
Imprime el contenido de la variable en la ventana inmediato
Vuelve a la lnea de While para repetir el proceso
Comencemos a programar con VBA - Access
10 - 4
En VBA hay una funcin que calcula la raz cuadrada directamente: Sqr(Nmero).
Es equivalente a Nmero^0.5
Habiendo escrito la funcin EsPrimo, en un mdulo estndar, vamos a crear un formulario
en el que introduciendo un nmero en un cuadro de texto, tras pulsar un botn, nos diga si
es primo no.
Cerramos el editor de cdigo y creamos un nuevo formulario y lo ponemos en Vista Diseo.
Aadimos al formulario una etiqueta, un cuadro de texto y un botn.
Nombres aplicados a los controles:
Etiqueta lblMensaje
Cuadro de texto txtNumero
Etiqueta del cuadro de texto lblNumero
Botn cmdPrimo
Ajustamos algunas de las propiedades del formulario, por ejemplo para quitar los
separadores de registro, botones, etc.
Ya que va a ser un formulario con muy pocos controles, ponemos los textos algo mayores
que lo normal, e incluso podemos jugar con los colores.
A m me ha quedado as
Para que el formulario tenga este aspecto, he modificado algunas de sus propiedades:
Propiedad Valor
Selectores de registro No
Botones de desplazamiento No
Separadores de registro No
Estilo de los bordes Dilogo
Vamos a hacer ahora que tras introducir un nmero en el cuadro de texto, y presionar el
botn, nos diga en la etiqueta si el nmero es primo.
Volvemos a la hoja de propiedades y seleccionamos Eventos.
Teniendo seleccionado el botn, activamos el evento Al hacer clic, pulsamos en el
botoncito que aparece con los tres puntos y seleccionamos Generador de cdigo, y a
continuacin Aceptar.
Vamos a escribir el cdigo:
Os recuerdo que detrs de la comilla simple lo que se escriba es un comentario
(lneas en verde). Estas lneas VBA las ignora, sirviendo slo como ayuda al usuario.
Tambin os recuerdo que el espacio en blanco seguido de la barra inferior, al final de
una lnea, hace que la lnea siguiente se considere como la misma lnea.
El dividir as las lneas lo hago como ayuda para la composicin de este texto y para
ordenar el cdigo.
Private Sub cmdPrimo_Click()
Dim strNumero As String
Dim lngNumero As Long
A continuacin asigna el contenido del cuadro de texto txtNumero, procesado primero con
la funcin Nz, que devuelve una cadena vaca si tiene el valor Null, y a continuacin le
quita los posibles espacios en blanco de los extremos mediante la funcin Trim.
Seguidamente pasa por la primera estructura de decisin If, controlando si la cadena
strNumero es de tipo numrico.
Si no lo fuera muestra en la etiqueta el mensaje "No ha introducido un nmero".
Si lo fuera, primero comprueba si la expresin numrica de strNumero est entre 1 y
214748364, rango de valores vlidos en el rango de los Long, para la funcin EsPrimo.
Si no fuera as, muestra el mensaje " El nmero est fuera de rango", lleva el
cursor al control txtNumero y sale del procedimiento.
Supongamos que el contenido de strNumero ha logrado pasar todos estos controles.
Mediante la funcin Val(strNumero) asigna el valor a la variable lngNumero.
Como ya no vamos a utilizar la cadena strNumero para ms clculos, para mostrar el
nmero, le asignamos el resultado de la funcin Format(lngNumero, "#,##0").
Con esta utilizacin, la funcin Format devuelve una cadena formada por el nmero con
los separadores de miles.
La funcin Format tiene un amplio abanico de posibilidades en la conversin de
nmeros y fechas a cadenas de texto.
Merece por s misma un tratamiento ms extenso.
Se lo daremos en una prxima entrega.
El siguiente paso es comprobar si el nmero lngNumero es primo, utilizando la funcin
EsPrimo que escribimos anteriormente.
Si lo fuera, escribiramos en la etiqueta "El nmero " seguido del contenido de la
cadena strNumero, y el texto " es primo".
Si no lo fuera, escribiramos lo mismo, pero indicando " no es primo".
Terminado todo esto llevamos el cursor al cuadro de texto txtNumero mediante su
mtodo SetFocus.
Todo muy bien.
El cliente est contento y el programa responde a lo que nos peda, pero
Casi siempre hay un pero
Viendo lo efectivos y rpidos que hemos sido, al cliente se le ocurre que sera muy
interesante poner dos botoncitos que al presionarlos, dado un nmero cualquiera,
nos muestre el nmero primo inmediatamente mayor menor al nmero que hemos
mostrado.
-Tiene que ser fcil, total ya has hecho lo ms importante y ste es un pequeo
detalle adicional, que no te costar prcticamente nada de tiempo y supongo que no
tendrs problemas para hacrmelo sin aumentar el importe presupuestado
A alguno le suena esta conversacin?.
Y adems, aunque ya has terminado lo que te pedan, como hay que aadirle este pequeo
detalle no te pagan hasta que no lo termines
Decido aadir dos botones con unas flechas en su interior.
Al primero, con una flecha hacia arriba lo llamo cmdPrimoSiguiente, y al segundo, con
una flecha hacia abajo, cmdPrimoAnterior.
End Sub
En el cdigo anterior podemos ver algunas cosas interesantes.
Lo primero que nos puede llamar la atencin es la sentencia:
On Error Resume Next
Esta es la forma ms bsica de efectuar un control de los errores que se puedan originar
durante la ejecucin de un programa en VBA.
Simplemente se le est indicando a VBA que si se produjera un error en algn punto del
procedimiento lo ignore y vaya a la siguiente sentencia del cdigo.
El ignorar los errores no es una verdadera forma de control.
Aprenderemos en otra entrega diferentes formas de manejar los posibles errores, ya
sean generados por el cdigo, por datos inadecuados de los usuarios, etc.
Ms adelante nos encontramos con una sentencia If que evala una expresin doble
If lngNumero < 2147483647# And lngNumero >= 0 Then
Para que esta expresin sea cierta, lo tienen que ser a l vez las dos expresiones unidas por
And; es decir lngNumero tiene que ser menor que 2147483647 y simultneamente
tiene que ser mayor igual que 0.
Cuando varias expresiones estn unidas por el Operador Lgico And, para que la expresin
total sea cierta, es necesario que lo sean cada una de esas expresiones. Con que haya una
falsa, la expresin total ser falsa.
Por el contrario, cuando varias expresiones estn unidas por el Operador Lgico Or, para
que la expresin total sea cierta, es suficiente con que lo sea una cualquiera de las
expresiones que la forman.
A continuacin nos encontramos con otro Operador, es el operador negacin Not.
Do While Not blnPrimo
Not hace que la expresin lgica que le sigue cambie su valor.
As si blnPrimo contiene el valor True
Not blnPrimo
devolver el valor False.
La expresin equivale a:
Mientras blnPrimo no sea cierto
Que es equivalente a
Mientras blnPrimo sea falso.
Con ello se ejecutar el cdigo contenido entre la lnea de Do y la lnea del Loop.
Cuando lngNumero sea primo, la funcin EsPrimo asignar True a blnPrimo, con lo
que se saldr del bucle, pondr la cadena de texto del nmero txtNumero en el cuadro de
texto y ejecutar el procedimiento cmdPrimo_Click, como si se hubiera presionado en el
botn [cmdPrimo].
Si el valor de lngNumero no hubiera cumplido con el rango de valores, pone un 1 en el
cuadro de texto txtNumero, y ejecuta el procedimiento cmdPrimo_Click.
En el procedimiento que maneja la pulsacin de la tecla [cmdPrimoAnterior] aunque tiene
una estructura semejante, se introducen unos cambios que considero interesante remarcar.
Comencemos a programar con VBA - Access
10 - 12
Do Until EsPrimo(lngNumero)
lngNumero = lngNumero - 1
Loop
txtNumero = CStr(lngNumero)
cmdPrimo_Click
Else
txtNumero = "2147483647"
cmdPrimo_Click
End If
Else
txtNumero = "2147483647"
cmdPrimo_Click
End If
End Sub
En primer lugar utilizamos una estructura del tipo Do Until, en vez de Do While.
Adems, como condicin no utiliza una variable como en el caso anterior, sino que lo
compara directamente con el valor devuelto por la funcin EsPrimo, que devuelve True
False segn sea el caso:
Do Until EsPrimo(lngNumero)
Con esto nos evitamos utilizar una
variable y una sentencia adicional.
Adems el cdigo resulta algo ms claro..
En este caso, si la variable no supera los
filtros, pone el valor "2147483647" en
el cuadro de texto.
VBA - Access
Entrega 11
Gestin de errores
Eduardo Olaz
11 - 2
Errores
La gestin de los errores en procedimientos
A la hora de utilizar el cdigo de un mdulo, hay dos tiempos
Tiempo de Diseo.
Tiempo de Ejecucin.
El tiempo de diseo transcurre mientras estamos modificando el contenido del cdigo de
un mdulo, sea del tipo que sea, o cuando estamos cambiando las propiedades de
controles, formularios o informes, en la llamada Vista Diseo, ya sea directamente
mediante ejecucin de cdigo.
Esto a ms de uno le sorprender:
Access permite crear mediante cdigo, formularios por ejemplo utilizando el mtodo
CreateForm, que devuelve una referencia a un nuevo formulario, tambin permite
aadirle controles mediante el mtodo CreateControl , e incluso asociarle un
mdulo, escribiendo dinmicamente todo su contenido. Para esto ltimo tendramos
que crear una referencia al objeto Module del formulario, y para insertarle el cdigo
utilizar su mtodo InsertText.
De forma semejante existe el mtodo CreateReport para la creacin dinmica de
informes.
Si queremos usarlos posteriormente deberemos guardarlos, por ejemplo con el
mtodo Save del objeto DoCmd.
El tiempo de ejecucin transcurre cuando hemos creado una instancia de un objeto,
formulario, informe, clase o hemos llamado a un procedimiento de un mdulo estndar.
En el lenguaje normal podramos decir que estamos en tiempo de ejecucin cuando
estamos ejecutando los objetos o el cdigo de Access.
Errores en Tiempo de Diseo
En Tiempo de Diseo podemos cometer una serie de errores, a la hora de escribir el cdigo.
Muchos de estos errores sern detectados inmediatamente por el editor de Access.
Cuando escribimos una lnea de cdigo, Access realiza un anlisis del texto que estamos
escribiendo. En este proceso se realiza fundamentalmente su anlisis sintctico.
Tambin comprueba si hay sentencias incompletas, por ejemplo If sin Then.
Si encuentra una expresin errnea lanza un mensaje de Error de compilacin e incluso
aporta una cierta informacin que nos puede orientar sobre el origen del error.
Instrucciones de salto.
La Instruccin Goto
Cuando el cdigo se encuentra con esta sentencia realiza un salto incondicional.
Su sintaxis tiene esta estructura:
GoTo lnea
Lnea puede ser una Etiqueta de lnea un nmero de lnea.
Observa este cdigo
Public Sub PruebaGoto()
GoTo Etiqueta_01
Debug.Print "No he saltado a Etiqueta_01"
Etiqueta_01:
Debug.Print "*** Salto a la Etiqueta_01 ***"
GoTo 10
Debug.Print "No he saltado a 10"
10 Debug.Print "*** Salto a la lnea 10 ***"
End Sub
Si ejecutamos el cdigo nos imprime en la ventana Inmediato
*** Salto a la Etiqueta_01 ***
*** Salto a la lnea 10 ***
Una etiqueta es una palabra que comience con una letra y termine con los dos puntos.
Un nmero de lnea es un nmero situado al principio de la lnea.
La utilizacin de nmeros de lnea proviene de la poca de Basic, cuando las lneas de
cdigo deban ir precedidas de un nmero que las identificara.
GoTo Etiqueta_01
Salta a la etiqueta sin ejecutar la lnea intermedia.
GoTo 10
Salta a la lnea precedida por el nmero 10.
Gosub - - Return
Es otra instruccin de salto, de la cual slo voy a comentar que existe por compatibilidad con
las antiguas versiones de Basic.
Si alguien quiere ms informacin puede acudir a la ayuda de VBA.
Personalmente desaconsejo completamente su uso, ya que en VBA existen alternativas ms
eficientes y claras.
La utilizacin de Goto y Gosub se desaconseja ya que pueden convertir el cdigo en una
sucesin de saltos de canguro imposible de seguir de una forma coherente.
Capturar Errores
Ya hemos comentado que durante la ejecucin de una aplicacin pueden producirse
diversos tipos de errores, como rangos de valores no vlidos, divisin por cero,
manipulacin de un elemento de una matriz, coleccin, o un fichero que no existan, etc.
Si prevemos que en un procedimiento pudiera producirse un error, para poder gestionarlo,
pondremos en su cabecera o en un punto anterior al lugar donde el error se pudiera generar,
la sentencia:
On error Goto Etiqueta
Si un procedimiento incluye esta lnea, y en tiempo de ejecucin, en una lnea posterior a
sta, se produjera un error, la ejecucin del cdigo saltar a la lnea que incluye esa
etiqueta, y mediante el objeto Err podremos controlar el error.
El objeto Err
Este objeto contiene la informacin de los errores que se producen en tiempo de ejecucin.
Cuando se produce un error, el objeto o el procedimiento que lo ha generado puede asignar
datos a sus propiedades.
Las propiedades ms importantes, o las que en este nivel nos interesan ms, son:
Number
Description
Source
Hay otras propiedades que, de momento no vamos a analizar, como son
HelpContext HelpFile LastDLLError
La propiedad Number contiene un nmero que sirve como identificador del error.
Description incluye una cadena de texto que nos sirve para interpretar las
caractersticas del error.
Source contiene informacin sobre el proyecto u objeto que ha generado el error.
Tomando como modelo el cdigo que generaba un error de Divisin por cero, vamos a
hacer otro procedimiento que lo controle:
Public Sub ErrorControlado()
On Error GoTo HayError
Dim n As Byte
n = 0
Debug.Print 4 / n
Salir:
Exit Sub
HayError:
Debug.Print "Error n " & Err.Number
Debug.Print Err.Description
Debug.Print Err.Source
Resume Salir
End Sub
El resultado de la ejecucin de este cdigo es:
Error n 11
Divisin por cero
Entrega11
Para usar las propiedades del objeto Err, se utiliza la misma sintaxis que para otros objetos
NombreObjeto.Propiedad
La instruccin Resume
Hace que la ejecucin del cdigo contine en una lnea determinada, tras gestionar un error.
En el ejemplo anterior Resume Salir hace que el cdigo vaya a la lnea marcada con la
etiqueta Salir:
La ejecucin de
Resume Salir
har que se salga del procedimiento.
Despus de la palabra Resume, puede ponerse una etiqueta un nmero de lnea.
En ambos casos se producir una salto hasta la lnea especificada.
Si se pusiera
Resume Resume 0
Si el error se hubiera producido en el procedimiento que contiene el controlador de errores,
la ejecucin contina en la instruccin que lo caus.
Si el error se produjera en un procedimiento llamado, la ejecucin continuar en la
instruccin para el control de errores desde la cual se llam al procedimiento que contiene la
rutina de gestin de errores..
Si se hubiera escrito
Resume Next
Se ejecutar la lnea siguiente a aqulla en la que se produjo el error se llam al
procedimiento para la gestin de errores.
Resume slo se puede usar en una rutina de gestin de errores.
Vamos a ver cmo manejan las excepciones los asistentes de Access.
Creamos un nuevo formulario mediante [Nuevo] - [Vista Diseo]. Con ello se abre un
nuevo formulario en Vista Diseo, sin estar ligado a ningn origen de datos.
Si no tuviramos visible la barra de herramientas, vamos a activarla, mediante la opcin de
men [Ver] [Cuadro de herramientas].
En esta barra, si no estuviese activado, activaremos el botn [Asistentes
para controles]. En este grfico ejemplo el botn est desactivado
Una vez activado el botn de los asistentes, al seleccionar un control, Access generar
cdigo por nosotros, cdigo que se ejecutar con alguno de los eventos del control.
Ahora vamos a poner un botn que servir para cerrar el formulario cuando se presione
sobre l.
Seleccionamos en la barra de herramientas el [Botn de comando] y lo colocamos en el
formulario, pinchando sobre l y marcando, sin soltar el botn izquierdo, el rectngulo que
va a ocupar el botn.
Tras hacer esto, se nos abre la ventana del Asistente para [Botones de comando].
Comencemos a programar con VBA - Access
11 - 8
En la parte de la izquierda nos muestra un ejemplo de los iconos que se podran poner en el
botn.
DoCmd.Close
Exit_cmdSalir_Click:
Exit Sub
Err_cmdSalir_Click:
MsgBox Err.Description
Resume Exit_cmdSalir_Click
End Sub
Lo primero que hace es utilizar On Error GoTo Err_cmdSalir_Click ; con ello si se
produjera algn error saltar a la lnea marcada con Err_cmdSalir_Click:
Esta es la forma como los asistentes de Access suelen nombrar las etiquetas que sealan el
comienzo del cdigo de Gestin de Errores Err_NombreDelProcedimiento:
A continuacin nos encontramos con que se ejecuta el mtodo Close del objeto DoCmd.
El objeto DoCmd es un objeto especial de Access. Contiene un gran nmero de mtodos
para ejecutar muchas de las tareas habituales con los objetos de Access.
A gran parte de estos mtodos se les puede pasar una serie de argumentos.
Por sus amplias posibilidades, DoCmd merece un captulo aparte. Lo desarrollaremos en
prximas entregas.
Basta decir que en este caso, al llamar al mtodo Close sin pasarle ningn argumento,
DoCmd cierra la ventana activa y como sta es el formulario del botn, al pulsarlo cierra el
formulario, que es lo que queramos conseguir.
Si no ha habido ningn problema, la ejecucin del cdigo se encuentra con la etiqueta que
marca el punto a partir del cual se sale del procedimiento. Como aclaracin, una etiqueta no
ejecuta ninguna accin, slo indica dnde comienza un segmento de cdigo. En nuestro
caso, a partir de este punto nos encontramos con la lnea Exit Sub que nos hace salir
del procedimiento cmdSalir_Click.
Despus de esta ltima lnea comienza el segmento de cdigo que controla cualquier error
en tiempo de ejecucin que se pudiera originar dentro del procedimiento.
Primero, mediante un cuadro de mensaje, nos muestra el texto contenido en la propiedad
Descripcin del objeto Err.
A continuacin, mediante Resume Exit_cmdSalir_Click hace que salte el cdigo a la
etiqueta que marca la salida del procedimiento.
Una puntualizacin: Resume, adems de dar la orden de que el cdigo se siga ejecutando
desde un determinado punto del procedimiento, pone a cero las propiedades del objeto
Err, lo que equivale a hacer que desaparezca el error.
Como hemos visto, cuando usamos un asistente para controles de Access, en el cdigo
generado se suele colocar un segmento para la gestin de errores.
Este cdigo escrito por Access lo podemos cambiar; por ejemplo podramos sustituir
Exit_cmdSalir_Click por Salir, Err_NombreDelProcedimiento por
hayError, e incluso lo podramos quitar, si estuviramos seguros de que nunca se podra
llegar a producir un error o ya tuviramos desarrollado nuestro propio sistema para la
gestin de errores.
Gestionando errores
Supongamos que nos han encargado un programa para visualizar en un formulario el
contenido, en formato texto, de los ficheros que seleccionemos.
Para especificar el fichero que se va a visualizar nos piden que su nombre, incluida su ruta,
se escriba en un cuadro de texto.
Tras esto, y presionar un botn, su contenido se mostrar en un segundo cuadro de texto.
Se decide seleccionar un cuadro de texto como soporte, con el fin de que se puedan
seleccionar y copiar segmentos del texto del contenido de los ficheros.
Debo aclarar que no todo el contenido de un fichero cualquiera se podr mostrar en
un cuadro de texto. Si el fichero es de tipo Binario, grficos, ficheros exe
multimedia, habr caracteres que no se muestren que tengan secuencias
ininteligibles.
Como ya habamos escrito previamente un procedimiento para mostrar el contenido de
ficheros (MuestraFichero del captulo anterior) vamos a aprovecharlo, con algunas
modificaciones para adaptarlo a los nuevos requerimientos.
El nuevo procedimiento exigir que se le pase como parmetro un cuadro de texto; en este
caso con nombre Pizarra, que ser donde se ir escribiendo el contenido del fichero
mientras se vaya leyendo.
Adems le aadiremos un control de errores, ya que podra ocurrir que no se pudiera abrir el
fichero por no existir, o porque estuviera abierto en modo exclusivo por algn usuario.
Public Sub MuestraFichero( _
ByVal Fichero As String, _
ByRef Pizarra As TextBox)
On Error GoTo ProducidoError
Dim intFichero As Integer
Dim strLinea As String
intFichero = FreeFile
Open Fichero For Input As #intFichero
While Not EOF(intFichero)
Line Input #intFichero, strLinea
Pizarra.Value = Pizarra.Value & strLinea
Wend
Salir:
Exit Sub
ProducidoError:
MsgBox "Se ha producido el error " & Err.Number, _
vbCritical + vbOKOnly, _
"Error en el procedimiento MuestraFichero()"
[email protected] Eduardo Olaz
Entrega 11 Gestin de errores 11 - 11
Pizarra.Value = ""
Resume Salir
End Sub
Creamos un nuevo formulario y le aadimos los siguientes elementos
Control Nombre
Cuadro de texto txtFichero
Cuadro de texto txtContenido
Botn cmdVerFichero
El cuadro de texto txtFichero servir para introducir el nombre completo del fichero a
visualizar.
En txtContenido mostraremos el contenido del fichero.
El botn cmdVerFichero activar el procedimiento que sirve para mostrar el contenido
del fichero. La llamada al procedimiento lo colocaremos en el evento Al hacer clic del botn
cmdVerFichero.
Usaremos el procedimiento MuestraFichero al que le pasaremos como parmetro el
control txtContenido.
En el cuadro de texto txtContenido activamos la Barra Vertical en la propiedad Barras
de Desplazamiento.
En el evento Al hacer clic del botn escribiremos lo siguiente:
Private Sub cmdVerFichero_Click()
txtContenido = ""
MuestraFichero txtFichero, txtContenido
End Sub
Lo que hace el procedimiento es:
Limpia el posible contenido de txtContenido asignndole una cadena vaca.
Llama al procedimiento MuestraFichero Pasndole como parmetros el nombre del
fichero que queremos abrir, contenido en el control txtFichero, y el control en el que
queremos mostrar los datos txtContenido.
En el ejemplo se muestra el contenido del fichero CodigosDeBarras.ini ubicado en la carpeta
Windows.
VBA - Access
Entrega 12
Trabajando con
procedimientos
Eduardo Olaz
12 - 2
Procedimientos
Hemos hablado sobre diversos aspectos de los procedimientos Function y Sub.
Relacionados con ellos, he dejado en el tintero completar la explicacin de una serie de
temas que vamos a tratar en esta entrega.
Entre ellos cabe destacar
Declaracin de variables como Static, a nivel de procedimiento
Paso de parmetros Por Valor y Por Referencia, ByVal y ByRef
Parmetros Opcionales Optional
Resolucin de problemas mediante Procedimientos Recursivos e Iterativos.
Parmetros Tipo Matriz mediante ParamArray.
Paso de parmetros Con Nombre mediante el operador de asignacin :=
Constantes Enumeradas Enum ... End Enum
Cuadros de dilogo predefinidos para intercambiar informacin entre VBA y el
usuario MsgBox e InputBox
Variables Static
A nivel de procedimiento hemos comentado que una variable puede declararse con Dim.
No puede declararse ni como Public ni como Private.
Declarada con Dim, cuando acaba el procedimiento, el contenido de la variable desaparece,
y la siguiente vez que se llama al procedimiento, tras su declaracin, la variable se reinicia
con el valor por defecto correspondiente a su tipo.
Como aclaracin de esto ltimo, por ejemplo, si tenemos el procedimiento:
Public Sub ValorConDim()
Dim n As Long
n = n + 1
Debug.Print "Valor de n: " & n
End Sub
Cada vez que llamemos al procedimiento ValorConDim imprimir en la ventana Inmediato
Valor de n: 1
Vamos ahora a escribir un nuevo procedimiento muy parecido al anterior
Public Sub ValorConStatic()
Static n As Long
n = n + 1
Debug.Print "Valor de n: " & n
End Sub
Slo cambia el nombre y la declaracin de n que est declarada como Static en vez de
con Dim.
Ahora la primera vez que se ejecuta muestra tambin Valor de n: 1
lngM = 1
lngN = 2
lngO = 2
Vemos que lngM no ha cambiado su valor. Mantiene el valor 1 que se ha pasado al
procedimiento PorValor.
En cambio tanto lngM como lngO han pasado de tener el valor 1 a tomar el valor 2.
Esto es as porque cuando se pasa una variable Por Valor a un procedimiento, se est
haciendo que el procedimiento trabaje con una copia de la variable pasada al procedimiento,
no con la variable misma. Por ello, los cambios que hagamos al valor del parmetro en el
procedimiento, no afectarn a la variable original.
En cambio, si pasamos una variable a un procedimiento, Por Referencia, los cambios que
hagamos en el parmetro se vern reflejados en la variable original.
Tanto el VBA de Access como el VBA de Visual Basic, o de otras aplicaciones, pasan por
defecto los parmetros Por Referencia.
Esto no ocurre con otros programas, como Pascal, C o la plataforma de desarrollo Net, con
programas como VB.Net, y C#, en las que la forma por defecto es Por Valor.
El hecho de que por defecto se pasen los parmetros por referencia puede dar lugar a
errores de cdigo difcilmente detectables. Por ello, y como norma general, recomiendo que
cuando se pase un parmetro se indique siempre si es Por Valor o Por Referencia usando
ByVal o ByRef.
No todo son inconvenientes, el paso de parmetros Por Referencia, permite que un
procedimiento Sub o Function modifiquen varios valores simultneamente.
Supongamos que necesitamos un procedimiento para obtener la potencia n de tres valores
de tipo Long que se pasan como parmetros.
Public Sub ProbarByRef()
Dim lng1 As Long, lng2 As Long, lng3 As Long
Dim lngExponente As Long
lng1 = 2
lng2 = 3
lng3 = 4
lngExponente = 4
' Pasamos por referencia las tres variables
TresPotencias lng1, lng2, lng3, lngExponente
' Las variables lng1, lng2 y lng3 _
han sido elevadas a la potencia 4
Debug.Print "Variable 1 " & lng1
Debug.Print "Variable 2 " & lng2
Debug.Print "Variable 3 " & lng3
End Sub
Parmetros Opcionales
Tanto en los procedimientos Function, como en los Sub podemos definir algunos, e
incluso todos los parmetros como Opcionales.
Qu quiere decir esto?.
- Tan simple como que podemos hacer que la introduccin de su valor en un parmetro
opcional no sea estrictamente necesaria.
Puntualizaciones sobre parmetros opcionales.
Para definir que un parmetro es opcional ponemos delante de cualquier otro posible
modificador, como ByVal ByRef, la palabra reservada Optional.
Si en un procedimiento hay varios parmetros, y uno de ellos est definido como
opcional, los parmetros que le sigan tambin debern estar definidos como
Optional.
Comencemos a programar con VBA - Access
12 - 6
Constantes Enumeradas
En algunos tipos de procedimientos o funciones, vemos que alguno de los parmetros slo
debe tomar un nmero limitado de valores. Sera muy interesante que a la hora de ir
escribiendo un procedimiento, VBA nos fuera sugiriendo los valores vlidos.
Para ayudar a este fin tenemos las Constantes Enumeradas.
Las Constantes Enumeradas son un conjunto de constantes agrupadas en un tipo
enumerador. Los valores que pueden admitir son slo del tipo Long
La forma de construirlas es
[Public | Private] Enum nombre
nombre_miembro [= expresin_constante]
nombre_miembro [= expresin_constante]
. . .
End Enum
Se declaran a nivel del encabezado de un mdulo, pudiendo ser declaradas como
Public o Private. En los mdulos de clase slo pueden declararse como Public
La declaracin comienza opcionalmente indicando primero su alcance a continuacin la
instruccin Enum seguida del nombre del tipo.
En las sucesivas lneas se van aadiendo los nombres de los sucesivos valores,
opcionalmente con su valor correspondiente.
Public Enum Booleano
blFalso
blCierto
End Enum
En este caso blFalso tendra el valor 0 y blCierto tomara el valor 1.
Podramos haber hecho
Public Enum Booleano
blFalso
blCierto = -1
End Enum
Con lo que blFalso tendra el valor 0 y blCierto tomara el valor -1.
Las constantes enumeradas, si no se les asigna un valor, toma el de la constante anterior,
incrementada en 1.
Ya hemos dicho que si a la primera no se le asigna un valor toma el valor 0.
Public Enum DiasSemana
dsLunes = 1
dsMartes
dsMiercoles
dsJueves
dsViernes
dsSabado
dsDomingo
End Enum
En este caso, por ejemplo dsJueves toma el valor 4.
He dicho que a las constantes enumeradas slo se les puede asignar valores Long.
Esto no es del todo cierto. Esto por ejemplo funcionara
Public Enum TipoSexo
tsFemenino = "1"
tsMasculino
End Enum
En esta declaracin tsFemenino tendra el valor numrico 1 y tsMasculino el valor 2.
- Y cmo es posible esto?
- Forma parte de las pequeas incoherencias que tiene Visual Basic heredadas de las
viejas versiones; incoherencias que en teora son para ayudar al usuario, pero que pueden
acabar despistndolo.
End Enum
Como hemos comentado asignar el valor 2 a tsMasculino no sera necesario.
Una vez definidas estas constantes, estn inmediatamente disponibles en la Ayuda
Contextual, como podemos ver en la siguiente imagen, pudindose utilizar como un tipo de
datos ms.
Adems, conforme vayamos desarrollando el cdigo nos mostrar los posibles valores
concretos que podrn tomar los parmetros
Completemos la funcin:
Public Function Tratamiento( _
ByVal Apellido As String, _
Sexo As TipoSexo, _
Optional ByVal Estado As EstadoCivil _
) As String
Si hacemos las pruebas con las diferentes posibilidades veremos que responde a lo
solicitado por la empresa contratante.
Visto el xito, nos piden que tambin creemos una funcin para la lnea de la direccin de
forma que nos ponga:
A la Att. de Don Nombre Apellido1
A la Att. de Doa Nombre Apellido1
Si no existiera el Nombre que pusiera
A la Att. del Sr. Apellido1
A la Att. de la Sta. Apellido1
A la Att. de la Sra. Apellido1
El desarrollo de esta funcin la dejo para el lector.
Para intercambiar informacin entre el usuario y VBA tenemos 2 procedimientos bsicos que
se corresponden a los cuadros de dilogo predefinidos en VBA.
MsgBox
InputBox.
Funcin MsgBox
La funcin MsgBox, muestra un mensaje en un Cuadro de dilogo con determinados
botones, y puede devolver un nmero que identifica el botn pulsado por el usuario.
En este cuadro de dilogo se puede definir el texto de la barra de ttulo, el mensaje
mostrado, un icono que indica el tipo de mensaje y seleccionar botones de los predefinidos
previamente por VBA.
La sintaxis es la siguiente
Es decir
MsgBox mensaje
Por ejemplo
MsgBox "Hola a todos"
Esta instruccin mostrara el siguiente mensaje
He hecho una llamada a MsgBox como si fuera un procedimiento de tipo Sub, no como una
funcin.
En este caso tendra sentido ya que al haber slo un botn, MsgBox slo va a devolver un
valor.
MsgBox admite los parmetros, argumentos Con Nombre. As el cdigo anterior podra
haberse escrito
MsgBox Prompt:= "Hola a todos"
El valor devuelto depender del botn que se haya pulsado.
El parmetro Buttons indica por una parte el tipo de icono que debe mostrar el Cuadro de
dilogo cuadro de Mensaje y los botones que va a contener.
Supongamos que en un formulario hemos puesto un botn que al presionarlo har que se
formatee el disco C:
No hace falta ser muy listo para pensar que existe la posibilidad de una pulsacin accidental.
Para prevenir este caso. antes de lanzar el proceso de formateo, podramos hacer lo
siguiente.
Public Sub Formateo()
Dim strMensaje As String
VbInformation 64
VbExclamation 48
VbQuestion 32
VbCritical 16
La segunda parte del parmetro Buttons hace referencia a los botones que va a mostrar
el cuadro de mensaje.
Sus posibilidades son
Constante Valor Botones
VbOKOnly 0 [ Aceptar ]
VbOKCancel 1 [ Aceptar ] [ Cancelar ]
VbAbortRetryIgnore 2 [ Anular ] [ Reintentar ] [ Ignorar ]
VbYesNoCancel 3 [ S ] [ No ] [Cancelar]
VbYesNo 4 [ S ] [ No ]
VbRetryCancel 5 [ Reintentar ] [ Cancelar ]
VbMsgBoxHelpButton 16384 Aade un botn [ Ayuda ] a los anteriores
Hay una constante adicional VbMsgBoxRight que sirve para hacer que el texto se alinee
a la derecha del mensaje. Su valor es 524288.
Eduardo Olaz
12 - 18
Las dos ltimas constantes que permite usar MsgBox son VbMsgBoxSetForeground y
VbMsgBoxRtlReading.
La primera define la ventana del cuadro como de primer plano, y la segunda afecta a la
visualizacin de los textos en hebreo y rabe que se escriben de Derecha a Izquierda.
Usando las constantes:
Supongamos que queremos mostrar un mensaje con los botones
[ S ] [ No ] [ Cancelar ]
lngBotonesIcono = vbExclamation _
+ vbYesNoCancel _
+ vbDefaultButton3
strTitulo = "Proceso de Votacin"
strMensaje = "Seleccione su voto"
lngRespuesta = MsgBox( _
strMensaje, _
lngBotonesIcono, _
strTitulo)
' Tras pasar el cuadro el botn seleccionado _
a la variable lngRespuesta _
mostramos el voto
' Para ello usamos la funcin TeclaPulsada
strVoto = TeclaPulsada(lngRespuesta)
If lngRespuesta = vbCancel Then
strMensaje = "Has cancelado la votacin"
Else
strMensaje = "Has votado: " _
& TeclaPulsada(lngRespuesta)
End If
MsgBox strMensaje, _
vbInformation, _
"Resultado de la votacin"
End Sub
Funcin InputBox
La funcin InputBox, al igual que MsgBox, puede mostrar un mensaje, pero se diferencia
en que en vez de enviar un nmero Long en funcin de la tecla pulsada, nos pide que
escribamos un texto, en un cuadro de texto. Su contenido ser el dato que devuelva.
La sintaxis de InputBox es:
Parmetro Descripcin
prompt Mensaje del cuadro de dilogo (obligatorio)
title Texto a visualizar en la barra de ttulo
default Valor que devolver, si no introducimos ningn texto
xpos Coordenada X del cuadro (distancia desde el lado izquierdo)
ypos Coordenada Y del cuadro (distancia desde arriba)
helpfile Fichero de ayuda auxiliar
context Contexto del fichero de ayuda
Si no borramos ese texto, por ejemplo al introducir algn texto, se ser el texto que
devolver InputBox.
Al ejecutar ese cdigo podemos comprobar que el cuadro de entrada nos aparece en la
prctica centrado en la pantalla.
InputBox tiene dos parmetros que le permiten ubicar el cuadro en una posicin concreta.
Estos parmetros son Xpos e Ypos.
He modificado el cdigo del procedimiento para que muestre un ttulo y ubicarlo cerca de la
posicin superior izquierda
Public Sub Pregunta()
Dim strRespuesta As String
strRespuesta = InputBox( _
Prompt:="Cmo te llamas?", _
Default:="Introduce aqu tu nombre", _
Title:="Escriba su nombre?", _
XPos:=500, YPos:=500)
MsgBox "Tu nombre es " & strRespuesta, _
vbInformation, " Respuesta suministrada"
End Sub
Las medidas de posicin se dan en Twips.
Un Twip, TWentIeth of a Point equivale a la Vigsima parte de un punto.
El Twip equivale a 1/1440 de pulgada, es decir, 567 twips equivalen a un centmetro.
Esto es vlido para la teora.
En la vida real, las pruebas con diferentes valores son las que nos indicarn qu valores
sern los adecuados a cada caso.
Nota:
Los parmetros helpfile y context hacen referencia a ficheros de ayuda desarrollados
al efecto para la aplicacin.
En este nivel de estudio (bsico), no vamos a abordar el anlisis del desarrollo de ficheros
de ayuda.
Esto no es bice para indicar que, tanto con MsgBox como con InputBox, se puede
hacer referencia a determinados contenidos de ficheros de ayuda desarrollados ex profeso
para la aplicacin, y no slo al fichero en s, sino a una seccin concreta del mismo.
Hay abundante documentacin disponible en Internet al respecto.
Comencemos a programar con VBA - Access
12 - 22
Slo quiero resear el magnfico trabajo desarrollado por mi amigo Guille en su pgina:
http://www.elguille.info/vb/VB_HLP.HTM
VBA - Access
Entrega 13
Funciones de VBA
Eduardo Olaz
13 - 2
Funcin Choose
La funcin Choose, selecciona y devuelve un valor de entre una lista de argumentos.
Sintaxis
Choose(ndice, opcin-1[, opcin-2, ... [, opcin-n]])
Choose busca el argumento situado en la posicin definida por el ndice.
Si ndice fuese menor que 1, mayor que el total de argumentos, devolvera el valor Null.
Si ndice fuese un nmero no entero, lo redondeara al entero ms prximo.
En este ejemplo hemos definido, como constantes enumeradas los posibles puestos de una
hipottica empresa.
Las constantes enumeradas contienen un valor long, por lo que vamos a desarrollar una
funcin que nos devuelva, en base a su valor, la descripcin literal del cargo.
Public Enum Puesto
eoEmpleado = 1
eoTecnico
eoAdministrativo
eoMandoIntermedio
eoComercial
eoDirectivo
eoGerente
End Enum
"Comercial", _
"Directivo", _
"Gerente")
End If
End Function
Si escribimos
PuestoDeTrabajo(eoMandoIntermedio)
Nos devolver
Mando Intermedio
Los argumentos de la funcin Choose, en realidad son un ParamArray, como el que
vimos en la entrega anterior.
Funcin Switch
La funcin Switch, evala una lista de expresiones y devuelve un valor, o una expresin
asociada, a la primera expresin de la lista que sea cierta.
Su sintaxis es
Switch(expresin-1, valor-1[, expresin-2, valor-2 [,
expresin-n,valor-n]])
Supongamos que queremos hacer una funcin que recibiendo como parmetro el nombre
de un pas nos devuelva su capital.
Public Function Capital(ByVal Pais As String) As String
Dim varPais As Variant
' Uso un variant porque si Switch no encuentra _
una expresin cierta, devuelve Null
Pais = Trim(Pais)
varPais = Switch(Pais = "Espaa", "Madrid", _
Pais = "Francia", "Pars", _
Pais = "Portugal", "Lisboa", _
Pais = "Italia", "Roma", _
Len(Pais) = 0, "Tienes que introducir algo", _
IsNumeric(Pais), "Los nmeros no valen")
If IsNull(varPais) Then
Capital = "No conozco la capital de " & Pais
Else
Capital = varPais
End If
End Function
En cada caso devolver:
Capital("Italia") "Roma"
Capital(3.1416) "Los nmeros no valen"
Capital("Japn ") " No conozco la capital de Japn"
Funcin Format
La funcin format recibe una expresin que contiene una cadena, un valor numrico, una
fecha, un valor boleano un valor nulo, y devuelve una cadena formateada de acuerdo a las
instrucciones contenidas en la cadena formato.
Su sintaxis es
End Sub
Nos mostrar en la ventana Inmediato
ESTA CADENA A MAYSCULAS
esta cadena a minsculas
# Derecha#
#Izquierda #
#Cadena Sin Cortar#
#Cadena Sin Cortar#
#Cortada#
# E d u a r d o#
#E d u a r d o #
"Percent" "123456789,01%"
"Scientific" "1,23E+06"
"Yes/No" "S" Si Cero "No"
"True/False" "Verdadero" Si Cero "Falso"
"On/Off" "Activado" Si Cero "Desactivado"
Formato compuesto
Como los cuadros de texto de los formularios de Access, Format admite cadenas de formato
compuesto, es decir formato diferente para distintos tipos de valores.
Estas cadenas pueden constar de 4 secciones, separadas cada una de ellas con un punto y
coma.
En el caso de los nmeros, la primera define cmo se mostrarn los valores Positivos, la
segunda los negativos, la tercera para el cero y la cuarta para el valor nulo.
Format(3.14,"+ #,##0.00;(#,##0.00);Cero pelotero;Valor Nulo")
Devuelve "+ 3,14"
Format(-28,"+ #,##0.00;(#,##0.00);Cero pelotero;Valor Nulo")
Devuelve "(28,00)"
Format(0,"+ #,##0.00;(#,##0.00);Cero pelotero;Valor Nulo")
Devuelve "Cero pelotero"
Format(Null,"+ #,##0.00;(#,##0.00);Cero pelotero;Valor Nulo")
Devuelve " Valor Nulo"
Si alguna de las secciones no estuviera definida, se utilizara para ella el formato positivo.
Format(-28, "#,##0.00 ;;Grati\s;Valor Nulo")
Devuelve "-28,00 "
Format(0, "#,##0.00 ;;Grati\s;Valor Nulo")
Devuelve "Gratis"
Configuracin Regional
La funcin Format nos permite averiguar cul es la Configuracin Regional en algunas de
sus propiedades sin tener, por ejemplo, que acceder al registro de Windows.
Si ejecutamos el procedimiento Configuracin nos mostrar algunos elementos de la
Configuracin Regional.
Public Sub Configuracion()
Dim datPrueba As Date
Dim sngDato As Single
Dim strFormato As String
Dim strSeparador As String
Dim strDato As String
Dim strSeparadorMiles As String
Dim strSeparadorDecimal As String
Comencemos a programar con VBA - Access
13 - 12
datPrueba = #12/31/2000#
strDato = Format(datPrueba, "Short Date")
strSeparador = Mid(strDato, 3, 1)
If Left(strDato, 2) = "31" Then
strFormato = "dd" & strSeparador _
& "mm" & strSeparador & "yy"
Else
strFormato = "mm" & strSeparador _
& "dd" & strSeparador & "yy"
End If
Debug.Print "Separador fecha " & strSeparador
Debug.Print "Formato fecha " & strDato
sngDato = 1234.5
strDato = Format(sngDato, "Standard")
strSeparadorMiles = Mid(strDato, 2, 1)
strSeparadorDecimal = Mid(strDato, 6, 1)
Debug.Print "Separador de millares " _
& strSeparadorMiles
Debug.Print "Separador de decimales " _
& strSeparadorDecimal
Debug.Print "Formato numrico " & strDato
strDato = Format(sngDato, "Currency")
Debug.Print "Formato moneda " & strDato
End Sub
Este procedimiento en mi ordenador muestra:
Separador fecha /
Formato fecha 31/12/2000
Separador de millares .
Separador de decimales ,
Formato numrico 1.234,50
Formato moneda 1.234,50
El resultado ser diferente en funcin de la Configuracin Regional propia de cada equipo.
VBA - Access
Entrega 14
Funciones de VBA II
Eduardo Olaz
14 - 2
Funcin FormatNumber
Devuelve una cadena obtenida al formatear un nmero.
Su sintaxis es
FormatNumber (expresin[, numDgitosDespusDeDecimal [,
incluirDgitoInicial [,
utilizarParntesisParaNmerosNegativos [,
agruparDgitos]]]])
La expresin puede ser cualquiera que devuelva un valor numrico.
numDgitosDespusDeDecimal define el nmero de decimales del formato de salida.
Si se pusiera el valor -1, usara la configuracin por defecto. Si necesita recortar los
decimales de expresin, realizar en su caso, un redondeo de cifras.
incluirDgitoInicial define si se pone un cero inicial, antes del separador de
decimales, si el valor de la parte entera fuera cero.
utilizarParntesisParaNmerosNegativos define si se utilizan los parntesis para indicar
un valor negativo.
agruparDgitos define si se agrupan los nmeros mediante el delimitador de grupos
(miles) especificado en la configuracin regional.
Estos tres ltimos parmetros toman valores long.
Sus valores vlidos son vbTrue, vbFalse, vbUseDefault.
vbUseDefault fuerza a usar la configuracin Regional.
El nico parmetro obligatorio es la expresin que devuelve el nmero a formatear.
Si no se pasa otro parmetro el formato se ajusta a lo definido en la Configuracin Regional.
FormatNumber admite tambin la terminacin con $. Ver el prrafo Consideraciones
previas sobre el uso del signo Dlar en esta misma entrega.
Funcin FormatCurrency
FormatCurrency devuelve una cadena tras formatear un nmero al modo moneda.
Su sintaxis es
Funcin FormatPercent
FormatPercent devuelve una cadena tras formatear un nmero al modo porcentaje.
Multiplica el valor de expresin por 100 y le aade el signo de porcentaje %.
Su sintaxis es
Funcin FormatDateTime
FormatDateTime Devuelve una cadena tras formatear un nmero al modo fecha hora,
fecha.
Su sintaxis es
datFecha = Date
datHora = Time
datFechaHora = datFecha + datHora
Debug.Print FormatDateTime(datFecha)
Debug.Print FormatDateTime(datHora)
Debug.Print FormatDateTime(datFechaHora)
Debug.Print
Debug.Print FormatDateTime(datFechaHora,vbGeneralDate)
Debug.Print FormatDateTime(datFechaHora, vbLongDate)
Debug.Print FormatDateTime(datFechaHora, vbLongTime)
Debug.Print FormatDateTime(datFechaHora, vbShortDate)
Debug.Print FormatDateTime(datFechaHora, vbShortTime)
End Sub
Tras ejecutarlo, en mi ordenador, muestra los siguientes valores:
20/02/2005
21:15:35
20/02/2005 21:15:35
20/02/2005 21:15:35
domingo 20 de febrero de 2005
21:15:35
20/02/2005
21:15
El resultado puede cambiar, respecto a otros ordenadores, segn su Configuracin regional.
Funcin MonthName
MonthName Devuelve el nombre del mes en el idioma especificado en la configuracin
regional. Su sintaxis es
MonthName(mes [, abreviar])
El parmetro que se le pasa es un nmero que representa al mes. Su valor debe estar entre
1 y 12; caso contrario dar error de Argumento o llamada a procedimiento no vlida
El parmetro abreviar , de tipo boleano, indica si queremos el nombre abreviado.
MonthName(1) "enero"
MonthName(2) "febrero"
- - - - - - - - - -
MonthName(11) " noviembre"
MonthName(12) " diciembre"
Funcin WeekdayName
WeekdayName Devuelve el nombre del da de la semana que se le pasa como parmetro,
en el idioma especificado en la configuracin regional. Su sintaxis es
En mi equipo esta funcin devuelve los siguientes valores para distintas llamadas.
WeekdayName(1) " lunes"
WeekdayName(1 ,True ,vbUseSystemDayOfWeek) " lun"
WeekdayName(1,False,vbSunday) " domingo"
WeekdayName(1,,vbMonday) " lunes"
WeekdayName(1,,vbMonday) " lunes"
Se pueden obtener resultados exticos cambiando el parmetro primerDaDeLaSemana.
Todas estas funciones tienen algo en comn:
Facilitan la presentacin de datos acorde con la configuracin del ordenador de cada
usuario, evitando tener que acceder a la configuracin regional para efectuar el formateo
adecuado del dato.
Manipulacin de cadenas
Consideraciones previas sobre el uso del signo Dlar en funciones que
devuelven cadenas de texto
Basic, desde sus principios, ya inclua todo un conjunto de procedimientos para el
tratamiento de cadenas, entre ellos podemos mencionar Left$, Right$ y Mid$.
Estos mismos procedimientos estn disponibles con VBA, pero con una salvedad; pueden
usarse sin poner el signo del Dlar al final del nombre del procedimiento.
A pesar de que la ayuda de VBA no lo utiliza, podemos afirmar que su uso es muy
recomendable.
La ayuda de VBA indica que estas funciones devuelven un tipo Variant (String).
Esto supone que internamente VBA tiene que hacer una conversin previa de Variant a
String.
La utilizacin del signo del Dlar fuerza a la funcin a devolver directamente un tipo
String, con lo que la velocidad de proceso se incrementa.
Como veremos despus la funcin Left devuelve la parte izquierda de una cadena.
Incluyo aqu el cdigo para hacer una pequea comprobacin de velocidad.
La funcin Timer devuelve el nmero de segundos que han transcurrido desde las cero
horas del da de hoy.
Public Sub Prueba()
Const Bucle As Long = 10000000
Const conCadena As String = "ABCDEFGHIJKLMN"
Dim i As Long
Dim strCadena As String
Dim tim0 As Single
tim0 = Timer
For i = 1 To Bucle
strCadena = Left(conCadena, 7)
Next i
Debug.Print Timer - tim0 & " Segundos"
tim0 = Timer
For i = 1 To Bucle
strCadena = Left$(conCadena, 7)
Next i
Debug.Print Timer - tim0 & " Segundos"
tim0 = Timer
For i = 1 To Bucle
strCadena = Left$(String:=conCadena, Length:=7)
Next i
Debug.Print Timer - tim0 & " Segundos"
End Sub
Funcin Left
Devuelve los n caracteres situados a la izquierda de una cadena dada.
Sintaxis
Left(string, length)
Left$(string, length)
Left$( "Eduardo Olaz", 7) "Eduardo"
Left( string:= "Eduardo Olaz", length := 7) "Eduardo"
length debe ser mayor igual a cero. Si es cero devolver la cadena vaca "".
Si fuese menor a cero generar el error 5 Argumento o llamada a procedimiento no vlida.
Funcin LeftB
Devuelve los n Bytes situados a la izquierda de una cadena dada.
Sintaxis
LeftB(string, length)
LeftB$(string, length)
LeftB$( "Eduardo Olaz", 14) "Eduardo"
Cmo es posible esto?
Las cadenas que maneja VBA son del tipo UNICODE . En este formato cada carcter est
formado por 2 Bytes.
LeftB extrae Bytes. Left extrae Caracteres. Por ello LeftB es adecuada para el
manejo directo de cadenas de Bytes y Left para el manejo de caracteres.
Lo dicho para LeftB ser igualmente aplicable para las funciones RightB y MidB que se
corresponden con Right y Mid, funciones que veremos a continuacin.
Function Right
Devuelve los n caracteres situados a la derecha de una cadena dada.
Sintaxis
Right (string, length)
Right$(string, length)
Right( "Eduardo Olaz", 4) " Olaz"
Right$( string:= "Eduardo Olaz", length := 4) "Olaz"
length debe ser mayor igual a cero. Si es cero devolver la cadena vaca "".
Tanto para Left como para Right si length es mayor que el nmero de caracteres
contenidos en la cadena, devolver la cadena completa sin generar un error.
Left$( "Eduardo Olaz", 50) "Eduardo Olaz"
Right( "Eduardo Olaz", 50) "Eduardo Olaz"
Function Mid
Devuelve los n caracteres de una cadena dada, situados a partir de una posicin.
Sintaxis
Mid(string, start[, length])
Mid$(string, start[, length])
Mid$( "Eduardo Olaz", 9, 3) "Ola"
Mid( string:="Eduardo Olaz",start:= 9,length:= 3) "Ola"
String es la cadena de la que vamos a extraer caracteres.
start es la posicin a partir de la cual vamos a extraerlos. Es de tipo Long y mayor que 0.
length es el nmero de caracteres que queremos extraer. Su tipo es Long.
Este parmetro es opcional. Si no se incluyera, o su valor fuera superior al nmero de
caracteres que hay desde la posicin de partida, incluyendo su carcter, devolvera todos
los caracteres que hay desde la posicin de start.
Mid( "Eduardo Olaz", 9) "Olaz"
Mid$( "Eduardo Olaz", 9, 30) "Olaz"
Instruccin Mid
La instruccin Mid, Reemplaza determinado nmero de caracteres de una cadena con los
caracteres de otra.
Sintaxis
Mid(VariableString, start[, length]) = Cadena
Comencemos a programar con VBA - Access
14 - 10
La cadena den la que queremos hacer el cambio se debe pasar mediante una variable de
tipo String Variant (VariableString).
La cadena de la que queremos extraer los caracteres puede ser pasada de forma directa, o
mediante una variable.
El nmero de caracteres reemplazados es menor o como mucho igual al nmero de
caracteres de VariableString.
Tomemos como ejemplo el siguiente cdigo
Public Sub PruebaInstruccionMid()
Dim strAlumno As String
Debug.Print strInicial
Mid(strInicial, 7) = "$$$$$$$$$$$$"
Debug.Print strInicial
End Sub
Al ejecutar PruebaMid nos mostrar
Cadena Inicial
Cadena123icial
Cadena$$$$$$$$
Como en el caso de Las funciones anteriores, tambin existe la versin MidB para efectuar
cambios a nivel de Bytes.
a(2) = "1234567890"
Funcin InStr
Devuelve un tipo Variant, convertido a Long que indica la posicin en la que podemos
encontrar una Subcadena en otra cadena.
Si como cadena buscada, o a buscar, se pasa un Null, devolver un Null.
Sintaxis
InStr([start, ]string1, string2[, comparar])
Parmetros
start: opcional, posicin donde empezar a buscar.
String1: Cadena expresin de cadena en la que se busca
string2: Cadena buscada
comparar: opcional, constante que indica qu se consideran cadenas iguales. Si no se
escribe toma el valor por defecto.
Las opciones para comparar son:
vbUseCompareOption -1 Sigue el criterio definido en Option Compare
vbBinaryCompare 0 Hace una comparacin a nivel de Bytes.
vbTextCompare 1 Compara los textos
vbDatabaseCompare 2 Sigue el criterio definido en la base de datos Access
Comencemos a programar con VBA - Access
14 - 14
Como en el caso de las funciones anteriores, tambin existe la funcin InStrB que busca
valores Byte en una cadena de Bytes.
Funcin InStrReverse
Es similar a InStr, salvo que la bsqueda comienza desde el final de la cadena
Como puede comprobarse, su sintaxis difiere ligeramente de la de InStr.
Sintaxis
InstrRev(cadena1, cadena2[, inicio[, comparar]])
inicio define la posicin final de la bsqueda. Si se omite empieza por el ltimo carcter.
Al igual que InStr si se introdujera un nulo como cadena a buscar o en la que buscar,
devolvera un Null.
Funcin StrComp
Devuelve un entero como resultado de la comparacin de dos cadenas. Si como parmetro
de alguna de las dos cadenas se pasara un nulo, devolvera Null.
Sintaxis:
StrComp(string1, string2[, comparar])
Si string1 es menor que string2 devuelve -1
Si string1 es igual a string2 devuelve 0
Si string1 es mayor que string2 devuelve 1
Si string1 o string2 es Null devuelve Null
La forma de comparar depender del valor(opcional) de comparar.
Como referencia ver comparar en InStr.
StrComp ("curso","VBA") devuelve -1
StrComp ("curso","VBA", ,vbBinaryCompare) devuelve 1
Funcin Replace
Devuelve una cadena en la que se han cambiado una subcadena por otra dada.
Sintaxis:
Sintaxis
Replace(expresin, encontrar, reemplazarCon [, inicio[,
contar[, comparar]]])
expresin: Cadena o expresin de cadena en la que buscar
encontrar: Subcadena buscada
reemplazarCon: Subcadena que reemplazar a la anterior
inicio: Cadena o expresin
comparar: Forma de comparar. Como referencia ver comparar en InStr.
Este cdigo sirve para ver distintas formas de utilizar la funcin, y sus resultados:
Funcin StrReverse
La funcin StrReverse devuelve una cadena con los caracteres invertidos respecto a la
cadena pasada como parmetro.
Sintaxis
StrReverse(cadena)
StrReverse("ABCDEFGHIJK") "KJIHGFEDCBA"
Funcin Filter
La funcin Filter devuelve un array con los elementos de otro array que contienen (o no
contienen) un determinado valor. La cadena devuelta est basada en el ndice 0.
Sintaxis
Filter(sourcesrray, match[, include[, comparar]])
Sourcesrray es la matriz en donde se va a buscar.
match es el valor con el que queremos comparar.
include Si es True hace que se busquen los valores que contengan a match.
Si es False, los que no lo contengan.
comparar Forma de comparar. Como referencia ver comparar en InStr.
El siguiente procedimiento primero busca en una matriz llamada aMatriz los datos que
contengan la palabra "Jess" y se los asigna a la matriz aFiltrada. Muestra los datos
en la ventana Inmediato y seguidamente busca aqullos elementos que no contengan la
palabra "Eduardo" y los muestra.
Public Sub PruebaFilter()
Dim aFiltrada() As String
Dim aMatriz(1 To 6) As String
Dim i As Long
aMatriz(1) = "Antonio Martnez"
aMatriz(2) = "Jess Martnez"
aMatriz(3) = "Eduardo Olaz"
aMatriz(4) = "Eduardo Prez"
aMatriz(5) = "Jess Prez"
aMatriz(6) = "Juan Prez"
Antonio Martnez
Jess Martnez
Jess Prez
Juan Prez
Funcin Split
Devuelve una matriz, basada en el ndice 0, que contiene un nmero especificado de
subcadenas extradas de una cadena de texto.
Sintaxis
Split(expresin[, delimitador[, contar[, comparar]]])
expresin Una cadena o una expresin que devuelva una cadena de caracteres. La
cadena puede contener caracteres especificadores de separacin.
delimitador Es un carcter que sirve para definir los lmites de las subcadenas dentro
de la cadena pasada. Si no se indica, toma como carcter de separacin el espacio en
blanco.
contar Indica el nmero de subcadenas que queremos extraer. Si se pasa el valor -1, se
especifica que queremos extraer todas las subcadenas. Es el modo por defecto
comparar Al igual que en las funciones anteriores, forma de comparar entre s las
cadenas. Como referencia ver comparar en InStr.
La funcin Split es til para obtener datos desde un fichero de texto con los campos
separados por Delimitadores.
El siguiente cdigo hace primero un
Public Sub PruebaSplit()
Dim strDatos As String
Dim aDatos() As String
Dim i As Long
Martnez Prez
Gmez Iturri
Garca Martn
Funcin Join
La funcin Join se podra decir que es la inversa de la funcin Split.
Toma una matriz de caracteres y los junta en una nica cadena.
El siguiente cdigo hace lo siguiente
Asigna las estaciones del ao a una matriz mediante la funcin Split.
A continuacin vuelve a juntar los datos en pero usando como separador un espacio
en blanco " ".
Public Sub PruebaJoin()
Dim strDatos As String
Dim aDatos() As String
Dim strResultado As String
strDatos = "Primavera;Verano;Otoo;Invierno"
aDatos = Split(strDatos, ";")
strResultado = Join(aDatos, " ")
Debug.Print strResultado
End Sub
Tras ejecutar el cdigo se muestra
Primavera Verano Otoo Invierno
Operador Like
Este operador se utiliza para comparar dos cadena de caracteres.
Para una comparacin con Option Compare Text, las siguientes expresiones
devolvern:
left("Eduardo Olaz", 7) like "EDUARDO" True
left(" Eduardo Olaz", 7) like "EDUARDO" False
VBA - Access
Entrega 15
Operadores
Eduardo Olaz
15 - 2
Operadores
A la hora de construir instrucciones en VBA, que contengan operaciones, no slo
manejamos constantes, variable y expresiones, sino que utilizamos unos elementos
llamados Operadores, que aplicados a uno varios operandos, generan el resultado de la
operacin.
Tipos de Operadores
Aritmticos Se usan para efectuar clculos matemticos
De Comparacin Permiten efectuar comparaciones
De Concatenacin Combinan cadenas de caracteres
Lgicos Realizan operaciones lgicas
Operadores aritmticos
VBA maneja la mayor parte de los operadores aritmticos habituales en los lenguajes de
programacin.
Estos operadores son
+ Suma
- Resta
* Producto
/ Divisin
^ Elevar a potencia
\ Divisin entera
Mod Mdulo Resto
En general, el tipo devuelto por el resultado de una operacin, es el del tipo del ms preciso
de los operadores, salvo que el resultado supere su rango; en ese caso devolver el
siguiente tipo de mayor precisin. Esta regla tiene abundantes excepciones.
Para ms informacin consulte la ayuda de Access en la que se relata toda la casustica
pormenorizada para cada uno de los operadores.
Si el resultado de una operacin fuese un dato de coma flotante y se asignara a un tipo
entero, se efectuara un redondeo.
Si se trata de asignar un resultado fuera del rango de valores de la variable que va a recibir
el resultado de la operacin, se generar un error de Desbordamiento y se interrumpir la
ejecucin del cdigo, salvo que el error fuera capturado y tratado.
Operador Suma
El operador suma (+), sirve para asignar el resultado de la suma de dos nmeros, en el
caso de cadenas, dar como resultado una cadena compuesta por las dos anteriores.
La forma de usarlo es
resultado = expresin1+expresin2
bytResultado = 10 + 23
Debug.Print bytResultado
bytResultado = 150 + 150
Debug.Print bytResultado
End Sub
Nos imprimir el resultado 33 y a continuacin nos generar el error n 6 Desbordamiento,
ya que un tipo Byte slo admite valores que van de 0 a 255.
Nos dara ese mismo tipo de error si tratramos de hacer
bytResultado = 15 + (-16)
Ya que a un Byte no se le pueden asignar valores negativos
Lo mismo ocurrira en el siguiente cdigo
Dim intResultado As Integer
strResultado = 3 + 4
Debug.Print strResultado
strResultado = 3 + "4"
Debug.Print strResultado
Hay otro sumando permitido por VBA que no deja de ser sorprendente. Es el valor Empty
(vaco) que si lo usamos con un nmero, consigo mismo, se asimila al Cero. Y con una
cadena a la cadena vaca "".
Empty + "A" "A"
Empty + 3.1416 3.1416
Empty + Empty 0
Esta promiscuidad en el manejo y la asignacin entre tipos diferentes de datos que permite
Visual Basic para Aplicaciones, es algo que personalmente no me termina de convencer,
pero como deca el castizo, - es lo que hay.
VBA no permite los operadores del tipo Pre Post Incremental como seran:
Y = ++X Y = X++
Operador Resta
El operador resta (-), sirve para asignar el resultado de la sustraccin entre dos nmeros.
Tiene dos formas sintcticas
resultado = expresin1-expresin2
- expresin
En la primera, la variable resultado recibe el valor resultante de restar expresin2 a
expresin1.
En la segunda se cambia el signo al valor numrico de expresin.
Si expresin1 expresin2 tuvieran el valor Null, resultado recibir tambin
el valor Null.
Empty lo considera como valor Cero.
Como en el caso de la suma, si uno de los operadores fuera del tipo Date, el resultado
tambin lo ser. Si desde la ventana Inmediato hacemos:
Print #3/14/5# - 100
nos mostrar
04/12/2004
Para obtener informacin sobre los distintos tipos devueltos, en funcin del de los tipos de
los operadores, consulte la ayuda de VBA.
Operador Producto
El operador producto (*), sirve para asignar el resultado del producto de dos nmeros.
La forma de usarlo es
resultado = expresin1*expresin2
resultado es una variable de tipo numrico y tanto expresin1 como expresin2
pueden ser cualquier expresin que de como resultado un valor numrico.
El tipo numrico que se suministra a resultado depender de los tipos de expresin1
y expresin2.
Si uno de los operandos es del tipo Single y el otro del tipo Long, resultado recibir
un tipo Double. Para ms informacin consultar la ayuda de VBA.
Si alguno de los operadores es Null, resultado tomar tambin el valor Null.
Si alguno de los operandos es Empty, resultado ser Cero. Ya que considerar que
ese operando contiene el valor Cero.
Operador Divisin
El operador divisin (/),asigna el resultado de la divisin de dos nmeros.
La forma de usarlo es
resultado = expresin1/expresin2
resultado es una variable de tipo numrico y tanto expresin1 como expresin2
pueden ser cualquier expresin que de como resultado un valor numrico.
Si expresin2 fuera el valor Cero, dara el error 11 de Divisin por cero.
El tipo numrico que recibe resultado normalmente ser del tipo Double.
Esta regla tiene varias excepciones
Si los operandos son del tipo Byte, Integer Single, resultado recibir un
Single, a menos que supere el rango de Single en cuyo caso ser del tipo Double.
Si uno de los operandos fuera del tipo Decimal, resultado tambin lo ser.
Es aplicable lo dicho en los anteriores operadores matemticos respecto a Null y Empty.
Para ms informacin consultar la ayuda de VBA.
16 ^ 0.5 4
Adicionalmente, para obtener la raz cuadrada en VBA existe la funcin Sqr.
Sqr(16) 4
Cuando estudibamos matemticas nos contaron que en el campo de los nmeros reales, la
raz cuadrada de un nmero negativo no tiene solucin. Por ello se crearon los nmeros
imaginarios.
Si tratamos de hacer Sqr(-16)nos generar un error 5 en tiempo de ejecucin,
indicando que el valor -16 no es correcto para la funcin Sqr.
Puede sorprender que esto no ocurra si calculamos la raz cuadrada elevando a 0.5
-16 ^ 0.5 -4
En cambio si hacemos (-16)^0.5, s dar el error.
La razn la veremos ms adelante en la prioridad de operadores.
El clculo del operador potencia se realiza antes que el del operador de cambio de signo.
Tanto en la base como en el exponente admite nmeros de coma flotante.
Por ejemplo podramos obtener algo tan extico como el resultado de elevar el nmero e,
base de los logaritmos Neperianos, al valor de Pi
2.7182818 ^ 3.1415926 23,1406906315563
4 \ 0 Error 11
Hay que tener un especial cuidado con este operador, y no olvidar que previamente realiza
un redondeo a cero decimales, tanto del numerador como del denominador.
Este redondeo utiliza el mtodo de redondeo vigente en el sistema bancario americano,
que es ligeramente diferente al europeo.
De este tema hablaremos cuando veamos la funcin Round.
Operadores de Comparacin
En algunos procesos podemos necesitar establecer si un valor es menor, igual mayor que
otro, por ejemplo para la toma de una decisin mediante una sentencia If . . . Then.
En VBA tenemos 6 tipos de operadores para esta tarea.
Estos operadores son
Operador Like
En la entrega anterior vimos la funcin InStr, que permite buscar una cadena dentro de
otra y nos devuelve la posicin en la que se encuentra. Tambin vimos la funcin StrComp
que compara dos cadenas dicindonos cul es menor.
Para la comparacin entre cadenas tenemos tambin un operador adicional
Like Permite comparar una expresin patrn con una cadena, indicndonos
si esa cadena cumple con lo indicado en la patrn.
Su sintaxis es
resultado = cadena Like patrn
Para el operador Like, tambin es aplicable lo comentado anteriormente sobre Option
Compare. Para obtener ms informacin al respecto puede consultar la informacin sobre
el operador Like en la ayuda de VBA.
Comencemos a programar con VBA - Access
15 - 10
Operador Is
Para la comparacin entre objetos tenemos un operador adicional, es el operador IS.
Case 10
- - -
Case is > 10
En ellas comprobamos si la variable pasada como testigo es menor mayor que 10.
Hay otro entorno en el que se usa Is y es en estructuras del tipo If . . . Then; en concreto
acompaando a la expresin TipeOf.
TipeOf devuelve el tipo de un objeto.
Se usa de la siguiente forma
TypeOf nombre_objeto Is tipo_objeto
Esto nos puede servir, por ejemplo para cambiar las propiedades de objetos en funcin del
tipo al que pertenecen.
Para ilustrar esto vamos a crear un formulario nuevo.
Al cargar el formulario, examinar los controles que hay en l.
Asignar a todos los controles la misma altura (propiedad Height) y ordenar las
etiquetas, cuadros de texto y botones que contenga.
Ajustar la distancia que haya entre la parte izquierda del control y la parte izquierda del
formulario (propiedad Left).
Ajustar tambin la distancia respecto a la parte superior de la seccin donde estn
ubicados (propiedad Top).
Las otras dos propiedades que ajustar sern
Texto del control (propiedades Caption o el valor por defecto de los cuadros de texto)
Anchura del control (propiedad Width).
En la barra del men del Cuadro de Herramientas, desactivamos el botn [Asistentes para
controles] (la de la varita mgica).
Ponemos en el formulario
4 Cuadros de texto
2 Etiquetas adicionales (ponles un texto para ver el efecto)
3 botones
Procuraremos poner los controles de una manera desordenada, y variando sus tamaos.
Nuestro formulario podra tener un aspecto tan pattico como ste:
Vemos que no es probable que obtenga el premio al diseo del formulario del ao.
Para tratar de poner orden en este caos, vamos a hacer que sea Access el que lo haga
utilizando cdigo. Aprovecharemos el evento Al cargar del formulario
Teniendo seleccionado el formulario, en la ventana de propiedades seleccionamos el evento
Al cargar y en el editor de cdigo escribimos lo siguiente:
Private Sub Form_Load()
Const conlngAltura As Long = 300
Dim ctr As Control
Dim lngEtiquetas As Long
Dim lngCuadrosTexto As Long
Dim lngBotones As Long
End If
Next ctr
End Sub
Este cdigo hace que el formulario, tras cargarse, tome este otro aspecto
Su sintaxis es TypeName(nombrevariable)
Operadores de concatenacin
Los operadores de concatenacin sirven para unir varias cadenas en una sola.
Estos operadores son
+ Suma
& Ampersand
Ya he comentado la posibilidad que tiene el operador suma para unir cadenas, al igual que
el operador &.
Tambin he comentado mi preferencia por el operador & para efectuar estas tareas.
La sintaxis para estos operadores es
resultado = expresin1 + expresin2
resultado = expresin1 & expresin2
Operadores lgicos
Los operadores lgicos sirven para realizar operaciones lgicas con los operandos.
Estos operadores son
Operador And
El operador And, realiza una conjuncin lgica entre dos expresiones operandos.
Su sintaxis es
Operador Or
El operador Or, realiza una Disyuncin lgica entre dos operandos.
Su sintaxis es
resultado = expresin1 Or expresin2
Resultado puede ser cualquier variable numrica boleana.
resultado tomar el valor True, si cualquiera de las dos expresiones es True.
Las combinaciones de False con False da False.
Null con False con Null da Null
A nivel de bits, en operaciones con nmeros, Or dar 1 salvo en el caso de que ambos bits
valgan 0.
5 Or 13 13
0101
1101
1101
El binario 1101 es en notacin decimal el nmero 13
Con el operador And, hemos visto que podemos averiguar qu bit est activado en una
expresin.
El operador Or nos permite definir el valor de un determinado bit de un valor.
Supongamos que tenemos un dispositivo que contiene la propiedad Config de tipo Long,
que controla el funcionamiento del mismo.
Comencemos a programar con VBA - Access
15 - 18
Operador Xor
El operador Xor, realiza una Exclusin lgica entre dos operandos.
Su sintaxis es
resultado = expresin1 Xor expresin2
Resultado puede ser cualquier variable numrica boleana.
Tomar el valor True, si una de las dos expresiones es True y la otra False.
Si cualquiera de ellas es Null, dar Null.
Si las dos son a la vez False o True dar False.
Cuadro de resultados del operador Xor
Expresin 1 Expresin 2 Resultado
True True False
True False True
False True True
False False False
Operador Not
El operador Not, realiza una Negacin lgica sobre una expresin.
Su sintaxis es
resultado = Not expresin
Resultado puede ser cualquier variable numrica boleana.
Tomar el valor True, si expresin es False y a la inversa.
Si expresin fuese Null, devolver Null.
Cuadro de resultados del operador Not
Expresin Resultado
True False
False True
Null Null
Operador Eqv
El operador Eqv, realiza una Equivalencia lgica entre dos expresiones.
Su sintaxis es
resultado = expresin1 Eqv expresin2
resultado puede ser cualquier variable numrica boleana.
Si alguna de las expresiones fuera Null, el resultado ser Null.
Si los dos operandos fuesen True False, dara como resultado True.
En caso contrario dara False.
Cuadro de resultados del operador Eqv
Expresin 1 Expresin 2 Resultado
True True True
True False False
False True False
False False True
Podra considerarse como el operador inverso a Xor.
En operaciones a nivel de bit, dar 1 si los dos bits fueran iguales.
Si uno de los dos es 0 y el otro 1 dar 0.
5 Eqv 13 -9
0000000000000101
0000000000001101
1111111111110111
El binario 1111111111110111 es el nmero -9
Operador Imp
El operador Imp, realiza una Implicacin lgica entre dos expresiones.
Su sintaxis es
resultado = expresin1 Imp expresin2
resultado puede ser cualquier variable numrica boleana.
Cuadro de resultados del operador Imp
Expresin 1 Expresin 2 Resultado
True True True
True False False
True Null Null
False True True
False False True
False Null True
Null True True
Null False Null
Null Null Null
1. 19 And 7 3
2. 4 Or 3 7
3. 7 Or 13 15
Si quisiramos que evaluara primero 4 or 19, 7 or 13 y luego los respectivos
resultados mediante And, deberamos haber escrito
(4 Or 19) And (7 Or 13)
Que nos dar como resultado 7.
La utilizacin de parntesis aclara el cdigo y ayuda a evitar errores en el diseo del mismo,
muchas veces con resultados inesperados, y de difcil deteccin.
VBA - Access
Entrega 16
Eduardo Olaz
16 - 2
Si nos ponemos en el cuadro Nombre del formulario, vemos que nos aparece una flecha
hacia abajo que nos permite seleccionar un formulario.
Si la base de datos era nueva nos aparecer nicamente el formulario PruebaMacro que
acabamos de guardar. Seleccionaremos ese formulario.
Tras ello nos aparece una nueva ventana en la que nos sugiere que la exportacin a un
mdulo la va a efectuar con control de errores y comentarios.
'------------------------------------------------------------
' Autoexec
'
'------------------------------------------------------------
Function Autoexec()
On Error GoTo Autoexec_Err
Autoexec_Exit:
Exit Function
Autoexec_Err:
MsgBox Error$
Resume Autoexec_Exit
End Function
Vemos que la macro ha sido cambiada por un mdulo que contiene la funcin Autoexec.
Quiero suponer que en vez de un procedimiento sub, genera una funcin
que no devuelve explcitamente ningn valor, para que pueda ser utilizada
directamente desde la pestaa eventos de la ventana de propiedades de un
formulario, informe o control. Ya hablaremos ms delante de este tema
Esta funcin tiene dos partes que se corresponden con las dos acciones de la macro.
La accin AbrirFormulario se sustituye por el mtodo OpenForm del objeto DoCmd.
La accin CuadroMsj se sustituye por la funcin MsgBox que ya hemos visto.
Har mencin aparte a la instruccin Beep.
Esta instruccin en teora sirve para que el equipo emita un sonido de advertencia.
Dependiendo de la tarjeta de sonido que se tenga, y la configuracin del software, se oir un
pitido, un sonido o incluso puede que no se oiga absolutamente nada.
Las mismas acciones que hemos puesto en la macro Autoexec, podramos haberlas puesto
en un mismo fichero de Macro, como dos macros independientes.
Para ello vamos a hacer lo siguiente:
Desde la ventana de Macros, ponemos el cursor del ratn encima de la macro Autoexec y
presionamos el botn derecho del ratn (el izquierdo para los zurdos que as lo tengan
configurado).
Nos aparecer un men contextual, una de cuyas opciones es Cambiar nombre.
Cambiamos el nombre de la macro Autoexec, por el de MacrosInicio.
A continuacin pulsamos el botn de Diseo (el la escuadra, la regla y el lpiz ) y se nos
abrir la macro en vista diseo.
Guardamos todo y vemos que ahora s que se muestra el cuadro de mensaje para
indicarnos la apertura del formulario.
Cmo afectara este cambio en las macros al cdigo que se generara con el conversor de
macros a cdigo VBA?.
La respuesta la podemos obtener de forma inmediata.
Guardamos la macro, si es que no lo habamos hecho, y desde la ventana macro,
seleccionamos nuestra flamante MacrosInicio y activamos la opcin de men
[Herramientas] [Macro] [Convertir Macros a Visual Basic]
Se nos genera un nuevo mdulo, esta vez con el nombre
Macro convertida- MacrosInicio.
El cdigo que contiene ese mdulo es el siguiente
'------------------------------------------------------------
' MacrosInicio_Autoexec
'
'------------------------------------------------------------
Function MacrosInicio_Autoexec()
On Error GoTo MacrosInicio_Autoexec_Err
MacrosInicio_Autoexec_Exit:
Exit Function
MacrosInicio_Autoexec_Err:
MsgBox Error$
Resume MacrosInicio_Autoexec_Exit
End Function
'------------------------------------------------------------
' MacrosInicio_Mensaje
'
'------------------------------------------------------------
Function MacrosInicio_Mensaje()
On Error GoTo MacrosInicio_Mensaje_Err
Beep
MsgBox "Formulario abierto", vbOKOnly, ""
MacrosInicio_Mensaje_Exit:
Exit Function
MacrosInicio_Mensaje_Err:
MsgBox Error$
Resume MacrosInicio_Mensaje_Exit
End Function
As como la primera vez nos cre un mdulo con una nica funcin, al tener ahora dos
macro en un mismo fichero de macros, nos crea un mdulo con dos funciones.
El objeto DoCmd
El objeto DoCmd es un objeto especfico de Access, creado para sustituir a las acciones de
las Macros. De hecho sustituye con ventaja a casi todas ellas.
Hasta Access 97, no exista ese objeto, pero s exista el procedimiento DoCmd.
Por tanto el objeto DoCmd empez a existir con Access 97.
Los argumentos de la accin sern ahora los argumentos del mtodo de DoCmd.
En la accin AbrirFormulario, ponamos como Nombre del formulario PruebaMacro, como
vista Formulario y como modo de la ventana Normal.
Al mtodo OpenForm, que abre un formulario, le pasamos como nombre del formulario
(FormName) "PruebaMacro", como vista (View) acNormal, y como tipo de ventana
(WindowMode) acNormal.
Las constante acNormal est definida como una constante enumerada miembro de
Access.AcFormView. Su valor numrico es 0.
Comencemos a programar con VBA - Access
16 - 8
Ya comentamos las Constantes Enumeradas en la entrega 12. Este tipo de constantes van
a ir apareciendo con mucha frecuencia conforme vayamos avanzando en VBA.
Como habrs podido ver hay un paralelismo total entre la accin de macro y el mtodo
correspondiente de DoCmd.
Pero no todas las Acciones de las macros estn implementadas en los mtodos de DoCmd.
Por ejemplo, en la conversin de macros a cdigo VBA hemos visto que CuadroMsj se
sustituye por la funcin MsgBox.
Otras acciones no implementadas en DoCmd son
Accin Equivalencia en VBA
RunApp Funcin Shell
RunCode Llamada a la subrutina correspondiente
SendKeys Instruccin SendKeys
SetValue Operador = de asignacin
StopAllMacros Instrucciones Stop o End
StopMacro Instrucciones Exit Sub o Exit Function
Beep Se puede utilizar para emitir un sonido por los altavoces del PC
CancelEvent Se utiliza para cancelar un evento. Slo tiene efecto cuando se
ejecuta como resultado de un evento. No usa parmetros.
Close Permite cerrar la ventana de un objeto.
Hay que pasarle como parmetros el Tipo y el Nombre del objeto.
Tambin se le puede pasar un tercer argumento para indicar si se
guardan o no los posibles cambios.
Este cdigo cierra el formulario actual
DoCmd.Close
Esta lnea cierra el formulario PruebaMacro y guarda los posibles
cambios sin preguntar si deben o no ser guardados.
DoCmd.Close acForm, " PruebaMacro", acSaveYes
Hourglass Hace aparecer un reloj de arena en vez del cursor normal del
ratn.
Si el parmetro es False, vuelve a colocar el cursor por defecto.
DoCmd.Hourglass True
acDesign
acFormDS
acFormPivotChart
acFormPivotTable
acNormal (predeterminado)
acPreview
El Modo de edicin toma una constante AcFormOpenDataMode
acFormAdd Se puede agregar registros nuevos pero no se
pueden modificar los existentes.
acFormEdit Se pueden modificar los registros existentes
y agregar registros nuevos.
acFormPropertySettings (predeterminado)
acFormReadOnly Los registros slo se pueden ver.
El Modo como se mostrar la ventana toma uno de los valores
AcWindowMode
acDialog El formulario ser Modal y Emergente.
acHidden El formulario estar oculto.
acIcon Se abre minimizado.
acWindowNormal valor predeterminado
La siguiente lnea abre el formulario Alumnos, en modo de slo
lectura, con los datos de los alumnos residentes en Pamplona.
DoCmd.OpenForm "Alumnos", , , _
"Poblacion = 'Pamplona'", acFormReadOnly
OpenFunction Abre una funcin definida por el usuario en una base de datos de
Microsoft SQL Server para verla desde Microsoft Access.
Los parmetros son el nombre de la funcin, la Vista como se va a
mostrar la funcin, y el Modo de visualizacin o edicin de los
datos.
La Vista puede es una constante del tipo AcView.
acViewDesign Abre la funcin en la vista Diseo.
acViewNormal (predeterminado).
acViewPivotChart Vista Grfico dinmico.
acViewPivotTable Vista Tabla dinmica.
acViewPreview Abre la funcin en la Vista preliminar.
El modo de visualizacin es del tipo AcOpenDataMode.
acAdd Abre la funcin para la insercin de datos.
acEdit (predeterminado). Abre la funcin para
actualizar los datos existentes.
acReadOnly Abre la funcin en Slo lectura.
La siguiente lnea abre la funcin Ajuste en vista normal y en el
modo edicin de datos.
DoCmd.OpenFunction "Ajuste", , acEdit
DoCmd.OpenStoredProcedure "ControlAlumnos", _
acViewNormal", _
acReadOnly
OpenTable Abre una tabla en vista hoja de datos, diseo o vista previa, y
permite, en su caso, especificar el Modo de la Vista (tipo AcView)
y el del Modo de edicin de los datos (tipo AcOpenDataMode).
El siguiente cdigo abre la tabla Alumnos en el modo Normal pero
de slo lectura.
DoCmd.OpenTable "Alumnos", _
acViewNormal", _
acReadOnly
OpenView Abre una vista de una base de datos SQLServer desde un archivo
de proyecto .adp
La vista puede estar en modo hoja de datos, diseo o vista previa.
Como parmetros se pasan el Nombre de la vista, el Modo como
se va a ver (AcView) y el Modo de edicin de los datos (tipo
AcOpenDataMode).
El siguiente cdigo abre la vista AlumnosMatriculados en el modo
tabla dinmica de slo lectura.
DoCmd.OpenView "AlumnosMatriculados", _
acViewPivotTable, _
acReadOnly
Eduardo Olaz
Entrega 16 Macros vs. Cdigo - Objeto DoCmd 16 - 19
DoCmd.RunMacro "MacrosInicio.Mensaje",3
La accin RunSQL (EjecutarSQL) ejecuta una consulta de accin
RunSQL
utilizando una instruccin SQL correspondiente. Tambin puede
utilizarse para ejecutar una consulta de definicin de datos.
Como consultas de accin se puede anexar, eliminar y actualizar
registros e incluso guardar un conjunto de datos resultado de una
consulta dentro de una nueva tabla.
Como consulta de definicin de datos se pueden usar las
siguientes instrucciones SQL
Para crear una tabla Create Table
Para modificar una tabla Alter Table
Para borrar una tabla Drop Table
Para crear un ndice Create Index
Para borrar un ndice Drop Index
El siguiente ejemplo crea la tabla Alumnos, con diferentes tipos de
campo, utilizando el mtodo RunSQL.
Public Sub CrearTablaAlumnos()
Dim strSQL As String
DoCmd.GoToRecord , , acNext
Exit_cmdRegistroSiguiente_Click:
Exit Sub
Err_cmdRegistroSiguiente_Click:
MsgBox Err.Description
Resume Exit_cmdRegistroSiguiente_Click
End Sub
Vemos que nos ha generado un procedimiento de evento que define qu debe pasar cuando
se presione el botn [cmdRegistroSiguiente].
En concreto vemos que usa el objeto DoCmd con el mtodo GotoRecord, y el parmetro
acNext.
Esto hace que intente posicionarse en el registro siguiente. Incluso define un sistema para
controlar posibles errores que se puedan generar.
Sugiero al lector que intente realizar un formulario, conectado a una tabla o consulta y que
contenga botones para efectuar las siguientes operaciones:
1. Ir al primer registro
2. Ir al registro anterior
3. Ir al registro siguiente
4. Ir al ltimo registro
5. Agregar nuevo registro
6. Guardar registro
7. Cerrar Formulario
Una vez realizadas estas operaciones analizar el cdigo que se genera.
As mismo sugiero que efecte pruebas con diferentes mtodos de DoCmd.
VBA - Access
Entrega 17
Eduardo Olaz
17 - 2
Los mtodos que ahora nos interesan son Path, Name y FullName.
Veamos el siguiente cdigo:
Public Function CarpetaActual() As String
CarpetaActual = CurrentProject.Path
End Function
De esta manera, si los datos estuvieran en el fichero Datos.mdb ubicado en una carpeta
llamada Datos, que cuelgue de la carpeta de la aplicacin, podramos definir una funcin
llamada FicheroDatos que nos devuelva la ruta completa del fichero.
Podra ser algo as como:
Public Function FicheroDatos() As String
Const conBaseDatos As String = "Datos.mdb"
FicheroDatos = CarpetaActual() _
& "\Datos\" & conBaseDatos
End Function
Si ejecuto en mi ordenador esta funcin, me devuelve la cadena
C:\CursoVBAAccess\Captulo_17\Datos\Datos.mdb
Otro paso interesante sera comprobar si existen la carpeta y el fichero en nuestro disco.
Una de las formas de averiguarlo sera utilizando la funcin Dir().
Funcin Dir
La funcin Dir(), nos devuelve un valor de tipo String que representa el nombre de un
archivo, o carpeta que coincide con el patrn o atributo de archivo que se le ha pasado
como parmetro. Tambin nos puede devolver la etiqueta de volumen de una unidad de
disco.
NombreDeRuta es una expresin de cadena que indica la ruta donde queremos buscar y
el tipo de fichero que nos interesa.
Adems de la ruta podemos especificar caractersticas que tenga el nombre del fichero,
mediante el uso de los comodines "*" y "?". Por ejemplo para obtener los ficheros de
cualquier tipo que empezaran por la letra A, en la carpeta "C:\Graficos\" podramos
escribir Dir("C:\Graficos\A*.*").
El smbolo "*" sustituye a cualquier nmero de caracteres.
El smbolo sustituye a 1 carcter, o ninguno.
Por ejemplo, Dir("C:\Graficos\????.*") nos devolvera nombres de ficheros con
hasta cuatro caracteres en el nombre, y con cualquier tipo de extensin.
Dir("C:\Graficos\?a??.*") nos devolvera nombres con hasta cuatro caracteres
en el nombre, que tuvieran la letra a como segundo carcter en el nombre , y con cualquier
tipo de extensin. Estos nombres de fichero seran vlidos para este ltimo caso
gato.bmp
bart.jpg
Para obtener todos los nombres de fichero de una carpeta que cumplan determinada
condicin, la primera llamada se efecta con el nombre de la ruta y sus atributos.
Las siguientes llamadas se hacen nicamente con Dir() devolviendo el nombre de los
sucesivos ficheros.
Mientras existan ficheros que cumplan la condicin, Dir() devolver su nombre. Cuando
deje de haberlos, devolver la cadena vaca "".
Atributos es una constante. Los valores que puede tomar son:
vbNormal (Predeterminado) Especifica archivos sin atributos.
vbReadOnly Slo lectura y sin atributos
vbHidden Archivos ocultos y sin atributos
VbSystem Del sistema y sin atributos
vbVolume Etiqueta del volumen
vbDirectory Carpetas y archivos sin atributos
Si por ejemplo quisiramos obtener todos los ficheros que fueran del tipo Gif y que
estuvieran en la carpeta C:\Graficos\", podramos hacer:
Public Sub FicherosGif()
Dim colFicheros As New Collection
Dim strCarpeta As String
Dim strFichero As String
Dim i As Long
strCarpeta = "C:\Graficos\"
Exit Sub
Else
Do Until strFichero = ""
colFicheros.Add strFichero
strFichero = Dir()
Loop
End If
For i = colFicheros.Count To 1 Step -1
Debug.Print colFicheros(i)
colFicheros.Remove (i)
Next i
Set colFicheros = Nothing
End Sub
En este ejemplo busca los ficheros del tipo gif, en la carpeta "C:\Graficos\" mediante
la expresin
Dir(strCarpeta & "*.gif")
Si en la primera llamada encuentra alguno, strFichero ser diferente a la cadena vaca,
aade el resultado a la coleccin colFicheros.
Repite el bucle con Dir() y va aadiendo el resultado a la coleccin, hasta que devuelva la
cadena vaca.
En ese momento hace un bucle que va recorriendo los diferentes elementos de la coleccin,
desde el ltimo hasta el primero, los muestra en la ventana Inmediato y los descarga de la
coleccin.
Al final elimina el objeto colFicheros asignndole el valor Nothing.
Si en el primer Dir no hubiramos indicado la carpeta donde queremos buscar, por ejemplo
escribiendo
Dir("*.gif")
El procedimiento hubiera mostrado los posibles ficheros gif que existieran en la ruta de
acceso actual. Una de las carpetas habituales suele ser la de "Mis documentos".
El valor de esta carpeta la podemos obtener mediante la funcin CurDir.
Mediante la funcin Dir, podemos tambin obtener el nombre del volumen, usando la letra
de la unidad y la constante vbVolume.
Por ejemplo:
Dir("C:",vbVolume)
Dir("E:",vbVolume)
Funcin CurDir
La funcin CurDir(), nos devuelve un valor de tipo String que representa el nombre de
la ruta de acceso actual.
Su sintaxis es CurDir[(Unidad)]
Podemos usar el nombre de la unidad de la que queremos obtener la ruta de acceso.
Instruccin ChDir
La instruccin ChDir, establece la carpeta actual. Para ello se le pasa como parmetro la
carpeta deseada.
Su sintaxis es ChDir Ruta
Si la ruta no existiera, generara el error 76
"No se ha encontrado la ruta de acceso"
Para cambiar la carpeta actual a "C:\Programa\Datos".
ChDir "C:\Programa\Datos"
ChDir no cambia la unidad de disco actual, slo la carpeta del disco especificado
La siguiente instruccin cambia la carpeta de D:
ChDir "D:\Comercial\Datos"
Si la unidad seleccionada hasta ese momento era la C, seguir sindolo despus de esta
ltima instruccin.
Si en la ruta no se especifica la unidad, se cambia el directorio o carpeta predeterminado de
la unidad actual.
Se puede hacer que la carpeta actual sea la de un nivel superior pasndole dos puntos.
ChDir "C:\Programa\Datos"
Tras esto la carpeta actual es "C:\Programa\Datos\".
ChDir ".."
Tras esto la carpeta actual pasa a ser "C:\Programa\".
Si quisiramos cambiar la unidad de disco actual, debemos utilizar la instruccin ChDrive.
Instruccin ChDrive
La instruccin ChDrive, establece la unidad de disco actual.
Su sintaxis es ChDrive Unidad
ChDrive "D"
Si no existiera, o no estuviera disponible la unidad pasada como parmetro, generara el
error 68
"Dispositivo no disponible"
A veces podemos vernos en la necesidad de crear una carpeta nueva.
Para ello tenemos la instruccin MkDir.
Instruccin MkDir
La instruccin MkDir, crea una carpeta.
Instruccin RmDir
La instruccin RmDir, elimina una carpeta existente.
Su sintaxis es RmDir Ruta
Tras crear las carpetas del punto anterior podramos eliminarlas utilizando
RmDir "C:\MiNuevaCarpeta\Subcarpeta_1"
RmDir "C:\MiNuevaCarpeta\Subcarpeta_2"
RmDir "C:\MiNuevaCarpeta"
Para eliminar una carpeta con RmDir es preciso que sta est vaca, es decir: no debe
tener ningn archivo ni otra subcarpeta. Caso contrario generara el error 75
"Error de acceso a la ruta o el archivo"
Instruccin Kill
La instruccin Kill, elimina un archivo existente.
Su sintaxis es Kill Ruta
El argumento requerido Ruta es una cadena que especifica el nombre o los nombres de los
archivos que se van a eliminar.
Puede incluir la ruta completa del fichero.
Al igual que la funcin Dir, tambin admite utilizar los comodines asterisco "*" y "?".
Por ejemplo, si quisiramos borrar todos los ficheros gif de la carpeta actual, usaramos
Kill "*.gif"
Si quisiramos borrar todos los ficheros de la carpeta actual, usaramos
Kill "*.*"
Si quisiramos borrar todos los archivos que empezaran por Tmp :
Kill "Tmp*.*"
Si quisiramos borrar todos los ficheros cuyo nombre empiece por A y tengan hasta 4
caracteres en el nombre.
Kill "A???.*"
El objeto FileSearch
Adems de los procedimientos vistos con anterioridad, VBA incorpora un objeto que nos
puede suministrar una informacin ms completa que los procedimientos vistos en los
puntos anteriores. Es el objeto FileSearch.
El objeto FileSearch es devuelto por el objeto Application, a travs de su propiedad
FileSearch.
Para poder trabajar con FileSearch, aunque no se haya efectuado una referencia a la
biblioteca mencionada, y que se identifique el valor de las constantes, en esta y sucesivas
tablas pongo su nombre y su valor.
SortOrder especifica el orden de los datos obtenidos.
Nombre de la constante Valor
msoSortOrderAscending predeterminado 1
msoSortOrderDescending 2
End Sub
Propiedad LastModified
La propiedad LastModified (de tipo Boolean) devuelve o establece una constante
que indica el tiempo transcurrido desde la ltima vez que se modific y guard el archivo.
El valor predeterminado para esta propiedad es msoLastModifiedAnyTime, con el
valor 7.
Este ejemplo, extrado de la ayuda de Access, establece las opciones para la bsqueda de
un archivo. Los archivos que devolver esta bsqueda han sido previamente modificados y
estn ubicados en la carpeta C:\Grficos o en una subcarpeta de sta.
Objeto FoundFiles
& .LookIn
End If
End With
End Sub
Mtodo NewSearch
El mtodo NewSearch restablece los valores por defecto de todos los criterios de
bsqueda.
Su sintaxis es :
ObjetoFileSearch.NewSearch
Propiedad FileType
La propiedad FileType nos permite averiguar o establecer el tipo de archivo que debe
buscarse. Es de lectura y escritura
Esta propiedad se debe corresponder a alguna de las constantes MsoFileType.
Sus valores posibles son:
Nombre de la constante Valor
msoFileTypeAllFiles 1
msoFileTypeBinders 6
msoFileTypeCalendarItem 11
msoFileTypeContactItem 12
msoFileTypeCustom
msoFileTypeDatabases 7
msoFileTypeDataConnectionFiles 17
msoFileTypeDesignerFiles 22
msoFileTypeDocumentImagingFiles 20
msoFileTypeExcelWorkbooks 4
msoFileTypeJournalItem 14
msoFileTypeMailItem 10
msoFileTypeNoteItem 13
msoFileTypeOfficeFiles 2
msoFileTypeOutlookItems 9
msoFileTypePhotoDrawFiles 16
msoFileTypePowerPointPresentations 5
msoFileTypeProjectFiles 19
msoFileTypePublisherFiles 18
msoFileTypeTaskItem 15
msoFileTypeTemplates 8
msoFileTypeVisioFiles 21
msoFileTypeWebPages 23
msoFileTypeWordDocuments 3
Nota:
La constante msoFileTypeAllFiles, de valor 1, hace que se busquen todos los archivos.
La constante msoFileTypeOfficeFiles, cuyo valor es 2, incluye todos los archivos que
tienen una de las siguientes extensiones: *.doc, *.xls, *.ppt, *.pps, *.obd,
*.mdb, *.mpd, *.dot, *.xlt, *.pot, *.obt, *.htm, o *.html.
Ejemplo:
El siguiente cdigo busca en la carpeta "C:\Grficos", sin tomar en cuenta las
subcarpetas, los ficheros tipo Pgina Web.
Public Sub UsoDeFileType()
Dim objFileSearch As Object
Dim i As Long
Set objFileSearch = Application.FileSearch
With objFileSearch
.NewSearch
.SearchSubFolders = False
.LookIn = "C:\Grficos"
' msoFileTypeWebPages tiene el valor 23
.FileType = msoFileTypeWebPages
If .Execute > 0 Then
MsgBox "Se han encontrado " _
& .FoundFiles.Count & _
" ficheros de tipo pgina web"
For i = 1 To .FoundFiles.Count
MsgBox .FoundFiles(i), _
vbInformation, _
"Fichero N " & Format(i, "0000")
Next i
Else
MsgBox "No hay ficheros web"
End If
End With
End Sub
With Application.FileSearch
MkDir Path:=strCarpeta
Sub ListarNombresDeCarpetas()
Dim i As Integer
Dim strResultados As String
With Application.FileSearch.SearchScopes.Item(1). _
ScopeFolder.ScopeFolders.Item(2)
For i = 1 To .ScopeFolders.Count
strResultados = strResultados & .ScopeFolders. _
Item(i).Name & vbCrLf
Next i
Nota:
Los apartados anteriores, referentes al objeto FileSearch, tienen exclusivamente
como objetivo, introducir al lector en el uso de este objeto y sus posibilidades.
Profundizar en los mismos est fuera del alcance y de los objetivos de este texto, por
lo que remito a los posibles interesados a la ayuda de VBA, en donde podrn
encontrar una extensa resea sobre ellos.
VBA - Access
Entrega 18
Eduardo Olaz
18 - 2
Instruccin Open
Para poder acceder a un fichero lo primero que hay que hacer es abrirlo.
La instruccin Open es la que se encarga de activar las funciones de Entrada/Salida en un
fichero.
Su sintaxis es
Funcin FreeFile
La Funcin FreeFile, nos devuelve un valor del tipo Integer que podremos utilizar con
la instruccin Open para abrir, leer, escribir y cerrar ficheros.
Su sintaxis es
FreeFile [(NmeroIntervalo)]
NmeroIntervalo es un parmetro opcional que puede tomar el valor 0 por defecto y 1.
Si se pasa como parmetro 0, devuelve un nmero libre para el manejador de ficheros, en el
rango de 1 a 255. Si se pasa el parmetro 1, el rango va de 256 a 511.
El rango 256 a 511 se suele usar para ficheros que van a ser compartidos.
Instruccin Print #
La Instruccin Print #, graba los datos tal y como se mostraran, por ejemplo en la
Ventana Inmediato, usando la sentencia Print.
Su sintaxis es
Print #NmeroArchivo,[ListaAGrabar]
NmeroArchivo es un entero entre 1 y 511.
Se aconseja usar uno devuelto por la funcin FreeFile.
ListaAGrabar (Opcional) es una lista de datos que queremos incorporar al fichero
abierto con Open .
Este procedimiento graba un prrafo con las primeras frases de Don Quijote de la Mancha,
en el fichero Texto.txt.
Finalmente cierra el fichero mediante Close #NmeroArchivo.
Public Sub UsoDePrint()
Dim lngFichero As Long
Dim strFichero As String
strFichero = CurrentProject.Path
lngFichero = FreeFile
' Abrimos el fichero, como de Escritura _
y si no existe lo crea
Open strFichero For Output As #lngFichero
' Escribimos en el fichero
Print #lngFichero, "En un lugar de la Mancha, ";
Print #lngFichero, "de cuyo nombre no quiero acordarme,";
Print #lngFichero, " no hace mucho que viva . . ."
Close #lngFichero
End Sub
Ejecute este procedimiento y abra el archivo, por ejemplo con el Bloc de Notas.
Como puede apreciar, las diferentes partes del texto han sido colocadas una detrs de la
otra. Esto ha sido as, porque he colocado un punto y coma despus de cada texto.
Print #lngFichero, "de cuyo nombre no quiero acordarme,";
Si no se hubiera colocado el punto y coma, cada tramo de texto se hubiera grabado en un
prrafo diferente.
Print# aade detrs de cada texto un Retorno de Carro VbCr y un Salto de Lnea vbLf,
salvo que encuentre un punto y coma, o una coma tras el texto a grabar.
El conjunto vbCr y vbLf equivale a la constante vbCrLf.
Si en lugar de poner un punto y coma, tras la expresin a grabar, pusiramos una coma,
Print# aadira un tabulador.
Por ejemplo, la expresin:
Print #lngFichero, 1, 2, 3, 4
Print #lngFichero, "1", "2", "3", "4"
[email protected] Eduardo Olaz
Entrega 18 Trabajar con ficheros II 18 - 5
Funcin Tab
La Funcin Tab, marca el nmero de columna en el que se empezar a grabar el primer
carcter de la lista de datos o la expresin a grabar mediante la instruccin Print # o el
mtodo Print.
Sintaxis: Tab[(n)]
n representa el nmero de columna.
Por ejemplo si ejecutamos este cdigo obtendremos un fichero como el de la imagen:
strFichero = CurrentProject.Path
ChDir (strFichero)
strFichero = strFichero & "\FicheroConTab.txt"
lngFichero = FreeFile(1)
Funcin Spc
La Funcin Spc, especifica el nmero de espacios en blanco antes de grabar el primer
carcter de la lista de datos o expresin, mediante Print # o el mtodo Print.
Sintaxis: Spc(n)
El parmetro n es obligatorio y marca el nmero de espacios.
Public Sub UsoDeSpc()
Dim lngFichero As Long
Dim strFichero As String
strFichero = CurrentProject.Path
ChDir (strFichero)
strFichero = strFichero & "\FicheroConSpc.txt"
lngFichero = FreeFile(1)
Open strFichero For Output As #lngFichero
Print #lngFichero, "Nombre"; Spc(3); "Eduardo";
Print #lngFichero, Spc(3); "Apellido1"; Spc(3); "Olaz"
Close #lngFichero
End Sub
Instruccin Width #
La instruccin Width #, especifica el ancho de lnea de salida a un archivo abierto
mediante la instruccin Open.
Sintaxis: Width # NmeroArchivo, Ancho
El parmetro Ancho es obligatorio y puede ser un nmero una expresin numrica cuyo
resultado est entre 0 y 255.
Si ejecutamos el siguiente cdigo:
strFichero = CurrentProject.Path
ChDir (strFichero)
strFichero = strFichero & "\FicheroConWidth.txt"
strTexto ="Estos son los viajes de la nave Enterprise." _
& vbCrLf _
& "Misin durante los prximos aos: " _
& "Explorar nuevos mundos . . ."
lngFichero = FreeFile(1)
Open strFichero For Output As #lngFichero
' Establece el ancho de la lnea a 10.
VBA.Width# lngFichero, 10
For i = 1 To Len(strTexto)
' Graba el texto carcter a carcter
strCaracter = Mid$(strTexto, i, 1)
Print #lngFichero, strCaracter;
Next i
Close #lngFichero
End Sub
Obtendremos el siguiente resultado:
Instruccin Write #
La instruccin Write #, es semejante a Print#, y sirve tambin para escribir datos en
un fichero secuencial.
La diferencia fundamental con Print # es que Write #, escribe las cadenas
marcndolas con el carcter Comilla doble como delimitador, adems separndolos con una
coma, y los nmeros los escribe separndolos con comas.
En el ejemplo con Print #, nos generaba el siguiente fichero:
strFichero = CurrentProject.Path
' Definimos como carpeta actual la del fichero mdb
ChDir (strFichero)
strFichero = strFichero & "\TextoConWrite.txt"
[email protected] Eduardo Olaz
Entrega 18 Trabajar con ficheros II 18 - 9
lngFichero = FreeFile
' Abrimos el fichero, como de Escritura _
y si no existe lo crea
Open strFichero For Output As #lngFichero
' Escribimos en el fichero
Podemos observar que efectivamente nos crea un fichero con los elementos separados por
comas. Otro aspecto interesante es que, tanto las fechas como los valores booleanos, los
delimita con almohadillas #.
Si hubiera que grabar un dato cuyo valor fuera Null, grabara #Null#.
Un dato de Error, lo grabara con el siguiente formato #ERROR cdigoerror#
Si hubiera que grabar un dato cuyo valor fuera Empty, no grabara nada en el fichero.
Los datos grabados con Print #, normalmente se leern con Line Input #
Input #. Estas instrucciones las veremos a continuacin.
strFichero = CurrentProject.Path
' Definimos como carpeta actual la del fichero mdb
ChDir (strFichero)
strFichero = strFichero & "\ClientesBanco.dat"
lngFichero = FreeFile
' Abrimos el fichero, como de Escritura _
y si no existe lo crea
Open strFichero For Output As #lngFichero
' Primero creamos el fichero ClientesBanco.dat _
que luego leeremos
Write #lngFichero, _
"Pedro Rodrguez", #5/25/1983#, 100000.25
Write #lngFichero, _
"Juan Gorostiza", #12/30/2001#, 43235.37
Write #lngFichero, _
"Jon Estarriaga", #7/7/2004#, -105.85
Write #lngFichero, _
"Andrea Olazbal", #2/14/1995#, 128.36
Close #lngFichero
lngFichero = FreeFile
' Ahora vamos a leer el fichero con Input
Open strFichero For Input As #lngFichero
Debug.Print
Debug.Print "Datos ledos con Input"
' Para ello deberemos asignrselos a sus variables
Do While Not EOF(lngFichero)
' Lee la lnea y se la asigna a las variables
Input #lngFichero, _
strCliente, datAperturaCuenta, curSaldoCuenta
Debug.Print strCliente, _
datAperturaCuenta, _
curSaldoCuenta
Loop
Close #lngFichero
End Sub
Al ejecutar este cdigo, nos mostrar en la ventana [Inmediato] lo siguiente:
Fichero C:\Curso_VBA\Captulo_18\ClientesBanco.dat
Instruccin Get
La instruccin Get, lee datos de un archivo abierto y asigna esos datos a una variable.
Su sintaxis es:
Get #NmeroArchivo,[NumeroRegistro],Variable
La variable suele ser una variable Type de tipo registro.
Open "Clientes.dat" For Random As #lngFichero _
Len = Len(Datos)
Get #lngFichero, 2, Datos
Close #lngFichero
Tras esta instruccin, se habrn pasado los datos del registro N 2 a la variable Datos.
El numero de registro es opcional
Instruccin Put
La instruccin Put, escribe datos en un archivo abierto , volcndolos desde una variable.
Su sintaxis es:
Put #NmeroArchivo,[NumeroRegistro],Variable
La variable suele ser una variable Type de tipo registro.
Si quisiramos grabar los datos contenidos en la variable Datos, en el registro N 2 de la
tabla Clientes.dat, podramos hacerlo as:
Open "Clientes.dat" For Random As #lngFichero _
Len = Len(Datos)
Put #lngFichero, 2, Datos
Close #lngFichero
El procedimiento PruebaFicheroRandom graba 5 registros en Clientes.dat y
luego los lee, mostrando los datos en la ventana de depuracin:
Datos As ClienteBanco, _
Optional ByVal Posicion As Long = -1)
On Error GoTo HayError
Dim lngFichero As Long
Dim strFichero As String
lngFichero = FreeFile
Open "Clientes.dat" For Random As #lngFichero _
Len = Len(Datos)
'Grabamos los datos
If Posicion >= 0 Then
Put #lngFichero, Posicion, Datos
Else
Put #lngFichero, , Datos
End If
Close #lngFichero
Salir:
Exit Sub
HayError:
MsgBox "Error al grabar " & strFichero _
& vbCrLf _
& Err.Description
Resume Salir
End Sub
lngFichero = FreeFile
Open "Clientes.dat" For Random As #lngFichero Len =
Len(Datos)
'Leemos los datos
If Posicion >= 0 Then
Get #lngFichero, Posicion, Datos
Else
Get #lngFichero, , Datos
End If
Close #lngFichero
Salir:
Exit Sub
HayError:
MsgBox "Error al leer " & strFichero _
& vbCrLf _
& Err.Description
Resume Salir
End Sub
Tras ejecutarse este cdigo, mostrar algo as como:
Funcin Seek
La instruccin Seek, devuelve un valor del tipo Long que nos indica el nmero de registro
de la posicin actual dentro de un fichero abierto.
Su sintaxis es:
Seek(#NmeroArchivo)
VBA - Access
Entrega 19
Eduardo Olaz
19 - 2
Fichero Schema.ini.
Este archivo es un archivo especial, que contiene una descripcin de la estructura, de un
fichero de texto organizado como una tabla de datos, proporcionando informacin sobre:
El formato que tiene el archivo.
Los nombres, la longitud y tipos los tipos de datos de los campos.
El juego de caracteres que se ha utilizado.
Informacin sobre las conversiones especiales de los tipos de datos.
El fichero Schema.ini debe encontrarse en la misma carpeta donde estar ubicado el
fichero de datos.
La informacin contenida en un fichero Schema.ini, sobre los formatos de datos, tiene
prioridad frente a la configuracin predefinida en el registro de Windows.
Para que VBA pueda manejarlo de forma adecuada, el nombre de este fichero debe
mantenerse, por lo que deber usarse siempre como Schema.ini.
Como veremos, Schema.ini es un tipo especial de los ficheros ini de configuracin.
El tipo genrico de ficheros ini ser analizado en un punto ms avanzado de esta misma
entrega.
End Sub
No se preocupe demasiado si no entiende ese cdigo.
Lo que hace es exportar el contenido de la tabla Alumnos de la base de datos Datos.mdb a
la tabla Alumnos.txt.
Veamos ahora qu significa cada una de las lneas del fichero Schema.ini.
Ya hemos indicado que la primera lnea, [Alumnos.txt] indica el nombre del fichero al
que se va a exportar.
La segunda lnea ColNameHeader=False indica que la tabla no va a contener los
nombres de los campos.
Si hubiramos puesto: ColNameHeader=True, el resultado de exportar la tabla sera:
"idAlumno","Nombre","Apellido1","Apellido2","FechaNacimiento","Poblacion","idCurso"
1 Antonio Martnez Ziga 02/10/1984 Pamplona 35
2 Pedro Iturralde Etxegrate 03/01/1985 Tudela 14
3 Marta Valduz Goikoa 27/07/1985 Tafalla 10
4 Enrique Viana Vergara 03/09/1984 Pamplona 10
La tercera lnea Format= FixedLength hace que los datos se exporten con un formato
de longitud variable. Los posibles valores que puede tomar esta clave son:
Delimited (*) Hace que los campos se delimiten por asteriscos. Se puede utilizar
cualquier carcter, excepto las comillas dobles (").
Por ejemplo (;) hara que el delimitador fuera un punto y coma.
Por ello sera aconsejable, en su lugar, la utilizacin del punto y coma Format=
Delimited (;)como delimitador de campos.
La cuarta lnea MaxScanRows=25 le indica al motor de la base de datos, el nmero de
filas que debe examinar en la tabla, para determinar el tipo de dato que contiene cada
campo. Si ponemos MaxScanRows=0 le estamos pidiendo que examine toda la tabla.
La quinta lnea CharacterSet=OEM define el conjunto de caracteres que se va a utilizar.
Esto es importante, dependiendo de sobre qu plataforma se va a exportar.
Si abriramos el fichero con un editor Windows, por ejemplo con el Bloc de Notas, veramos
el fichero de forma incorrecta.
Vamos que las vocales acentuadas se ven de forma incorrecta, lo mismo que el carcter .
Si abrimos ahora el mismo fichero con el Bloc de Notas, lo veramos de forma correcta.
Desde la versin 2000 Access, puede trabajar con caracteres Unicode, que necesitan 2
Bytes para el almacenamiento de cada carcter. Esta es la razn por la que, si no se usa la
opcin Compresin Unicode en el diseo de las tablas, stas llegan a ocupar casi el doble
de espacio que con las tablas Access de la versin 97 anteriores.
Las siguientes lneas empiezan con la slaba Col seguida de un nmero.
Col1 Col2 . . . Col7
En ellas se especifica qu campos van a ser exportados de la tabla, y en qu orden.
Adems se indica el tipo de dato y la anchura de la columna en que se va a exportar.
Es importante que la anchura de la columna sea la misma que la del campo en la tabla, ya
que en caso contrario se podran cortar su contenido.
Indicar los campos y el orden en que se van a exportar, es opcional para los ficheros con
separador de campos y obligatorio para los ficheros con campos de longitud fija.
El siguiente fichero Schema.ini exportar los campos de la tabla a Alumnos.txt
Incluir una cabecera con los nombres de los campos
Como delimitador de campos usar el carcter punto y coma (;).
Har una exploracin previa de toda la tabla para averiguar los tipos de los campos.
En la exportacin usara el juego de caracteres ANSI.
[Alumnos.txt]
ColNameHeader=True
Format=Delimited(;)
MaxScanRows=0
CharacterSet=Ansi
Vemos que, adems del delimitador de campos, los campos tipo texto estn contenidos
entre comillas.
En cambio ni los valores numricos ni los del tipo Fecha/Hora, lo hacen.
Las posibilidades de los ficheros Eschema.ini, llegan mucho ms lejos que lo expuesto
hasta ahora.
Por ejemplo hay todo un juego de posibilidades para dar formato a los campos, por ejemplo
para mostrar los nmeros con decimales las fechas con un formato especfico.
En la exportacin anterior vemos que la fecha de nacimiento la ha exportado con el formato
" dd/mm/yyyy hh:nn:ss "
Probablemente nos interesar que slo aparezcan los datos de fecha.
Esto se podra hacer con la siguiente opcin de formato:
DateTimeFormat = dd/mm/yyyy
El resultado sera
A la hora de definir las columnas, un fichero con campos de anchura fija, se debe especificar
el tipo de campo y la anchura que debe mostrar. Los tipos de campo que podemos usar son:
Byte, Bit
Currency
DateTime, Date
Double, Float
Long
Memo, LongChar
Short, Integer
Single
Text, Char
1 -128,60 9 - 128,60
2 -128,60 10 128,60 -
3 128,60- 11 128,60-
4 (128,60) 12 -128,60
5 -128,60 13 128,60-
6 128,60- 14 ( 128,6)
7 128,60- 15 (128,60 )
0 128,60 2 128,60
1 128,60 3 128,60
He aadido nuevos datos a la tabla original para comprobar los efectos del formato.
[Alumnos.txt]
ColNameHeader=True
Format=Delimited(;)
MaxScanRows=0
CharacterSet=Ansi
[Profesores.txt]
ColNameHeader=True
Format=Delimited(;)
MaxScanRows=0
CharacterSet=Ansi
strcarpeta = CurrentProject.Path
strBaseDatos = strcarpeta & "\Datos.mdb"
strTabla = "Alumnos.txt"
False, _
False, _
"Text;")
' Carga el recordset desde la tabla de texto
Set rst = db.OpenRecordset(strTabla)
With rst
' Mostramos los registros
Do While Not .EOF
For m = 0 To .Fields.Count - 1
' Mostramos los campos
Debug.Print .Fields(m),
Next m
Debug.Print
' Vamos al siguiente registro
.MoveNext
Loop
End With
rst.Close
Set rst = Nothing
db.Close
Set db = Nothing
End Sub
En mi ordenador el cdigo anterior imprime lo siguiente:
6 25/05/1983 Huarte 5 1110 0,97
1 02/10/1984 Pamplona 35 256,5 1,66
2 03/01/1985 Tudela 14 128,25 1,85
3 27/07/1985 Tafalla 10 250 1,75
4 03/09/1984 Pamplona 10 110 1,8
5 24/12/1983 Villava 1 -1253,35 1,55
Este cdigo utiliza la librera de DAO. Os recuerdo lo comentado en la pgina 3 sobre
activar la referencia a la librera correspondiente.
Podemos hacerlo de forma semejante usando la librera de ADO en vez de la de DAO.
Sub AbrirFicheroDeTextoADO()
Dim cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim strcarpeta As String
Dim strTabla As String
Dim m As Long, n As Long
strcarpeta = CurrentProject.Path
strTabla = "Alumnos.txt"
[email protected] Eduardo Olaz
Entrega 19 Trabajar con ficheros III 19 - 13
Tome el cdigo como referencia cuando ya conozca estos objetos, o como plantilla si
necesita cargar datos, por cdigo, desde un fichero de texto.
Ficheros ini
En la poca del Windows de 16 bits, (Windows 3.x) los programadores, para establecer una
serie de valores de inicializacin, utilizbamos ficheros ini.
Un fichero ini, del que el fichero Schema.ini es un caso particular, consta de una serie de
secciones encabezadas por su nombre, entre parntesis cuadrados (corchetes), y seguidas
de una serie de claves, con sus valores asignados. Recordemos un fichero .
[Alumnos.txt] Seccin
Clave ColNameHeader=True Valor
Clave Format=Delimited(;) Valor
Otro ejemplo:
[Inicio]
UltimoUsuario=Eduardo
FechaDesconexion=03/09/2005
[Datos]
idAlumno=123
idClase=25
Nos indica una serie de variables y los valores que han ido tomando.
lngDirectorio = conlngCadena
lngPath = GetWindowsDirectory( _
strDirectorio, _
lngDirectorio)
DameCarpetaWindows = Left$( _
strDirectorio, _
lngPath)
End Function
A la funcin GetWindowsDirectory le pasamos la cadena strDirectorio y se
almacenar en ella la ruta de la carpeta de Windows.
La variable lngPath recoge la longitud de la cadena obtenida, por lo que si hacemos
Left$(strDirectorio, lngPath)
Obtendremos la ruta completa de Windows.
Si en mi ordenador escribo Debug.Print DameCarpetaWindows()
Me mostrar C:\WINDOWS, que es donde efectivamente he instalado Windows en mi PC.
http://www.ciberteca.net/articulos/programacion/win32apis/ejemplo.asp
http://www.mentalis.org/index2.shtml La muy recomendable pgina de AllApi.net.
http://mech.math.msu.su/~vfnik/WinApi/index.html Otra pgina clsica muy interesante.
http://custom.programming-in.net/
http://www.mvps.org/access/api/
http://vbnet.mvps.org/index.html?code/fileapi/
' GetPrivateProfileString _
Recupera una cadena en un fichero de inicializacin
Declare Function GetPrivateProfileString _
Lib "kernel32.dll" _
Alias "GetPrivateProfileStringA" ( _
ByVal lpApplicationName As String, _
ByVal lpKeyName As String, _
ByVal lpDefault As String, _
ByVal lpReturnedString As String, _
ByVal nSize As Long, _
ByVal lpFileName As String _
) As Long
' lpApplicationName _
Seccin en la que se va a buscar la Clave.
' lpKeyName _
Nombre de la clave a buscar.
' lpDefault _
Valor por defecto a devolver _
si no se encuentra la clave.
' lpReturnedString _
Cadena en la que escribir el resultado. _
Debe tener como mnimo la longitud de nSize.
' lpFileName _
Nombre del archivo de inicializacin.
' GetPrivateProfileInt _
Recupera un entero de un fichero de inicializacin
Declare Function GetPrivateProfileInt _
Lib "kernel32.dll" _
Alias "GetPrivateProfileIntA" ( _
ByVal lpApplicationName As String, _
ByVal lpKeyName As String, _
ByVal nDefault As Long, _
ByVal lpFileName As String _
) As Long
' nDefault _
Valor por defecto a devolver _
si no se encuentra la clave.
' GetPrivateProfileSection _
Recupera una lista con los nombres de todas las claves _
de una Seccin y sus valores.
Declare Function GetPrivateProfileSection _
Lib "kernel32" _
Alias "GetPrivateProfileSectionA" ( _
ByVal lpApplicationName As String, _
ByVal lpReturnedString As String, _
ByVal nSize As Long, _
ByVal lpFileName As String _
) As Long
' lpReturnedString _
Lista en la que se cargan las claves y sus valores. _
Cada cadena est separada por un valor Nulo _
Al final de la lista se encontrarn dos valores nulos.
' nSize _
Tamao asignado a lpReturnedString
& Err.Description, _
vbCritical + vbOKOnly, _
" Error no controlado en la funcin " _
& "FicheroValido()"
End If
Resume Salida
End Function
Vamos a probar el procedimiento, para lo que en la ventana de depuracin escribimos:
EscribeClaveINI "Prueba.ini", "Mi Seccin", "Hora", CStr(Time)
Si abrimos el fichero con el Bloc de notas veremos que contiene lo que en principio
esperbamos:
Carpeta = CarpetaValida(Carpeta)
FicheroINI= FicheroValido(FicheroINI, Carpeta)
Seccion, _
Clave, _
ValorDefecto, _
strDevuelto, _
Len(strDevuelto), _
Carpeta & FicheroINI)
' Devolvemos el dato
' El nmero de caracteres ledos estar en lngRetornado
' La cadena leda en strDevuelto
LeeCadenaClaveINI = Left(strDevuelto, lngRetornado)
End Function
Con el cdigo anterior, si escribimos la sentencia
LeeCadenaClaveINI("Prueba.ini", "Usuario", "Nombre")
nos devolver la cadena Eduardo. Con lo que habremos ledo una cadena de tipo String.
Si supiramos que determinada clave contiene un valor entero, podramos utilizar la funcin
API , GetPrivateProfileInt que es ms sencilla de manejar, ya que la propia funcin
devolvera el entero solicitado en formato Long.
Antes que nada, vamos a grabar en nuestro fichero ini, un valor entero Long.
Para ello utilizaremos el procedimiento creado con anterioridad EscribeClaveINI.
Supongamos que queremos grabar el valor 123456., como valor de la Clave idUsuario
en la seccin Usuario de nuestro fichero ini.
Llamaramos a nuestro procedimiento EscribeClaveINI de la siguiente forma:
EscribeClaveINI "Prueba.ini", _
"Usuario", _
"idUsuario", _
CStr(12345)
Carpeta = CarpetaValida(Carpeta)
FicheroINI= FicheroValido(FicheroINI, Carpeta)
Carpeta = CarpetaValida(Carpeta)
FicheroINI = FicheroValido(FicheroINI, Carpeta)
lngDevuelto = GetPrivateProfileSectionNames( _
strContenedor, _
Len(strContenedor), _
Carpeta & FicheroINI)
' Si el valor devuelto fuera 0 sera porque _
no ha encontrado secciones en el fichero _
o no ha encontrado el fichero
If Not CBool(lngDevuelto) Then
' Preparamos un array sin datos
ReDim aSecciones(0 To 0)
aSecciones(0) = ""
Else
strSecciones = Left(strContenedor, lngDevuelto - 1)
' El separador es el carcter Chr$(0)
' Split devuelve un Array _
desde una cadena con separadores
aSecciones = Split(strSecciones, Chr$(0))
End If
' Devuelve el array
SeccionesINI = aSecciones
Salida:
SeccionesINI = aSecciones
Exit Function
HayError:
MsgBox "Se ha producido el error " _
& Format(Err.Number, "#,##0") _
& vbCrLf _
& Err.Description, _
vbCritical + vbOKOnly, _
" Error no controlado en la funcin " _
& "SeccionesINI()"
ReDim aSecciones(0 To 0)
aSecciones(0) = ""
Resume Salida
End Function
Si efectuamos una llamada a la funcin mediante SeccionesINI("Prueba.ini")(0)
en mi ordenador, considerando que antes hemos creado esas secciones, devuelve el
nombre de la seccin "Usuario"
Si Hacemos SeccionesINI("Prueba.ini")(1), devuelve "Mi Seccin"
Fijmonos en que la funcin SeccionesINI devuelve un Array, y por tanto se le puede
llamar pasndole, adems de los parmetros propios de la misma, el ndice del Array
devuelto.
Podemos generar un procedimiento que muestre los nombres de las secciones de un fichero
del tipo ini.
Public Sub MuestraSeccionesIni( _
ByVal FicheroINI As String, _
Optional ByVal Carpeta As String)
Dim aSecciones As Variant
Dim i As Long
Carpeta = CarpetaValida(Carpeta)
aSecciones = SeccionesINI(FicheroINI, Carpeta)
Carpeta = CarpetaValida(Carpeta)
FicheroINI = FicheroValido(FicheroINI)
lngDevuelto = GetPrivateProfileSection( _
Seccion, _
strContenedor, _
lngLongitud, _
Carpeta & FicheroINI)
' La cadena con los datos separados por Chr$(0) _
est en los primeros lngDevuelto - 1 Caracteres _
de strContenedor
strContenedor = Left(strContenedor, lngDevuelto - 1)
' Llamamos a la funcin que extrae los datos _
desde la cadena
LeeSeccionINI = DescomponerCadenaConNulos( _
strContenedor)
End Function
La funcin auxiliar DescomponerCadenaConNulos descompone los datos de una
cadena del tipo Clave1=Dato1 Clave2=Dato2 Clave3=Dato3 . . .
ClaveN=DatoN, en la que los sucesivos pares de Clave_i=Dato_i, estn separados
por el carcter ASCII de ndice = 0 y los pasa a un array de 2 dimensiones.
Veamos cmo podemos hacer que esta funcin devuelva un array ms manejable.
Public Function DescomponerCadenaConNulos( _
ByVal Cadena As String _
) As Variant
' Esta funcin recibe una cadena _
con los datos separados por nulos _
y devuelve un array String del tipo _
aDatos(0 to n-1, 0 to 1)
Dim lngLongitud As Long
Dim lngDatos As Long
Dim strNulo As String
Dim aCadenas As Variant
Dim aResultado() As String
Dim aLinea As Variant
Dim i As Long
strNulo = Chr(0)
lngLongitud = Len(Cadena)
lngDatos = (UBound(aCadenas) + 1)
ReDim aResultado(0 To lngDatos, 0 To 1)
For i = 0 To lngDatos - 1
aLinea = Split(aCadenas(i), "=")
aResultado(i, 0) = aLinea(0)
aResultado(i, 1) = aLinea(1)
Next i
DescomponerCadenaConNulos = aResultado
End Function
Lectura de una seccin
Vamos a probar estas 2 ltimas funciones.
Para ello utilizaremos el fichero Schema.ini que habamos construido para usarlo en la
exportacin importacin de datos, en un punto anterior de esta entrega.
No debemos olvidar que slo es un caso muy especial de fichero ini.
En este momento, en la carpeta de mi ordenador, el fichero Schema.ini contiene las
siguientes lneas:
strSeccion = "Alumnos.txt"
' Llamamos a la funcin LeeSeccionINI
aDatos = LeeSeccionINI("Schema.ini", strSeccion)
' Muestra los datos en la ventana Inmediato
Debug.Print
Debug.Print "Contenido del fichero Schema.ini"
Debug.Print "Seccin: [" & strSeccion & "]"
Debug.Print "Clave", Tab(conTabulacion); "Valor"
Debug.Print String(conTabulacion + 20, "-")
For i = 0 To UBound(aDatos, 1)
Debug.Print aDatos(i, 0),
Debug.Print Tab(conTabulacion); aDatos(i, 1)
Next i
End Sub
Tras ejecutar este procedimiento nos mostrar lo siguiente en la ventana de depuracin o
Inmediato.
Que, como podemos comprobar, efectivamente se corresponde con los datos contenidos en
el fichero Schema.ini.
Escritura de una seccin completa
Para poder escribir una seccin completa, usaremos la funcin API
WritePrivateProfileSection.
Recordemos la declaracin de esta funcin:
Declare Function WritePrivateProfileSection _
Lib "kernel32" _
Alias "WritePrivateProfileSectionA" ( _
ByVal lpApplicationName As String, _
ByVal lpString As String, _
ByVal lpFileName As String _
) As Long
lpApplicationName Seccin en la que vamos a escribir las Claves y Valores
lpString Lista que contiene las claves y sus Valores.
lpFileName es el fichero en el que se va a escribir los datos.
Al procedimiento a crear lo vamos a llamar EscribeSeccionINI.
El parmetro Datos, contendr un array semejante al devuelto por la funcin anterior
LeeSeccionINI. Por tanto ser de dos dimensiones conteniendo datos de tipo String.
Crearemos tambin la funcin ConstruyeCadenaConNulos que har la funcin inversa
a la que hace la funcin anterior DescomponerCadenaConNulos; es decir
ConstruyeCadenaConNulos extraer los datos del array Datos y los aadir a una
cadena del tipo Clave_i=Valor_i, teniendo como separador el carcter ASCII 0.
Al final de la cadena pondr 2 caracteres Ascii 0.
strNulo = Chr(0)
Call EscribeSeccionINI( _
"Prueba.ini", strSeccion, aDatos)
End Sub
El resultado ser
El Registro de Windows.
Hasta la aparicin de Windows 95, la forma habitual de almacenar los parmetros de
configuracin de una aplicacin, era la utilizacin de ficheros ini, tal y como hemos visto en
los puntos anteriores de esta entrega.
Desde la versin de Windows 95, tenemos a nuestro alcance una herramienta mucho ms
potente, que evita adems la proliferacin de ficheros ini, por todas las carpetas de las
aplicaciones instaladas. Esta herramienta es el fichero Regedit.exe.
Este programa nos permite editar el Registro de Configuraciones de Windows, conocido
tambin por su nombre reducido El registro.
Normalmente suele hallarse en la carpeta C:\Windows.
El registro de Windows se divide en varios bloques principales.
Mi versin actual de Windows (XP Profesional - Service Pack 2) tiene los siguientes bloques:
Cada uno de los bloques almacena los parmetros de las diversas aplicaciones instaladas, y
por supuesto de muchos de los virus, troyanos o programas SpyWare que hayan podido
infectar nuestro ordenador.
Para poder leer y escribir en esas secciones debemos utilizar una serie de procedimientos
API que nos suministra el propio Windows.
La utilizacin de estos procedimientos API la veremos en una seccin de esta publicacin en
la que profundizaremos en esta y otras posibilidades no contempladas por el propio VBA.
Instruccin SaveSetting
Actualiza o crea una entrada para una aplicacin en el registro de configuracin de
Windows.
Su sintaxis es
SaveSetting NombreAplicacin, seccin, clave, valor
NombreAplicacin es el nombre de la subcarpeta que queremos poner colgando de
VB and VBA Program Settings\ y que normalmente tiene como nombre el de la
propia aplicacin.
seccin es el nombre de la seccin donde queremos grabar el valor de la clave.
valor es el valor, o la expresin que devuelve un valor a grabar.
Supongamos que en nuestro programa Gestin De Socios queremos almacenar
dentro del registro de Windows los valores 1011 como ltimo socio, y 3 de septiembre
de 2005 como fecha de ltima utilizacin.
Para ello podemos crear el procedimiento GrabarDatosDeSalida al que llamaremos
inmediatamente antes de cerrar el programa, pasndole los parmetros adecuados.
Podra ser algo tan simple como esto:
Public Sub GrabarDatosDeSalida( _
ByVal Clave As String, _
ByVal Valor As Variant)
Funcin GetSetting
Devuelve el valor de una clave del registro.
Su sintaxis es
GetSetting NombreAplicacin, seccin, clave[,por defecto]
Los parmetros NombreAplicacin, seccin y clave, son los mismos que los
explicados en la Instruccin SaveSetting.
El parmetro opcional por defecto, permite definir el valor que devolvera la funcin, si no se
encontrara la clave en el registro. Si se omitiera equivaldra a poner una cadena de longitud
cero.
Una vez grabados los datos en el punto anterior, al arrancar la aplicacin podramos
ejecutar un procedimiento semejante al siguiente, para recuperar los valores del registro.
Public Sub CargarDatosDeEntrada()
Dim datUltimaFecha As Date
Dim strUltimaFecha As String
Dim lngSocio As Long
Funcin GetAllSettings
Devuelve el valor de todas las claves de una seccin del registro.
Su sintaxis es
GetSetting NombreAplicacin, seccin
Los parmetros NombreAplicacin, seccin y clave, son los mismos que los
explicados en la Instruccin SaveSetting.
Las claves son guardadas en una variable de tipo Array de dos dimensiones basada en
cero, declarada inicialmente como del tipo Variant.
Una vez cargados los datos en el array, para poder acceder a sus valores, podremos utilizar
un bucle que vaya desde el ndice cero, hasta el valor del ndice mayor (funcin UBound).
Usando como valor el 0 en el segundo ndice podremos obtener los nombres de las claves.
Si utilizamos como para el segundo ndice el 1, obtendremos los valores de las claves.
Veamos un ejemplo que aclarar este galimatas.
Public Sub MostrarDatosRegistro()
Instruccin DeleteSetting
Elimina una seccin completa o una clave en el registro de configuracin de Windows.
Su sintaxis es
DeleteSetting NombreAplicacin, seccin[, clave]
Los parmetros son los mismos que los de los procedimientos anteriores.
El nombre de la clave es opcional, si no se pusiera se borrara la seccin completa.
Por ejemplo
DeleteSetting "Gestin De Socios", _
"Valores finales", _
"Fecha Utilizacin"
Borrara la clave "Fecha Utilizacin".
Si hubiramos ejecutado
DeleteSetting "Gestin De Socios", _
"Valores finales"
Se borrara por completo la seccin "Valores finales".
VBA - Access
Entrega 20
Eduardo Olaz
20 - 2
Como veremos, la gran ventaja que tienen las propiedades es que permite filtrar los datos
que van a manejarse pudiendo evitarse la asignacin de datos incorrectos y teniendo la
posibilidad de reaccionar y avisar al usuario si se ha cometido una incorreccin..
Una parte de los datos se guardan en el propio objeto sin que sea posible acceder a ellos
directamente. Slo es posible manejarlos mediante el uso de las propiedades, teniendo que
sujetarse a los filtros que incluya en ellas el programador.
A esta capacidad de proteger y ocultar los datos bsicos del objeto es a lo que se llama
Encapsulacin.
Una clase podemos abordarla desde dos puntos de vista:
Como programador de la clase
Como usuario de la clase
El programador de la clase es el que define qu propiedades va a tener, de qu tipo y cmo
se va a comportar.
El usuario de la clase, ya sea el que la ha diseado u otra persona, va a utilizarla para crear
objetos que le faciliten una serie de tareas de programacin asignando valores concretos a
las propiedades y utilizando sus procedimientos, llamados mtodos de la clase.
Propiedades
Para estudiar qu son las propiedades, veamos la clase CPersona que vimos en el
captulo 7 (he eliminado las lneas de control de fecha, de la clase original, para ver mejor el
ejemplo didctico).
Os recuerdo que para crear una clase, usaremos la opcin de men [Insertar] > [Mdulo de
clase], y en este caso, pondremos a la propiedad Name de la ventana Propiedades el valor
CPersona.
Option Explicit
End Property
.FechaNacimiento = #12/24/1880#
Vemos que si la fecha es normal el cdigo se ejecuta como antes.
Recordemos que la lnea del procedimiento de prueba:
Debug.Print "Fecha de nacimiento: " _
& .FechaNacimiento
Llama tambin a la propiedad FechaNacimiento.
En el primer caso que hemos probado, esa propiedad la devolva directamente la variable de
tipo Date, pero en el segundo caso, la variable ha desaparecido, habiendo sido sustituida
por los dos procedimientos FechaNacimiento.
Fijmonos en el encabezado de los mismos:
Public Property Let FechaNacimiento(ByVal Fecha As Date)
y
Public Property Get FechaNacimiento() As Date
Vemos que el primero, Property Let, es equivalente a un procedimiento Sub, ya que no
devuelve ningn valor, y el segundo, Property Get, es equivalente a un procedimiento
Function, ya que devuelve un valor, en este caso del tipo Date.
Adems vemos que los dos procedimientos Property, son pblicos.
Otra cosa que llama la atencin es que tienen el mismo nombre FechaNacimiento.
El primero, Property Let, sirve para asignar un valor, pasado como parmetro, a una
variable, normalment de tipo Private, y por tanto inaccesible (encapsulada).
El segundo, Property Get, sirve para devolver el valor de una variable, en esta clase la
variable es m_datFechaNacimiento.
En ambos casos la variable a la que se tiene acceso es de tipo privado.
Fjese en la notacin que estoy empleando:
Pongo primero el prefijo m_ para indicar que es una variable privada, con validez a
nivel del mdulo de clase.
A continuacin pongo el prefijo dat, para indicar que es de tipo Date.
La variable acaba con el nombre humanizado de la misma FechaNacimiento.
El procedimiento Property Let, antes de asignar un valor a la variable comprueba que
est dentro del rango establecido; en este caso entre la fecha de hoy y la de hace 100 aos.
Si supera este filtro comprueba que sea diferente a la fecha almacenada en la variable
m_datFechaNacimiento; caso de serlo le asigna el nuevo valor de Fecha.
Veremos que esto ltimo tiene su importancia si queremos generar un evento cuando
cambie en un objeto el valor de una propiedad. Adems no tiene sentido asignar un valor a
una variable igual al que ya posee.
En resumidas cuentas, hemos creado dos procedimientos Property:
Uno de Lectura, Property Get, que suministra el valor de una variable interna de tipo
privado. Su forma de escritura es equivalente a la de una funcin.
Un segundo de Escritura, Property Let, que graba un valor en una variable interna de
tipo privado. Su forma de escritura es equivalente a la de un procedimiento.
Existe un tercer tipo de procedimiento property que se utiliza para grabar propiedades de
tipo Objeto. Es el Property Set.
Este podra ser un ejemplo de uso:
Public Property Set Objeto(NuevoObjeto As Object)
Set m_Objeto = NuevoObjeto
End Property
La propiedad FechaNacimiento, del ejemplo decimos que es de Lectura / Escritura, ya
que tiene los dos procedimientos Property Get y Property Let.
Si quisiramos crear una propiedad de solo lectura, por ejemplo que devolviera el nmero
de registros existentes en una tabla, crearamos slo el procedimiento Property Get.
Igualmente si quisiramos una propiedad de solo escritura, aunque no hay muchos casos
que se me ocurran que lo necesiten, escribiramos slo el procedimiento Property Let.
A la hora de crear una clase, lo que se suele hacer es definir los Atributos de la clase.
Para todos aquellos atributos sobre los que se quiere tener un control, ya sea porque
se quieren controlar los rangos de entrada o salida
se vayan a generar eventos cuando cambien, vayan a cambiar o alcancen
determinados valores
se quiera hacer que sean slo de Lectura o solo de Escritura
el mtodo a seguir es el siguiente
Se crea una variable de alcance Private para cada uno de los atributos
Se genera un Property Let para la asignacin de valores, o un Property
Set si el dato puede admitir algn tipo de objeto.
De forma paralela se genera un Property Get que devolver el dato de la
variable fuera del objeto.
En el caso de las funciones (mtodos) Edad y NombreCompleto, podramos haberlas
definido como propiedades de slo lectura, de la siguiente manera:
Public Property Get Edad() As Long
Edad = (Date - FechaNacimiento) / 365.2425
End Property
Despus de hacerlo
Vemos que ha cambiado el smbolo que aparece delante, tanto de Edad como de
NombreCompleto, y ha pasado de ser el smbolo de un Mtodo a otro que representa
una Propiedad.
Mtodos de clase
A las funciones y procedimientos pblicos de una clase se les llama Mtodos de clase.
En el caso de la clase CPersona, tenemos dos mtodos de clase, que devuelven valores,
es decir son del tipo Function. Estos mtodos son Edad, que devuelve un nmero del
tipo Long y NombreCompleto, que devuelve una cadena String.
Podran haberse creado mtodos que no devolvieran ningn valor, es decir del tipo Sub.
Todos estos mtodos pblicos podran, a su vez, haber utilizado para su ejecucin interna
otros mtodos privados de la propia clase, que no fuesen visibles desde fuera de la misma.
Como ya hemos dicho, a la capacidad de ocultar determinados atributos y procedimientos
de la clase, es a lo que se llama Encapsulacin.
que tenga, por ejemplo mtodos como Anterior y Siguiente, Derecha e Izquierda, que
devuelvan objetos de la misma clase.
Vamos crear una clase a la que llamaremos CIndividuo.
Esta clase va a ser muy sencilla, y slo va a tener una propiedad llamada Nombre que
devolver un String y otra propiedad llamada Pareja que va a devolver un objeto del
tipo CPareja.
Vamos a ello. Como siempre creamos un nuevo mdulo de clase al que pondremos por
nombre CIndividuo.
Nota:
Lo de poner una C delante del nombre en cristiano de la clase es una convencin
de nombres que se haba extendido en el mundillo de Visual Basic.
Ahora, en Vb.Net parece que la forma a adoptar es poner delante el prefijo cls.
Su cdigo sera el siguiente.
Option Explicit
Para probar esta clase vamos a escribir una historia cotidiana en la que se entremezclan
tres individuos.
Antonio y Mara se conocen desde hace tiempo y como el roce genera el cario,
acabaron hacindose novios.
Durante una temporada mantienen una relacin estable y feliz.
Un buen da Mara conoci a Juan. La atraccin mutua fue instantnea y fulgurante,
lo que les llev a vivir un apasionado romance.
A todo esto Antonio no se entera de nada.
Qu tenemos aqu?
Tenemos tres objetos de la clase CIndividuo, de los que la propiedad Nombre es
Mara, Antonio y Juan.
Pido disculpas por llamar objetos a personas, aunque algunas se lo lleguen a merecer.
Vemos que al principio Antonio es la Pareja de Mara y Mara lo es a su vez de
Antonio.
En un momento dado, la Pareja de Mara pasa a ser Juan, y la de Juan Mara.
Antonio sigue creyendo que su Pareja sigue siendo Mara.
Para representar esta historia, creamos el procedimiento HistoriaDeTres().
Public Sub HistoriaDeTres()
Dim Hombre As New CIndividuo
Dim Mujer As New CIndividuo
Dim UnTercero As New CIndividuo
Debug.Print Hombre.Nombre _
& " lleva mucho tiempo saliendo con " _
& Mujer.Nombre
Debug.Print "La pareja de " & Hombre.Nombre _
& " es: " & Hombre.Pareja.Nombre
Debug.Print "La pareja de " & Mujer.Nombre _
& " es: " & Mujer.Pareja.Nombre
Debug.Print Mujer.Nombre _
& " conoce a " & UnTercero.Nombre _
& " y ..."
Set Mujer.Pareja = UnTercero
Set UnTercero.Pareja = Mujer
Nodo_3
r da
ie
qu
Iz
_1
. or
d o e ri
No nt
.A
o _3
N od Valor
a
Nodo_1 No
rd do
ie _4
z qu .A
nt
.I r No er
_0 io do io
do t er _1 r
No An .D
er
1. ec
d o_ ha
No Valor
Nodo_0 No
Nodo_4
do
_2
.A
nt
No er
do io
_0 r
.D
er
ec
Valor ha Valor
Nodo_2
Valor
Sera equivalente a un rbol con dos ramas principales, de una de las cuales a su vez
parten otras dos ramas.
Vamos a crear una clase a la que llamaremos CNodoArbolSimple.
Primero insertaremos un mdulo de clase con el nombre CNodoArbolSimple.
En las primeras lneas definimos tres variables privadas del tipo CNodoArbolSimple, que
nos servirn para hacer referencia a los nodos Anterior, Izquierda y Derecha.
Tambin definiremos una variable de tipo Variant que nos servir para almacenar al
Valor asignado al nodo.
Y ahora fijmonos en la propiedad Valor.
Por qu he puesto una propiedad Property Get, otra Property Let y una tercera
Property Set?.
La razn es muy sencilla.
Al manejar Valor una variable de tipo Variant, puede ocurrir que sta haga referencia a un
objeto.
No se puede asignar un objeto de la forma m_varValor = NuevoValor, como lo hace
Property Let, ya que dara un error.
Es necesario hacer Set m_varValor = NuevoValor de lo que se encarga
Property Set.
Vamos a hora a definir la propiedad Valor para almacenar datos en el nodo:
Vamos a probar este esbozo de clase para comprobar si lo dicho funciona correctamente.
En un mdulo estndar escribimos:
Public Sub PruebaNodo()
Dim Nodo As New CNodoArbolSimple
Dim col As New Collection
col.Add "Lunes"
col.Add "Martes"
col.Add "Mircoles"
Nodo.Valor = 1000
Debug.Print Nodo.Valor
Option Explicit
Private m_varValor As Variant
Private m_strNombre As String
Private m_ndoAnterior As CNodoArbolSimple
Private m_ndoIzquierda As CNodoArbolSimple
Private m_ndoDerecha As CNodoArbolSimple
End If
End Property
With Nodo
.Nombre = "Nodo_0"
.Valor = 0
Set .Izquierda = New CNodoArbolSimple
Set .Derecha = New CNodoArbolSimple
End With
' Aado el nodo con sus datos y la clave "0" _
a la coleccin
Nodos.Add Nodo, "0"
With Nodo.Izquierda
.Nombre = "Nodo_1"
.Valor = 10
Set .Izquierda = New CNodoArbolSimple
Set .Derecha = New CNodoArbolSimple
Set .Anterior = Nodo
End With
Nodos.Add Nodo.Izquierda, "1"
With Nodo.Derecha
.Nombre = "Nodo_2"
.Valor = 20
Set .Izquierda = New CNodoArbolSimple
Set .Derecha = New CNodoArbolSimple
Set .Anterior = Nodo
End With
Nodos.Add Nodo.Derecha, "2"
With Nodo.Izquierda.Derecha
.Nombre = "Nodo_4"
.Valor = 40
Set .Anterior = Nodo.Izquierda
End With
Nodos.Add Nodo.Izquierda.Derecha, "4"
Debug.Print
Debug.Print " Nodo Base "
' El procedimiento MuestraDatos est a continuacin
MuestraDatos Nodos(CStr(0))
For i = 1 To 4
Debug.Print
Debug.Print " Nodo n " & CStr(i)
MuestraDatos Nodos(CStr(i))
Next i
Nodo n 1
Nombre Nodo_1
Comencemos a programar con VBA - Access
20 - 20
Valor 10
Nodo n 2
Nombre Nodo_2
Valor 20
Nodo n 3
Nombre Nodo_3
Valor 30
Nodo n 4
Nombre Nodo_4
Valor 40
Ahora la recorro por los enlaces
Siguiendo las propiedades
Izquierda, Derecha y Anterior
Nodo Base Nodo_0
Nodo N 1 Nodo_1
Nodo N 2 Nodo_2
Nodo N 3 Nodo_3
Nodo N 4 Nodo_4
Para destruir la estructura podramos ir eliminando cada uno de los elementos de la
coleccin Nodos, mediante su mtodo Remove, antes de salir del procedimiento.
Ya se que a primera vista no parece muy espectacular, pero hemos creado una estructura
tipo rbol, en la que cada nodo puede estar enlazado con otros tres y es capaz de
almacenar un valor.
En la clase CNodoArbolSimple hemos colocado una propiedad Izquierda, otra
Derecha y una Anterior.
Si quisiramos crear un rbol ms genrico, en el que un nodo podra tener 0, 1 n ramas,
deberamos sustituir las propiedades Derecha e Izquierda, por una propiedad
Rama(ndice) que trabajara contra una coleccin privada de la propia clase.
Igualmente podramos saltarnos una estructura de rbol y definir una estructura de grafo
ms complejo.
Podramos haber desarrollado una propiedad Padre(ndice) que enlazara con varios
posibles Ancestros, de nivel -1, una propiedad Hermano(ndice) que enlazara con
objetos del mismo nivel, y una propiedad Hijo(ndice) que enlazara con objetos de
nivel 1. A travs de los objetos devueltos podramos tener acceso a Abuelos, Nietos, etc
Adems podramos hacer que cada nodo almacenara diferentes valores de diversos tipos.
Las referencias a Hermanos, Padres e Hijos podramos guardarlos en Colecciones
Privadas de la propia clase.
Las aplicaciones en las que una estructura de este calibre, podra servir como elemento
clave, son innumerables:
Desarrollo flexible de Escandallos de Produccin
Elaboracin de Grafos
Diseo de una hoja de clculo
Definir modelos de datos
Diseo de juegos
Todas las que tu imaginacin pueda intuir. . .
Antes de seguir quiero volver a incidir en un aspecto que hemos tocado.
Si una clase incluye referencias a objetos la propia clase, y mtodos para desplazarse entre
las referencias, podemos encadenar estos mtodos.
Por ejemplo si tenemos una clase que posee una propiedad Siguiente que devuelve otro
objeto de esa misma clase, podramos recorrer la estructura de objetos, utilizando el mtodo
Siguiente desde un Objeto base de forma reiterativa, hasta que lleguemos a un objeto cuya
propiedad Siguiente est sin asignar, es decir su valor sea Nothing.
Objeto.Siguiente.Siguiente.Siguiente. . .
Funcin Is Nothing
Para ver si hemos asignado un objeto a una variable objeto, podemos utilizar la funcin Is
Nothing, que devolver True si est sin asignar, y False si ya tiene asignado un objeto.
La forma de utilizarla es
MiObjeto Is Nothing
Por ejemplo, el siguiente cdigo imprimir primero False, ya que no hemos todava
asignado un objeto a la propiedad Anterior, del objeto Nodo1. A continuacin imprimir
True, ya que el objeto Nodo2 s tiene asignado el objeto Nodo1 en la propiedad
Anterior.
Public Sub PruebaIsNothing()
Dim Nodo1 As New CNodoArbolSimple
Dim Nodo2 As New CNodoArbolSimple
Debug.Print Nodo1.Anterior Is Nothing
Set Nodo2.Anterior = Nodo1
Debug.Print Nodo2.Anterior Is Nothing
End Sub
Eventos.
Un evento es un procedimiento de la clase que se ejecuta desde dentro del propio objeto
creado con la clase, y que es posible captarlo en el objeto que contiene a la clase.
Como veremos prximamente, si en un formulario colocamos un botn de comando
(CommandButton) cada vez que lo presionemos genera el evento Click.
Si quisiramos que cuando se presione el botn de nombre cmdSalir, se cierre el
formulario, podramos poner en el mdulo de clase del formulario el siguiente cdigo.
Salir:
Exit Sub
HayError:
MsgBox Err.Description
Resume Salir
End Sub
Dentro del mdulo de clase del objeto Botn, algn programador ha definido un evento al
que ha puesto por nombre Click()
Nosotros podemos programar Eventos dentro de las clases, de forma que esos eventos
puedan ser captados por otras clases que contengan a las primeras.
Para ello se utiliza las instrucciones Event y RaiseEvent, que veremos ms adelante.
Qu es un Evento
Si vamos a la ayuda de Access, vemos que lo describe de la siguiente forma
Un evento es una accin especfica que se produce en o con un objeto determinado.
Microsoft Access puede responder a una variedad de eventos:
clics del Mouse
cambios en los datos
formularios que se abren o se cierran
muchos otros.
Los eventos son normalmente el resultado de una accin del usuario.
No se si aclara mucho, pero como complemento me atrevo a decir que un evento es algo as
como una llamada de aviso que efecta un objeto cuando suceden determinadas cosas.
Esa llamada puede, o no, ser recogida por un procedimiento, que actuar en consecuencia.
Vamos a ver un ejemplo clsico.
Pongamos en un formulario un botn de comando.
Ojo: desactiva antes el Asistente para controles de la barra de herramientas.
A su propiedad Ttulo, le ponemos el texto Saludo.
Sin dejar de seleccionar el botn, activamos la hoja Eventos de la ventana de propiedades.
Seleccionamos el evento Al hacer clic y pulsamos en el botoncito con tres botones
Nos aparece una pequea ventana con tres opciones. Seleccionamos Generador de
cdigo y pulsamos en el botn Aceptar.
Directamente nos abre el mdulo de clase de ese formulario, probablemente con el siguiente
cdigo.
Option Compare Database
[email protected] Eduardo Olaz
Entrega 20 Ms sobre Clases y Objetos (1) 20 - 23
Option Explicit
End Sub
End Sub
Podemos ver que el nuevo procedimiento tiene el nombre del objeto txtPrueba, seguido
de la barra baja _ y el nombre, en ingls del evento KeyPress.
En este caso, adems incluye el parmetro KeyAscii, de tipo Integer.
el evento es llamado cada vez que se pulsa una tecla en el cuadro de texto, pasndole un
valor entero (KeyAscii) que contiene el cdigo ASCII de la letra correspondiente a la
tecla pulsada.
Por ejemplo, el cdigo ASCII correspondiente a la letra A es el 65, y el de la letra a es el
97. Podramos cambiar el valor de ese cdigo. Por ejemplo, si en el procedimiento
pusiramos
Private Sub txtPrueba_KeyPress(KeyAscii As Integer)
KeyAscii = Asc(UCase(Chr(KeyAscii)))
End Sub
Y ejecutramos el cdigo, veramos que slo podremos poner letras maysculas, aunque
pulsemos minsculas.
La razn es la siguiente
Cuando pulsamos una tecla, y antes de que realmente se llegue a escribir nada en el cuadro
de texto, como ya hemos dicho, llama al procedimiento del evento, pasndole el cdigo
ASCII correspondiente a la letra de la tecla pulsada. Supongamos que hemos pulsado la
letra a minscula. Por tanto el cdigo ASCII pasado ser el 97.
A continuacin convierte el cdigo 97 en la propia letra a, mediante la funcin Chr
Chr(97).
Mediante la funcin Ucase, UCase(Chr(97),)convierte la a minscula en A mayscula.
Finalmente extrae el cdigo ASCII correspondiente a la A mayscula, 65, y lo pasa al
parmetro ASCII.
En una fase posterior, el formulario muestra la A mayscula en el cuadro de texto.
Resumen:
Un evento se coloca en el mdulo del objeto contenedor del objeto que genera el evento. En
el caso anterior en el mdulo de clase del formulario, que es el que contiene al botn
cmdSaludo y al cuadro de texto txtPrueba.
Los procedimientos que gestionan los eventos correspondientes tienen como nombre
NombreDelObjeto_NombreDelEvento([PosiblesParmetros])
Ejemplos de nombres de los procedimientos gestores de los eventos:
cmdSaludo_Click()
txtPrueba_KeyPress(KeyAscii As Integer)
txtPrueba_KeyDown(KeyCode As Integer, Shift As Integer)
Como podemos ver, un evento puede tener (o no) uno ms parmetros.
Esos parmetros, normalmente pasados Por Referencia, pueden ser cambiados dentro del
procedimiento gestor de eventos.
Un mismo objeto puede generar diferentes tipos de eventos.
Capacidad
Nivel Mximo
Contenido Actual
Nivel Mnimo
Para controlar cada una de las propiedades definiremos las variables privadas, a las que se
acceder mediante las correspondientes propiedades.
Tambin definiremos los eventos que hemos definido.
Insertamos un nuevo mdulo de clase y escribimos
Dim m_sngCapacidad As Single
Dim m_sngNivelMaximo As Single
Dim m_sngContenido As Single
Dim m_sngNivelMinimo As Single
End Property
' Contenido actual del depsito
Public Property Get Contenido() As Single
Contenido = m_sngContenido
End Property
Salir:
Exit Sub
HayError:
MsgBox "Se ha producido el error n " & Err.Number _
& vbCrLf _
& Err.Description, _
vbCritical + vbOKOnly, _
"Error en la clase CDeposito " & Err.Source
Resume Salir
End Sub
If blnCancelar Then
' Cancelamos el proceso
Exit Sub
Else
' Pasamos Volumen a ValidaTrasvase
ValidaTrasvase -Volumen
Salir:
Exit Sub
HayError:
MsgBox "Se ha producido el error n " & Err.Number _
& vbCrLf _
& Err.Description, _
vbCritical + vbOKOnly, _
"Error en la clase Deposito " & Err.Source
Resume Salir
End Sub
Volumen)
Err.Raise 1110, "Proceso de trasvase", _
"Se pretende extraer ms volumen" _
& " que el que hay en el depsito"
Exit Sub
actual, que como inicialmente ser cero, al llamar a la propiedad Contenido ejecutar el
procedimiento Introducir.
Podramos haber definido eventos que se dispararan en el momento que cambiramos la
capacidad del depsito, o sus niveles de seguridad, pero como stas sern propiedades que
normalmente se definirn en el momento de la creacin del depsito, y no cambiarn
durante su vida til, no he considerado pertinente escribirlos. En una clase desarrollada para
su explotacin real, seguramente s habra que considerarlos.
La propiedad Contenido devuelve o establece la cantidad contenida ahora en el depsito.
Si en el mundo real queremos establecer una cantidad para el contenido de un depsito,
realizaramos los siguientes pasos.
Comprobaramos el volumen existente en el depsito
Si la cantidad es idntica a la que queremos que contenga, se acaba el problema.
Si la cantidad que queremos que tenga es mayor que la existente en el depsito,
aadiremos la diferencia entre lo que queremos que haya y lo que realmente hay.
Si es mayor que la que queremos extraeremos la diferencia.
Es lo que hace el segmento de cdigo
Select Case Volumen
Case Is > m_sngContenido
Introducir Volumen - m_sngContenido
Case Is < m_sngContenido
Extraer m_sngContenido - Volumen
End Select
Llama al mtodo Introducir al mtodo Extraer pasndole como parmetro el
volumen que ser necesario trasvasar.
Es una de las ventajas de trabajar con objetos, ya que podemos aplicar al cdigo una lgica
de procesos muy cercana a lo que ocurrira en el mundo real, con lo que el cdigo se hace
ms estructurado, modular y comprensible.
Vamos a analizar primero el mtodo Introducir.
Lo primero que hace es comprobar si el Volumen a introducir es negativo, lo que equivaldra
a que tendramos que extraer. Por tanto, si fuera as llamara al mtodo Extraer.
If Volumen < 0 Then
Extraer -Volumen
Exit Sub
End If
Seguidamente dispara el evento Introduciendo, al que le pasa como parmetros el
Volumen a trasvasar, y por referencia la variable Boleana blnCancelar.
' Desencadenamos el primer evento
RaiseEvent Introduciendo(Volumen, blnCancelar)
En el objeto contenedor del objeto Depsito, que podra ser por ejemplo un formulario, en el
procedimiento manejador del evento podra haberse establecido la propiedad Cancelar al
valor True, con lo que se interrumpira el proceso de introduccin. Este proceso se realiza
en el segmento de cdigo:
If blnCancelar Then
' Cancelamos el proceso
Exit Sub
Else
ValidaTrasvase Volumen
m_sngContenido = m_sngContenido + Volumen
RaiseEvent Introducido(Volumen)
End If
Si no se ha interrumpido el proceso, llama a procedimiento ValidaTrasvase, que se
encarga de comprobar si las cantidades estn en los mrgenes correctos.
El procedimiento ValidaTrasvase, comprueba si es posible efectuar la operacin de
trasvase en su totalidad, es decir que durante el trasvase no vamos a intentar meter ms
volumen del que cabe en el depsito, ni vamos a intentar extraer ms volumen del que
actualmente hay.
Si ocurriera uno de estos dos casos, disparara el evento TrasvaseImposible
informando del contenido actual del depsito y del volumen que se pretende trasvasar.
A continuacin, si intentara introducir ms cantidad de la que cabe en el depsito, generara
el error n 1100, o el error 1110 si lo que se pretendiera es extraer ms cantidad de la
existente. Estos errores seran captados por el procedimiento que ha hecho la llamada de
comprobacin Introducir o Extraer.
La siguiente tarea es comprobar si volumen final es mayor que el nivel mximo, o menor que
el nivel mnimo, caso en el que disparar el evento ViolandoNivelDeSeguridad.
A este evento le pasa como parmetros el contenido actual del depsito, el volumen a
trasvasar y el nivel de seguridad, Mximo Mnimo, violado.
Si no se ha generado ningn error significa que la operacin de trasvase es posible, aunque
estuviese fuera de los lmites de seguridad. Por ello, al retomar
el control, el procedimiento Introducir, realiza el trasvase y
genera el evento Introducido.
m_sngContenido = m_sngContenido + Volumen
RaiseEvent Introducido(Volumen)
El procedimiento Extraer tiene una estructura semejante al
procedimiento Introducir; de hecho los dos podran haber
sido sustituidos por un procedimiento con un nombre tal como
Trasvasar.
Si el parmetro Volumen pasado a Introducir fuera
negativo, sera equivalente a llamar al procedimiento Extraer
con el Volumen positivo, y viceversa.
Si abrimos el examinador de objetos, nos mostrar todos los
miembros, (atributos, mtodos y eventos) que hemos definido en
la clase.
Vamos ahora a ver cmo podemos llegar a manejar los eventos generados, y cmo les
podramos dar una utilidad prctica.
A la hora de declarar un objeto de forma que se puedan manejar sus eventos, es preciso
hacerlo con la palabra WithEvents.
Palabra clave WithEvents.
Sirve para hacer que en un objeto contenedor en el que se ha declarado otro objeto capaz
de generar eventos, podamos definir procedimientos manejadores de esos eventos del
objeto contenido. Quizs suene un poco a galimatas, pero si queremos que un formulario
sea capaz de manejar los eventos de un objeto Depsito, de la clase CDeposito
deberemos declararlo, en el formulario, precedido de la palabra clave WithEvents.
La forma de utilizar WithEvents es
Dim|Public|Private WithEvents NombreObjeto As NombreDeLaClase
En nuestro caso podramos declarar un objeto de nombre Deposito de la clase
CDeposito. Para ello escribimos en el mdulo de clase de un formulario
Dim WithEvents Deposito As CDeposito
Cuando queremos declarar un objeto con capacidad para manejar sus eventos, el objeto no
podremos declararlo con la palabra clave New.
Por ejemplo, esta lnea de cdigo, colocada en la cabecera de un formulario producir un
error de compilacin en tiempo de diseo.
Objeto Nombre
Botn cmdExtraer
Botn cmdIntroducir
Etiqueta lblCapacidad
Etiqueta lblMaximo
Etiqueta lblContenido
Etiqueta lblMinimo
Como sugerencia, la clase CDeposito, se podra tomar como base, con pequeas
modificaciones, por ejemplo para controlar la validez de entradas y salidas de un artculo en
un almacn, e incluso para gestionar su stock.
Vamos a programar una sencilla clase a la que pondremos como nombre CTrabajador y
a instanciarla, para ver el efecto de los eventos Initialize y Terminate.
Option Explicit