You are on page 1of 606

Visual Basic - Guía del Estudiante Cap.

1
INTRODUCCION Antecedentes históricos.

El lenguaje de programación BASIC (Beginner's All purpose Symbolic Instruction Code ) nació
en el año 1964 como una herramienta destinado a principiantes, buscando una forma sencilla
de realizar programas, empleando un lenguaje casi igual al usado en la vida ordinaria ( en
inglés), y con instrucciones muy sencillas y escasas. Teniendo en cuenta el año de su
nacimiento, este lenguaje cubría casi todas las necesidades para la ejecución de programas.
Téngase en cuenta que las máquinas existentes en aquella época estaban estrenando los
transistores como elementos de conmutación, los ciclos de trabajo llegaban a la impensable
cifra de 10.000 por segundo y la memoria no pasaba de unos pocos k´s en toroides de ferrita.

Los autores fueron los científicos John G. Kemeny (Budapest, 1926 – USA 1992) y Thomas E.
Kurtz (Illinois 1928) Su trabajo original se llamó True BASIC.

La evolución del BASIC por los años 70 fue escasa, dado el auge que tomaron en aquella
época lenguajes de alto nivel como el FORTRAN y el COBOL. En 1978 se definió una norma
para unificar los Basics existentes creándose la normativa BASIC STANDARD

Con la aparición de los primeros ordenadores personales, dedicados comercialmente al usuario


particular, allá por la primera mitad de los ochenta, el BASIC resurgió como lenguaje de
programación pensado para principiantes, y muchos de estos pequeños ordenadores
domésticos lo usaban como único sistema operativo (Sinclair, Spectrum, Amstrad)

Con la popularización del PC, salieron varias versiones del BASIC que funcionaban en este tipo
de ordenadores (Versiones BASICA, GW-BASIC), pero todas estas versiones del BASIC no
hicieron otra cosa que terminar de rematar este lenguaje. Los programadores profesionales no
llegaron a utilizarlo, habida cuenta de las desventajas de este lenguaje respecto a otras
herramientas (PASCAL, C, CLIPPER). El BASIC con estas versiones para PC llegó incluso a
perder crédito entre los profesionales de la informática.

Las razones para ello eran obvias:

- No era un lenguaje estructurado.


- No existían herramientas de compilación fiables.
- No disponía de herramientas de intercambio de información.
- No tenía librerías.
- No se podía acceder al interior de la máquina.
- Un largo etcétera de desventajas respecto a otros lenguajes de programación.

Tal fue ese abandono por parte de los usuarios, que la aparición del Quick-BASIC de Microsoft,
una versión ya potente del BASIC, que corregía casi todos los defectos de las versiones pasó
prácticamente inadvertida, a no ser porque las últimas versiones del sistema operativo MS-DOS
incluían una versión de Quick-BASIC algo recortada (Q-Basic) como un producto mas dentro de
la amplia gama de ficheros ejecutables que acompañan al sistema operativo, y aprovecha de él
el editor de textos (Cada vez que se llama al EDIT estamos corriendo el editor del Q-Basic).

Esta versión del popular BASIC ya es un lenguaje estructurado, lo que permite crear programas
modularmente, mediante subrutinas y módulos, capaz de crear programas ya competitivos con

LSB Visual Basic - Guía del Estudiante Capítulo 1 Página 1


otros lenguajes de alto nivel. Sin embargo llegaba tarde, pues los entornos MS-DOS estaban ya
superados por el entorno gráfico Windows.

Sin embargo algo había en el BASIC que tentaba a superarse: su gran sencillez de manejo. Si a
esto se le añade el entorno gráfico Windows, el aprovechamiento al máximo de las
posibilidades de Windows en cuanto a intercambio de información, de sus librerías, de sus
drivers y controladores, manejo de bases de datos, etc. el producto resultante puede ser algo
que satisfaga todas las necesidades de programación en el entorno Windows. La suma de
todas estas cosas es VISUAL - BASIC. Esta herramienta conserva del BASIC de los años 80
únicamente su nombre y su sencillez, y tras su lanzamiento al mercado, la aceptación a nivel
profesional hizo borrar por fin el "mal nombre" asociado a la palabra BASIC.

Actualmente (2001) se está comercializando la versión 6.0 de este producto. Desde su salida al
mercado, cada versión supera y mejora la anterior. Dados los buenos resultados a nivel
profesional de este producto, y el apoyo prestado por el fabricante para la formación de
programadores, Visual-Basic se ha convertido en la primera herramienta de desarrollo de
aplicaciones en entorno Windows.

Es obligado decir sin embargo, que sigue siendo BASIC. No se pueden comparar sus
prestaciones con otros lenguajes cuando deseamos llegar al fondo de la máquina y controlar
uno a uno sus registros. No es ese el fin perseguido con VB y si es necesario llegar a esas
precisiones será necesario utilizar otro lenguaje que permita bajar el nivel de programación.
(Visual-C). o realizar librerías (DLLs) que lo hagan. En la mayor parte de las aplicaciones, las
herramientas aportadas por VB son mas que suficiente para lograr un programa fácil de realizar
y de altas prestaciones.

Características Generales de Visual-Basic

Visual-Basic es una herramienta de diseño de aplicaciones para Windows, en la que estas se


desarrollan en una gran parte a partir del diseño de una interface gráfica. En una aplicación
Visual Basic, el programa está formado por una parte de código puro, y otras partes asociadas
a los objetos que forman la interface gráfica.

Es por tanto un termino medio entre la programación tradicional, formada por una sucesión
lineal de código estructurado, y la programación orientada a objetos. Combina ambas
tendencias. Ya que no podemos decir que VB pertenezca por completo a uno de esos dos tipos
de programación, debemos inventar una palabra que la defina : PROGRAMACION VISUAL.

La creación de un programa bajo Visual Basic lleva los siguientes pasos:

Análisis . Es el studio de las necesidades que han dado origen a la creación de ese
programa. Es lo que se se llama Análisis de la aplicación. Es la primera fase que debe
tener siempre un programa y es tambien la más olvidada entre los programadores
noveles. Una aplicación no se inicia con el teclado, sino sobre un papel.

- Creación de un interface de usuario. Este interface será la principal vía de


comunicación hombre máquina, tanto para salida de datos como para entrada. Será
necesario partir de una o varias ventanas - Formularios - a las que le iremos añadiendo
los controles necesarios.

- Definición de las propiedades de los controles – Se dará la forma, posición, y


todas las características necesarias a los controles que hayamos colocado en ese
formulario. Estas propiedades determinarán la forma estática de los controles, es decir,
como son los controles y para qué sirven.

- Generación del código asociado a los eventos que ocurran a estos controles. A
la respuesta a estos eventos (click, doble click, una tecla pulsada, etc.) le llamamos

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 2


Procedimiento, y deberá generarse de acuerdo a las necesidades del programa.

- Generación del código del programa. Un programa puede hacerse solamente con
la programación de los distintos procedimientos que acompañan a cada objeto. Sin
embargo, VB ofrece la posibilidad de establecer un código de programa separado de
estos eventos. Este código puede introducirse en unos bloques llamados Módulos, en
otros bloques llamados Funciones, y otros llamados Procedimientos. Estos
Procedimientos no responden a un evento acaecido a un control o formulario, sino que
responden a un evento producido durante la ejecución del programa.

No es necesario entender de momento lo anterior. Visual Basic introduce un concepto nuevo de


programación, y es necesario cambiar hasta el argot del programador. Posiblemente se le
habrán acumulado demasiados términos de una sola vez. Es normal. A poco que siga leyendo
verá las cosas mas claras cuando se explique una por una.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 3


VARIABLES. DEFINICION Y ENTORNO

Basic, desde siempre, al contrario de otros sistemas de programación, no exigió la definición


previa de una variable. Una variable, como Vd. seguro que conoce, es un nombre que en el
programa le asignamos a un dato. Ese dato podrá cambiar. Piense por ejemplo, en un
programa consistente en la toma de datos de los alumnos de un centro escolar. Existirán varias
variables para poder introducir los datos de los alumnos. Estas variables pueden tener nombre
tales como:

Nombre
Apellido1
Apellido2
Dirección
Teléfono
Salario

La variable Nombre tomará valores distintos según vayamos introduciendo los datos de los
distintos alumnos. Es posible, que a lo largo de la ejecución del programa, esta variable Nombre
valga:

José
Pedro
María
Luis

Espero que su intuición o conocimiento anterior le lleve a conocer el concepto de variable. Mas
adelante lo verá mas claro.

Decíamos que Basic no exige la definición previa de las variables. Otras herramientas exigen
que se haga así. Por lo tanto es normal encontrar, en otros sistemas de programación, que un
programa comienza de la siguiente forma:

Declare Nombre As String Le dice que Nombre es una sucesión de letras


Declare Apellido1 As String
Declare Apellido2 As String
Declare Dirección As String
Declare Teléfono As String Le dice que Teléfono es una sucesión de letras
Declare Salario As Número Le dice que Salario es un número

Mediante estas declaraciones, el programa sabe de que tipo de dato se trata y por tanto cómo
debe trabajar con él. En otros sistemas de programación distintos de Basic, es necesario
realizar esta declaración antes de introducir una variable.

Basic permite que no se declaren. Cuando a lo largo del programa le introducimos una variable
nueva, asume que es una variable y que el tipo es el adecuado para el valor que le estamos
introduciendo en ese momento.

Por ejemplo, si Basic encuentra estas instrucciones

Salario=50000000
Nombre ="Pedro"
Teléfono = "1234567"

entiende que Salario, Nombre y Teléfono son variables, que Salario es un número (No hemos
metido su valor entre comillas), y que Nombre y Teléfono son sucesiones de caracteres
alfanuméricos (su valor está entre comillas)

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 4


Esta particularidad de no necesitar declarar las variables hace que sea sencillo introducir una
variable nueva. Sin embargo entraña un gran peligro. Imagínese que en un paso posterior del
programa, le mandamos escribir esos tres datos anteriores con la instrucción PRINT

Print Salario
Print Nombre
Print Telwfono

Habrá observado en tercer lugar la palabra Telwfono, que por error ha introducido el
programador. Basic interpreta que Telwfono es una variable e irá a leer en memoria el valor que
tiene. No tendrá ningún valor. Por lo tanto no escribirá nada y encima no dará ningún aviso de
que se ha cometido un error. Nada es gratis en esta vida, y la facilidad para introducir variables
se paga con la posibilidad de un error.

El peligro de no declarar las variables no termina en esa posibilidad de error. Cuando no


declaramos el tipo de variables, Visual Basic supone que la variable es de un tipo que soporta
cualquier tipo de datos : una variable tipo Variant. En ese tipo podrá meter cualquier tipo de
variable, pero a costa de ocupar mucho mas espacio en la memoria que si la hubiese declarado
con el tipo correcto para el dato que va a meter en ella.

Basic ha pensado en ese problema, y se puede solucionar con esta que será la primera
instrucción BASIC que vamos a estudiar:

OPTION EXPLICIT

Obliga a declarar previamente las variables que se vayan a usar. De no haberla


declarado antes de usarla, el programa dará una comunicación de error.

Esta declaración debe ponerla al comienzo de la sección de declaraciones de cada formulario y


módulo que contenga su aplicación. Pero no se preocupe de ello puesto que VB lo ha hecho por
Vd. Basta que lo programe en las opciones del VB. Haga click en Herramientas | Opciones de
la barra de menú del VB y le aparecerá este cuadro, donde debe marcar las casilla Requerir
declaración de variables. A partir de ahora, será VB quien ponga la sentencia Option Explicit
en el lugar correcto. (Fig. 1.1)

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 5


TIPOS DE VARIABLES

Las variables pueden ser de los siguientes tipos: (El número indicado en segundo lugar indica el
número de Bytes que ocupa en memoria.)

Booleana (2) Admite los valores 0 y 1, o True (verdadero) y False (falso)


Byte (1) Números enteros, en el rango de 0 a 255
Integer (2) Números enteros en el rango de -32768 a 32767
Long (4) Números enteros en el rango de -2147483648 a 2147483647
Single (4) Punto flotante, simple precisión
Doble (8) Punto flotante, doble precisión.
Currency (8) Entero, con punto decimal fijo (Típico de monedas)
String (*) Cadenas alfanuméricas de longitud variable o fija
Date (8) Fechas
Objet (4) Referencia a objetos
Variant (**) Otros tipos de datos

(*) Una variable tipo String ocupa el mismo número de bytes que caracteres tenga la cadena.
(**) Una variable tipo Variant ocupa 16 bytes si se trata de un número y 22 bytes + longitud de la
cadena si se trata de un dato tipo cadena de caracteres.

Existen también variables definidas por el usuario (Ya verá la sentencia Type). En este tipo de
variables se pueden introducir muchos datos de distinto tipo. Los bytes necesarios para
almacenar esa variable dependerá de los datos que se hayan definido.

Dentro de las variables Objet (variables que se refieren a objetos) existe una gran variedad que
a estas alturas del curso no debemos complicarnos con ellas. Pero para adelantar algo,
veremos que una variable puede ser del tipo Form - Formulario - , tipo Recordset, etc. etc.

Cada tipo de variable ocupa unos determinados bytes. Si no se define una variable, VB toma
como tipo por defecto para la variable el tipo Variant, tal como citábamos anteriormente. Este
tipo ocupa mas bytes que, por ejemplo, un integer. Si el tipo de dato que vamos a introducir en
una variable es un integer, y no la hemos declarado como tal, VB asumirá para esa variable que
es del tipo Variant, lo que le llevará a gastar mas bytes de memoria (16) que los que necesitaría
(2) si la hubiésemos declarado previamente. Si esa variable va a estar en el rango de 0 a 255, y
no declaramos previamente que la variable va a ser del tipo Byte, o la declaramos como integer,
p. e., estamos desperdiciando memoria RAM y posiblemente, retardando la ejecución del
programa. Lo mismo podemos decir del resto de las variables, y lo importante que es
declararlas y declararlas bien.

NOTA. Observe en la lista anterior que un dato Booleano ocupa 2 Bytes, mientras que un dato
tipo Byte ocupa un byte. En muchas ocasiones declaramos variables tipo Boolean con la
intención de que ocupen menos espacio. Paradoja del VB. Si la declaramos como Byte
ocupamos menos espacio en memoria. Declarar una variable como Boolean tiene también sus
ventajas (escribirá menos código por lo general cuando necesite leer o escribir una variable tipo
Boolean), pero tenga presente esta observación respecto al tamaño de los datos Boolean.

Puede declarar el tipo de la variable mediante un carácter después del nombre de la variable.
Esta técnica, obligatoria en Quick-Basic, está en desuso en VB. No es recomendable definir el
tipo de esta forma, pues existe un serio peligro de error. De cualquier forma, eso es potestativo
del programador y de sus costumbres.

Los caracteres que definen cada tipo de variable son:

% Integer & Long ! Single

# Double @ Currency $ String

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 6


Ejemplos Prácticos de declaración de variables

En Visual Basic, cuando declaramos una variable como String (Cadena de caracteres), no es
necesario declarar su longitud. VB aceptará cualquier número de caracteres. Si desea evitar
que se puedan introducir más de un determinado número de caracteres, debe declarar su
número. Por ejemplo :

Dim Var1 as String Var1 puede tener cualquier número de caracteres

Dim Var2 as String * 15 Var2 puede tener un máximo de 15 caracteres.

En este segundo caso, si se introduce como Var2 una cadena de caracteres con mas de 15
caracteres, Var2 tomará solamente los 15 primeros. Visual basic no presenta ningún aviso de
que esa variable ha omitido los caracteres que han sobrepasado la cifra de 15. Si desea que el
usuario conozca esa circunstancia, debe introducir el código oportuno para producir el aviso.

La declaración de variables tipo String con número de caracteres predefinido presenta también
inconvenientes a la hora de tratar esa cadena de caracteres con sentencias tales como Mid,
Left y Right, o a la hora de añadir una cadena a otra. La experiencia nos indica que NO merece
la pena declarar variables tipo String con el número de caracteres prefijado, excepto que
sea necesario justamente para definir la longitud de la cadena.

En una gran parte de los casos una variable que se compone de números debe declararse
como una variable de cadena de caracteres (String), y no como numérica. Cuando pensamos
por ejemplo en un número de DNI, compuesto por 7 u 8 cifras, un código postal, el número de
una calle, el piso de un edificio, parecen invitar a que la variable que los contenga sea una
variable de tipo numérico (Byte, Integer, Long, ...). Estas variables, aunque su contenido sean
números, siempre se deben declarar como String, ya que se tratan en realidad de cadenas de
caracteres, aunque estos no sean letras sino números. Para aclarar mas estas ideas, piense en
el número del DNI con la letra del NIF incluido, o que el lugar del DNI se deba rellenar con el
número del permiso de residencia, (lleva letras). Piense en el código postal de una provincia
que comienza por 0 ( 08XXX = Barcelona ) . Si la variable que va a contener ese código postal
se declara como numérica, el cero de la izquierda lo desprecia, por lo que ese código postal
quedaría reducido al 8XXX, número de 4 cifras que el cartero nunca reconocería como un
código postal, que necesariamente ha de tener 5 cifras. Para terminar, piense la forma de
introducir en una variable numérica el número 32Bis de una calle o el piso S2 de un edificio. O
piense en una variable que va a contener un código de un producto. Ese código siempre va a
ser un número, por ejemplo de 9 cifras. ¿Ha pensado como trataría el ordenador una variable
numérica que contiene el código 000100123 ?. El resultado sería que convertiría ese código en
la cifra 100123, y Vd. deberá buscarse la vida para añadir los ceros iniciales a la hora de
sacarlo a una impresora, por ejemplo.

En todos los casos anteriores, el número no representa una cantidad numérica, sino un
nombre. Lo que ocurre es que ese nombre contiene solamente números.

¿Qué variables debemos declarar entonces como numéricas ? La respuesta es bien sencilla :
Aquellas que van a contener datos con lo que vamos a realizar operaciones matemáticas.

Las variables booleanas (True/False) pueden en muchos casos sustituirse por una variable del
tipo Byte. Si ese datos True / False se va a introducir en una base de datos o en fichero en el
disco, puede ser mas prudente poner 0 en vez de False y 1 en vez de True.

Una variable byte ocupa muy poco, simplemente 1 byte como su nombre indica. Pero no puede
contener números mayores de 255 ni números negativos.

Cada vez que declare una variable numérica piense en los valores que puede tener, sobre todo
cuando esa variable va a ser el resultado de una operación matemática. Recuerde el escaso
margen de una variable tipo Integer ( de -32768 a 32767)

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 7


Si la aplicación va a tratar moneda, piense en la forma de expresar los números decimales y el
número de ellos permitidos, así como el redondeo. La variable correcta para este caso es
Currency, pero Currency le añade automáticamente el tipo de moneda de cada país (Pts. Para
España) lo que con frecuencia es un engorro. Los datos del tipo de moneda los toma del
sistema operativo del ordenador, por lo que no se extrañe si le expresa el número de pesetas
en dólares. Cambie el país en su S. O.

Otro tipo de variable es Date. Este tipo de variable representa una fecha o una hora. Pero
debe ser objeto de un estudio un poco mas extenso para tener claro que es una fecha para
Visual Basic, como las trata y como se pueden comparar. Lo verá mas adelante al estudiar las
funciones Format y DateDiff.

Ambito de las variables.

Denominamos ámbito de una variable a las partes del programa donde esa variable está
declarada. Para entenderlo mejor, veamos someramente la forma de un programa desarrollado
en VB.

Un programa VB tiene uno o varios formularios. Cada formulario tiene varios controles. Tanto el
formulario como cada uno de sus controles tienen una parte del programa, justamente la parte
relacionada con cada uno de los eventos que pueden suceder bien al formulario o a los
controles. A estas partes las habíamos llamado Procedimientos. Podemos tener procedimientos
que no estén relacionados con ningún evento ocurrido al formulario o a sus controles. (Los
Procedimientos que iremos insertando a lo largo de la aplicación)
Aparte de formularios y controles, un programa puede tener Módulos, y en cada uno de los
módulos podemos insertar cuantos Procedimientos y Funciones queramos. La estructura de un
programa VB puede ser de la siguiente forma:

Formulario1 Formulario2 Formulario3 Módulo1 Modulo2


Declaraciones Declaraciones Declaraciones Declaraciones Declaraciones
Proc. A1 Proc.B1 Proc.C1 Proc.D1 Proc.E1
Proc. A2 Proc.B2 Proc.C2 Proc.D2 Proc.E2
Proc. A3 Proc.B3 Proc.C3 Proc.D3 FunciónE1
Proc. A4 Proc.B4 Proc.C4 Proc.D4 FunciónE2
Proc. A5 Proc.BB1 Proc.CC1 FunciónE3
Proc. AA1 Proc.BB2 Proc.CC2 FunciónE4
Proc. AA2 Proc.B33 Proc.CC3 FunciónE5
Proc. AA3 Proc.CC4 FunciónE6

Si se declara una variable dentro de un procedimiento o Función, esa variable "NO SALE" del
Procedimiento o Función donde se declaró. El procedimiento puede estar en un Formulario
(Cualquier procedimiento de un control o un procedimiento creado por nosotros) o en un Módulo
(En este caso, el procedimiento solo puede ser creado por nosotros)

En un Formulario, una variable puede declararse de dos formas : Privada o Pública. Para
declarar una variable a nivel de formulario debe hacerse en la sección de declaraciones, que
está la ventana de código Objeto = General, Proc. = Declaraciones. Si se declara Privada,
esa variable se puede ver en todo el formulario, (es decir, en todos los procedimientos de todos
los controles del formulario y en los Procedimientos que pudiésemos insertar en ese
formulario), pero no sale de dicho formulario. Si se declara como Pública, esa variable puede
verse por todo el formulario, de la misma forma que lo haría declarada como Privada, y además
puede ser usada desde otro Formulario o Módulo, citándola con el nombre del Formulario,
seguido del nombre de la variable (Formulario.Variable)

En un Módulo una variable puede declararse como Privada, con lo que no saldrá de ese
Módulo, o Pública, pudiendo en este caso usarse en todo el programa. Cuando se declara una

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 8


variable como pública en un Módulo, basta referirse a ella por su nombre, sin citar el nombre del
Módulo donde se declaró.

En VB es posible declarar varias veces las variables, es decir, pueden declararse a nivel de
formulario, en su apartado de declaraciones, y esa variable conservará su valor en todas las
partes de ese formulario. Sin embargo, si se declara una variable con el mismo nombre a un
nivel inferior, por ejemplo al principio de un procedimiento, esa variable será una variable
distinta a la anterior, aunque tenga el mismo nombre, al declararla en un Procedimiento,
solamente será válida en ese Procedimiento. Una vez que hayamos salido de ese
procedimiento, la variable con ese nombre volverá a ser la declarada en el Formulario. En
realidad, lo que tenemos son dos variables distintas, pero con el mismo nombre, una declarada
para todo el formulario excepto para el procedimiento donde se volvió a declarar, y otra para
ese procedimiento concreto.

NOTA.- No es recomendable declarar una variable a dos niveles. Es mucho mejor utilizar otro
nombre para esa variable dentro del procedimiento donde se le declararía por segunda vez. A
esta nota cabe exceptuar cuando declaramos variables para una operación tipo contador

For I = 1 To N

Esa variable I es práctico declararla con el mismo nombre en cada Procedimiento donde se
use.

Tipos de declaración de variables.

Sentencia DIM Es la forma mas común de declarar una variable como


Privada. Puede emplearse en un Procedimiento, Función,
Formulario o Módulo. La sintaxis es de la siguiente forma:

Dim nombrevariable As Integer (o el tipo que sea)

Declarando una variable con la sentencia DIM, en un formulario, Función, procedimiento o


módulo, el ámbito de la variable será el explicado anteriormente para una variable declarada
como Privada. Es decir, esa variable no sale del formulario, procedimiento ó módulo donde se
declaró. Cada vez que entremos al formulario, procedimiento o módulo, esa variable tomará el
valor cero (si es numérica) o nulo (si es string).

Sentencia PRIVATE Es la forma de declarar una variable como Privada. Puede


emplearse solamente en la sección de declaraciones de un
Formulario o Módulo. La sintaxis es de la siguiente forma:

Private nombrevariable As Tipovariable

Declarando una variable mediante la sentencia PRIVATE en un Formulario o Módulo, esa


variable puede usarse en todo ese Formulario o Módulo (En todos sus Procedimientos y
Funciones), pero NO fuera del Formulario o Módulo donde se declaró.

La sentencia Private no puede usarse en un procedimiento o función.

Sentencia PUBLIC Es la forma de declarar una variable como Pública. Puede


emplearse solamente en la sección de declaraciones de un
Formulario o Módulo. La sintaxis es de la siguiente forma:

Public nombrevariable As Tipovariable

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 9


Declarando una variable de esta forma en la sección de declaraciones de un Módulo, esa
variable puede usarse en cualquier parte del programa citándola simplemente por su nombre.
Si se declara de esta forma en la sección de declaraciones de un Formulario, esa variable
puede usarse en toda el programa. Para nombrarla, si estamos en el Formulario donde se
declaró basta con citarla por su nombre. Si no estamos en ese Formulario, habrá que citarla por
el nombre del Formulario, seguido del nombre de la variable, separados por un punto :

NombreFormulario.Nombrevariable

En un Módulo puede usarse también la sentencia Global en vez de Public :

Sentencia GLOBAL Declara una variable que es válida en todo el programa. La


sintaxis es:

Global nombrevariable As tipovariable

La sentencia Global sólo puede usarse en el apartado de declaraciones de un Módulo. Esta


sentencia se mantiene por compatibilidad con versiones anteriores de VB. No la use.

Sentencia STATIC

Como se dijo anteriormente, una variable declarada en un procedimiento pierde su valor al salir
de él. Lo peor es que una vez que el programa vuelva a entrar en ese procedimiento, la variable
estará puesta a cero. Afortunadamente, esto último tiene solución. Si declarásemos una
variable en un procedimiento o función, como estática, esa variable, aunque no la podremos
utilizar fuera de ese procedimiento o función, cuando volvamos a él conservará el valor que
tenía cuando lo abandonamos. Esta declaración como estática se realiza mediante la
instrucción Static

Static nombrevariable As tipovariable

El nombre de una variable puede ser tan largo como queramos. hasta un máximo de 40
caracteres. En la versión VB para España se pueden usar incluso la Ñ y vocales acentuadas.
Es indiferente usar mayúscula ó minúsculas. No se sorprenda, si por ejemplo, la ha declarado
con mayúsculas y luego la cita con minúsculas al escribir el código, que automáticamente se
cambie a mayúsculas. El nombre de una variable siempre debe comenzar por una letra.

No hay problema por utilizar variables largas. Al compilar el programa no se lleva el nombre, es
decir, no le va a ocupar mas espacio. Utilice siempre nombres que le definan la variable con
algún sentido. Es muy útil a la hora de acordarse como se llaman, y sobre todo, a la hora de
rehacer un programa que realizó hace seis meses.

Pese a que Visual Basic no obliga a declarar variables, es muy útil hacerlo. De esta forma se
tiene control sobre el programa. La experiencia se lo irá demostrando.

Resumimos la forma de declarar una variable:

En un Procedimiento (La variable no puede usarse fuera de esta Procedimiento)

Dim Variable As Tipovariable

En un Procedimiento, como permanente (La variable no puede usarse fuera de este


procedimiento, y dentro de él conserva el valor aunque se salga y se vuelva a entrar)

Static Variable As Tipovariable

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 10


En un Formulario (En su sección de declaraciones)

Como Privada (Solamente se puede usar en ese Formulario)

Dim Variable As Tipovariable ó

Private Variable As Tipovariable

Como Pública (Puede usarse en toda la aplicación)

Public Variable As Tipovariable

En un Módulo

Como Privada (Solamente puede usarse en ese Módulo)

Dim Variable As Tipovariable ó

Private Variable As Tipovariable

Como Pública (Puede usarse en toda la aplicación)

Public Variable As Tipovariable ó

Global Variable As Tipovariable

Error típico de un programador novel de Visual Basic

Creo que esta costumbre viene del lenguaje C. Pero no vale en VB. Se trata de declarar varias
variables juntas en una misma línea :

Dim Variable1, Variable2, Variable3, Variable4 As String

Esta declaración está MAL hecha. Visual Basic interpretará que Variable1, Variable2 y
Variable3 son del tipo Variant, y solamente Variable4 la supone como tipo String

La forma correcta de hacerlo, si queremos declarar esas variables un una sola línea, es la
siguiente :

Dim Variable1 As String, Variable2 As String, Variable3 As String, Variable4 As String.

Forma de conocer el tipo de una variable . Función TypeName

Podemos conocer el tipo con el que se ha declarado una variable. Esto se hace mediante la
Función TypeName, que devuelve una cadena con el tipo de una variable.

MiTipo = TypeName(NombreVariable)

NombreVariable puede ser cualquier variable con excepción de las de tipos definidos por el
usuario.

La cadena de caracteres devuelta por TypeName puede ser una de las siguientes:

Cadena devuelta La variable contiene

Byte Un byte
Entero Un entero.
Largo Un entero largo.
LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 11
Simple Un número de punto flotante de precisión simple.
Doble Un número de punto flotante de precisión doble.
Moneda Un valor de moneda.
Fecha Una fecha.
Cadena Una cadena.
Boolean Un valor Boolean.
Error Un valor de error.
Empty No inicializado.
Null No hay datos válidos.
Objeto Un objeto que no respalda Automatización OLE.
Desconocido Un objeto de Automatización OLE cuyo tipo es desconocido.
Nada Una variable de objeto que no se refiere a un objeto.

Si NombreVariable es una matriz, la cadena devuelta puede ser cualquiera de las cadenas
posibles con un paréntesis vacío adherido. Por ejemplo, si NombreVariable es una matriz de
enteros, TypeName devolverá "Integer()".

Vamos a hacer nuestro primer programa en Visual Basic. Arranque VB y coloque en el


formulario que aparece nada mas arrancarlo, un botón de comando (CommandButton) y tres
etiquetas (Label). El botón de comando le aparecerá con el nombre de Command1 y los labels
con Label1, Label2 y Label3. Haga doble click sobre el formulario. Le aparecerá una ventana.
En la parte superior izquierda tiene una línea con la palabra Form y una flecha hacia abajo que
parece que va a desplegar algo. Haga click sobre esa flecha y luego sobre la palabra General
que le aparecerá. Teclee aquí las declaraciones de varias variables (observe que en la ventana
similar de la derecha aparece Declaraciones). Puede que ya le aparezca la linea con Option
Explicit. Si no le aparece, tecléela.

Option Explicit
Dim MiString As String ‘Hemos declarado que MiString es una variable tipo String
Dim MiEntero As Integer
Dim MiObjeto As Control ‘Hemos declarado que MiObjeto es una variable tipo Objeto

Haga doble click sobre el botón de comando. Le aparecerá la ventana anterior, pero referida
ahora al Command1. Teclee el siguiente código :

Private Sub Command1_Click()


Set MiObjeto = Command1 ‘Y aquí decimos que MiObjeto es precisamente el Command1

Label1 = TypeName(MiString)
label2 = TypeName(MiEntero)
Label3 = TypeName(MiObjeto)
End Sub

En los labels 1, 2 y 3 aparecerá el tipo de cada variable: String, Integer y CommandButton.

Esta función tiene mucha utilidad para determinar errores durante el diseño. Cuando aparece el
error “No coinciden los tipos” puede interrogarse al programa para ver qué tipo de variable es el
que hemos declarado. Esta idea es especialmente útil cuando el trabajo a realizar sea retomar
el trabajo comenzado por otro programador.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 12


Lenguaje Basic del Visual Basic.
No ha sido un juego de palabras. VB emplea unas instrucciones casi iguales a las que emplea
Quick Basic. Sin embargo ha añadido otras nuevas instrucciones, inherentes con la
programación visual. Vamos a estudiar aquí las instrucciones y definiciones mas sencillas,
comunes a QB y VB.

Sentencias condicionales.

Llamamos sentencias condicionales a aquellas que se realizan si se cumple una determinada


condición. Son las sentencias por las que empieza cualquier texto de Basic, y este no va ser
menos.

La sentencia condicional más usada es:

Si se cumple una condición Entonces

Realiza estas instrucciones

Si no se cumple

Realiza estas otras instrucciones

Fin de la sentencia.

Así de fácil es programar en Basic. Lo que ocurre es que esta herramienta habla inglés, y lo
descrito anteriormente toma la forma:

If condición Then
Instrucciones
Else
Otras instrucciones
End If

En este ejemplo, o se cumple una condición y ejecuta unas determinadas instrucciones, o no se


cumple, y ejecuta otras instrucciones distintas. Puede ocurrir que, caso de no cumplirse la
condicion primera, se abra un abanico de dos o tres posibilidades. La sentencia condicional
tendría entonces la forma:

If condición 1 Then
Instrucciones
ElseIf Condición 2
Otras instrucciones
ElseIf Condición 3
Otro juego de instrucciones
Else
Instrucciones que debe realizar caso de no cumplir las condiciones 1, 2 y 3.
End If

Como decíamos anteriormente, este es el tipo de sentencia condicional mas usada.

Existe otra sentencia condicional muy usada: Select Case

Su nombre casi nos define lo que es: Selecciona, dependiendo del caso, un determinado juego
de instrucciones:

Select Case variable ' variable es una variable que puede tomar los valores (p.e.) de

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 13


1a4

Case 1
Instrucciones a ejecutar en caso de que variable = 1
Case 2
Instrucciones a ejecutar en caso de que variable = 2
Case 3
Instrucciones a ejecutar en caso de que variable = 3
Case 4
Instrucciones a ejecutar en caso de que variable = 4
Case Else
Instrucciones a ejecutar en caso de que variable sea distinta a los valores
anteriores
End Select

Este procedimiento resulta mucho mas sencillo y rápido que las sentencias If Then Else
vistas anteriormente, cuando el margen de elección es mayor que 2.

Puede agrupar varios valores en una misma línea. Por ejemplo, si tiene 100 valores posibles, y
el tratamiento es igual para varios de ellos, puede agruparlos así:

Select Case Valor


Case Is < 20
Instrucciones
Case Is = 20
Instrucciones
Case Is = 21, 22, 23, 24, 25, 26
Instrucciones
Case Is > 26
Instrucciones
End Select

Cuando lo que queremos es elegir un valor, no ejecutar instrucciones como hacíamos


anteriormente, disponemos de otras dos funciones: Choose y Switch.

Switch toma una serie de parámetros, todos por parejas. El primer término de cada pareja es la
expresión a evaluar. El segundo es el valor que tiene que devolver. En realidad Switch es una
función (las funciones las veremos muy pronto)

A = Switch (B=1, 5, B=2, 7, B=3, 11)

Esta instrucción obtiene un valor para A que dependerá del valor que tome B entre los valores
posibles (1, 2 ó 3)

La sentencia Choose es casi igual, cambia solamente la forma. La misma intrucción anterior
puede realizarse con Choose de la siguiente forma:

A = Choose ( B, 5, 7, 11 )

En estas sentencias, Switch y Choose, si el valor de B no coincide con ninguno de los


valores que se le habían establecido (1, 2 ó 3 en nuestro caso), la sentencia devuelve el valor
Nulo ( Null ). Esto puede producir algún error si no se contempla esa posibilidad.

Las sentencias Switch y Choose no se usan mucho en programación. Parece que los
programadores o no las conocen o se lían (y es comprensible) al utilizarlas. Le garantizo que
puede llegar a ser un gran programador sin necesidad de utilizarlas. Use preferentemente If
End If y Select Case.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 14


Otra sentencia condicional: IIF

Devuelve uno de entre dos valores, dependiendo de la evaluación de una expresión.

Sintaxis Iif (Expresión, SiEsCierto, SiEsFalso)

Expresión es la expresión a evaluar.

SiEsCierto Valor o expresión devuelta si Expresión es True.


SiEsFalso Valor o expresión devuelta si Expresión es False.

Observaciones

IIf siempre evalúa SiEsCierto y SiEsFalso, aunque sólo vaya a devolver una de ellas. Por esta
razón, deberá vigilar que no se produzcan efectos no deseados. Por ejemplo, si al evaluar
SiEsFalso se produce un error de división entre cero, se generará un error aunque Expresión dé
como resultado True.

Como ejemplo, en el formulario de nuestro primer programa introduzca un nuevo botón de


comando. Introduzca también un TextBox. Vea que poco a poco vamos metiendo cosas aunque
no las conocemos todavía. Mas tarde las conocerá. El TextBox tendrá por nombre Text1. Haga
doble click sobre el botón de comando e introduzca el siguiente código :

Private Sub Command2_Click()


Dim MiVariable As String
MiVariable = IIf(Clng(Text1.Text) > 100, "Es mayor", "Es menor")
Label1 = MiVariable
End Sub

Al ejecutar el programa, debe introducir un valor numérico en Text1. Si ese valor numérico es
menor que 100, MiVariable tomará el valor “Es menor” (No se cumple la condición expresada
en el primer parámetro Text1.Text > 1000). Si introduce una cantidad mayor, se cumple esa
condición, por lo que MiVariable tomará el valor “Es mayor”. El valor que toma la variable puede
verlo en Label1.

Fíjese que hemos declarado MiVariable como String, ya que va a contener un dato tipo cadena
de caracteres.

Con estas sentencias condicionales es posible realizar bifurcaciones del programa, cambiar las
propiedades de un objeto, obtener resultados de operaciones, ....

Sentencias de bucle.

Es muy común utilizar bucles a lo largo de un programa. Un bucle es una sucesión repetitiva de
instrucciones, que se estarán realizando mientras se cumpla una condición o mientras no se
cumpla otra condición. Es tan sencillo como esto:

Mientras condición

Instrucciones

Fin del bucle

Existen dos formas de bucle: Una, que realiza un número determinado de recorridos por el
bucle. Es el denominado bucle por contador. Otra, realiza el bucle hasta que se cumpla (o deje
de cumplirse) una condición. Es el llamado bucle por condición.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 15


Bucle por contador

Realiza el bucle tantas veces como le indiquemos. Por ejemplo, en este bucle nos va a
presentar las 26 letras mayúsculas del alfabeto inglés

For N=65 To 90
Label1.caption = Chr ( N )
Next N

Este "programa" nos presentará en una caja (Label) los caracteres cuyo número ASCII vaya
desde el 65 (A) al 90 (Z) Comenzará presentando el correspondiente al número 65, e irá
presentando sucesivamente el 66, el 67, etc., hasta llegar al 90, donde se parará.

Bucles por condición

Ejecuta las instrucciones del bucle mientras se cumple una condición

X=0
Do While X < 1000
X=X+1
Loop

El programa toma una variable ( X ) que previamente tuvimos la curiosidad de ponerla a cero, e
incrementa su valor una unidad. Analiza si el valor de X es menor que 1000, y si es cierto,
vuelve a realizar el bucle. Así hasta que X ya no sea menor que 1000. Al dejar de cumplirse que
X sea menor que 1000, sale del bucle. Acabamos de realizar un temporizador, y también de
exponer las sentencias condicionales y los bucles, inicio de cualquier curso de Basic. Como
final de lección, se propone un problema. Con el primer bucle, donde visualizábamos los
caracteres A a la Z, posiblemente no nos diese tiempo de ver cada una de las letras que iban
apareciendo en la pantalla, en la etiqueta Label1, dado que cambiaría con mucha velocidad, y
solamente veríamos la Z, que es donde se detuvo el programa. Podemos poner un
temporizador cada vez que presente una letra, y así nos dará tiempo a verla. Con los dos
bucles vistos anteriormente ya podemos hacerlo.

Si lo que queremos es que el programa se ejecute mientras no se cumpla una determinada


condición, la sentencia será:

X=0
Do Until X > 1000
X=X+1
Loop

Observe que la diferencia entre una y otra es la condición, While para indicar Mientras se
cumpla que ... y Until para indicar Mientras no se cumpla que ....

Para terminar bien el programa anterior utilizaremos la condición de While (Mientras se cumpla
la condición)

For N=65 To 90
Label1.caption = Chr ( N )
Label1.RefreshN ' Refresca la etiqueta
X=0
Do While X < 1000
X=X+1
Loop
Next N

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 16


Este es nuestro primer programa en BASIC. En VISUAL BASIC es idéntico, pero nos falta la
interface gráfica. Para realizarla basta con abrir el VB y sobre el formulario que aparece al
abrirlo, introducir una etiqueta, (Label) que llevará el nombre por defecto de Label1. Solo nos
queda pensar donde introducimos el código anterior. Podemos introducir un botón de comando
(Command Button) que saldrá con el nombre por defecto de Command1. Haga doble click
sobre el botón. Aparecerá el procedimiento Click. Este procedimiento es el que se realiza
cuando hacemos click sobre ese botón. Escriba en ese procedimiento este código.

Private Sub Command1_Click() ' Esta línea sale automáticamente


For N=65 To 90
Label1.caption = Chr ( N )
Label1.RefreshN ' Refresca la etiqueta
X=0
Do While X < 1000 ' Bucle de temporización (*)
X=X+1
Loop
Next N ' Termina el bucle de temporización
End Sub ' Esta línea sale automáticamente

Hemos puesto nuestra primera piedra en Visual Basic. Este ejemplo es muy sencillo. Visual
Basic es tan sencillo como este ejemplo.

(*) Las temporizaciones no se hacen realmente así. El ejemplo anterior no deja de ser una
forma sencilla de detener el programa, para que en los comienzos de su carrera como
programador pueda ver el contenido de una etiqueta. Si lo hiciera de esta forma, su ordenador
estaría detenido realizando una función bastante triste, contar hasta 1000 para luego continuar
el programa. Y lo que es peor, en un ordenador a 300 MHz. Tardaría menos tiempo que en uno
a 66. Esta misma función puede hacerla con Sleep que la verá mas adelante, que es la forma
limpia y elegante de hacer una temporización

Formas de salir de un bucle

Para salir de un bucle, podemos esperar a que se complete, bien porque se ha cumplido la
condición (Bucles por condición) o a que se haya llegado al final de la cuenta (Bucles por
contador). Pero puede ocurrir que interese salir del bucle sin haber terminado la ejecución total
del mismo, por ejemplo, porque ya hemos encontrado lo que estabamos buscando, y sería una
pérdida de tiempo seguir ejecutando el bucle cuando ya hemos obtenido lo que buscamos.
Para ello, basta con ejecutar la sentencia Exit Do (Cuando hemos comenzado el bucle con Do
Until o Do While, o con Exit For cuando lo hemos comenzado con For ... To

Ejemplos

En el siguiente ejemplo pretendemos parar el programa cierto tiempo, a la espera que otro
equipo se conecte a través del puerto serie. (Cuando se conecte, el control MSComm1
detectará la señal DSR que le envía el otro equipo y deberemos salir inmediatamente del bucle
para, por ejemplo, atender a ese puerto serie)

Contador = 0
Do While Contador < 1000
Contador = Contador + 1
DoEvents
If MSComm1.DSRHolding = True Then Exit Do
Sleep (1000)
Loop

‘Aquí comenzamos a atender al puerto serie

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 17


En el siguiente ejemplo, deseamos transmitir por el puerto serie una serie de números, del 1 al
1000, pero siempre y cuando que el equipo que está al otro lado de la línea serie esté a la
escucha (Condición MSComm1.DSRHolding = True) Si se desconecta ese equipo, y la
condición pasa de True a False, deseamos salir del bucle:

For I = 1 To 1000
If MSComm1.DSRHolding = False Then Exit Do
MSComm1.Output = Str(I)
Next I

No se preocupe que no entienda esto del MSComm. Lo entenderá perfectamente unos


capítulos mas adelante. Lo importante es que entienda la idea de salir de un bucle por la vía
rápida.

Función DoEvents

Si hablameos de bucles, necesariamente debemos hablar de la función DoEvents. Y es así por


la misma razón que cada vez que ponemos un bucle, deberíamos poner dentro de ese bucle la
palabra mágica DoEvents.

Imagínese que Visual Basic está ejecutando este código:

Do While Valor < 100


Valor = valor + 1
If Valor = 90 then Valor =1
Loop

Observará que la variable Valor nunca podrá llegar a tener el valor 100, puesto que cada vez
que llega a 90 le ponemos de nuevo el valor 0. El programa no va a salir nunca del bucle, pero
además no podrá atender a otros eventos que se produzcan en el ordenador (por ejemplo la
pulsación de una tecla) ya que el microprocesador está atendiendo solamente a ese bucle. Si lo
está ejecutando desde el propio entorno de Visual Basic, deberá parar la ejecución mediante las
teclas Ctrl – Pausa. No podrá pararlo mediante el botón Terminar de la barra de herramientas
de VB. En un programa compilado posiblemente tenga que reiniciar el equipo mediante Alt –
Ctrl – Sup, llevándose por delante el resto de los programas que se estén ejecutando en ese
momento en su PC.

No es difícil cometer este error involuntariamente. Esto es lo que se llama un bucle infinito. Para
que no suceda, o al menos, que si nuestro programa entra en un bucle infinito se pueda salir de
una forma no tan agresiva, hay que introducir dentro del bucle la instrucción DoEvents. Cuando
VB encuentra esta función el control del microprocesador al sistema operativo, y si hay alguna
operación en espera (la pulsación de una tecla, por ejemplo) la ejecuta y posteriormente vuelve
a ejecutar el bucle. De esta forma, podemos salvar al menos los datos de las otras aplicaciones
que se están ejecutando al mismo tiempo.

El bucle tomaría esta forma:

Do While Valor < 100


Valor = valor + 1
If Valor = 90 then Valor =1
DoEvents
Loop

Salir de un procedimiento antes de terminar su ejecución

Y ya que explicamos como se sale de un bucle por la vía rápida, veamos como salir de un
procedimiento usando también esa “vía rápida”.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 18


Para salir de un procedimiento basta con ejecutar la sentencia Exit Sub. En el ejemplo
siguiente, usamos el botón BotonLeerNombre para introducir el dato Nombre en una base de
datos. Pero ese campo puede tener como máximo, 20 caracteres. Si el usuario ha introducido
mas de 20 caracteres, debemos salir del procedimiento donde se introduce ese dato sin
ejecutarlo de forma íntegra:

Private Sub BotonLeerNonbre_Click()


Mivariable = Text1.Text
If Len(Mivariable) > 20 Then
MsgBox "El Campo Nombre debe tener como máximo 20 caracteres"
Text1.Text = ""
Exit Sub ‘Con esta instrucción saldríamos de este procedimiento
Else
'Aqui vendrían las lineas de instrucciones donde trataríamos
'el contenido de Text1, si tuviese menos de 20 caracteres
End If
End Sub

NOTA. Los ejemplos anteriores sirven solamente de ilustración para explicar el código que
estamos estudiando. No pretenda ver una forma mejor de realizar la misma función, que seguro
que existe.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 19


BASIC DE VISUAL BASIC (y2)

Funciones de cadena

Se denomina CADENA a una sucesión de caracteres. Una cadena puede tener uno o varios
caracteres alfanuméricos. Una cadena es también una sucesión de números.

Ejemplo de cadenas:

Curso de Visual Basic


abcdefghijklmnopqrstuvwxyz1234567890
123456789

Hagamos una distinción entre una cadena que contenga números y un número. Un número
tiene un valor, pero también tiene una presentación escrita. El valor es algo que estará en el
ordenador como una sucesión de bits. Dependiendo de como lo hayamos declarado, tendrá
mas o menos bits. Pero esa información no es un número legible por el usuario. Lo que sí es
legible por el usuario es la representación en numeración decimal (u octal, o hexadecimal, o
incluso en binario) de ese número. Esa representación del número en un determinado sistema
de numeración es una cadena.

Así, el número nueve, que en la memoria del ordenador será una sucesión de bits, nos lo podrá
presentar como:

9 En numeración decimal
9 En numeración hexadecimal
11 En numeración octal
1001 En numeración binaria

Esas formas de presentarnos el número son CADENAS de caracteres. El valor del número
dentro del ordenador es un NUMERO.

Para presentar un número en la pantalla, el ordenador debe convertirlo previamente a una


cadena.

Cuando introducimos un valor numérico por teclado o pantalla, el ordenador para hacer
operaciones con él, debe transformarlo a un número.

Estas consideraciones nos llevan a las dos primeras funciones con cadenas:

Str (número) Convierte un número a una cadena en numeración


decimal.

Val (cadena numérica) Obtiene el valor (el número) correspondiente a esa


cadena.

Ejemplos

Variablenumerica = Val (TextBox1.Text)

Este ejemplo convierte la cadena de caracteres (numéricos) que hubiese en la caja de


texto TextBox1 en un número, y asocia este número a la variable Variablenumerica.
Si el contenido de la caja de textos no fuesen caracteres numérico (abcd, por ejemplo),
Variablenumerica tomaría el valor 0.

Label1.Caption = Str (Variablenumerica)

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 20


Este ejemplo pondría en la etiqueta Label1 los caracteres correspondientes al valor que tuviese
la variable Variablenumerica .

Nota para recordar: Siempre habrá que convertir un número a una cadena cuando queramos
presentarlo en la pantalla. Siempre habrá que convertir a número la cadena de caracteres
numéricos que hayamos introducido por teclado o por pantalla, cuando queramos operar con
ese número. Un Label, cuando tiene que presentar un único número, no le pedirá que se lo
convierta a cadena, pues VB hace automáticamente esa conversión. Sin embargo, cuando tiene
que presentar un número, y además un texto en el mismo Label, VB no realizará
automáticamente ese cambio, por lo que le dará un error. Le recomiendo que convierta los
números a variables de cadena siempre que los quiera presentar en un Label o TextBox.
Cuando tenga mas experiencia en VB verá que esta observación estará un poco de más. Pero
de momento, convierta cada dato según lo vaya a necesitar.

Existe una función mas amplia que Str. Se trata de Cstr. Esta función no solamente transforma
un número a una cadena, como hace Str, sino que convierte cualquier tipo de variable a una
variable tipo String (cadena).

Esta función transforma, por ejemplo, una variable tipo Booleana en una variable de cadena,
devolviendo la cadena “Verdadero” si el valor de la variable booleana es True, y “Falso” si es
False.

Puede también transformar a una cadena de caracteres el valor de un CheckBox o de un


OptionButton. En estos casos devuelve 0 y 1 para el CheckBox (Desactivado / Activado) y
Verdadero ó Falso para el OptionButton (Activado / Desactivado)

label1.Caption = CStr(booleana) Label1.Caption = Verdadero si booleana es true


Label1.Caption = Falso si booleana es False

Label2 = CStr(Check1.Value) Label2.Caption = 1 si Check1 está activado


Label2.Caption = 0 si Check1 está desactivado

Label3 = CStr(Option1.Value) Label3.Caption = Verdadero si Check1 está activado


Label3.Caption = Falso si Check1 está desactivado

Si se aplica Cstr a una variable tipo Fecha/Hora devuelve la fecha / Hora en formato corto.

Vea mas adelante la colección de funciones Cxx

Mas funciones de cadena:

Left (cadena, n)
Extrae los n primeros caracteres de una cadena, comenzando por la izquierda.

Si cadena = Curso de Visual Basic (Para todos los ejemplos)

Resultado = Left (cadena, 10) ----> Resultado = Curso de V

Right (cadena, n) Extrae lo n últimos caracteres de la cadena

Resultado = Right (cadena, 10) ----> Resultado = sual Basic

Mid (cadena, m, n) Extrae n caracteres de la cadena, siendo el primer carácter


extraído el que ocupa el lugar m.

(Vea Instrucción Mid mas abajo)

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 21


Resultado = Mid (cadena, 3, 10) ----> Resultado = rso de Vis

LCase (cadena) Devuelve otra cadena igual, pero con todos los
caracteres en minúsculas. (LCase = Lower Case)

Resultado = Lcase (cadena) ----> Resultado = curso de visual basic

UCase (cadena) Devuelve otra cadena igual, pero con todos los
caracteres en mayúsculas. (UCase = Upper Case)

Resultado = UCase (cadena) ----> Resultado = CURSO DE VISUAL BASIC

Len (cadena) Devuelve la longitud de la cadena

Resultado = Len (cadena) ----> Resultado = 21

LenB (Cadena) Devuelve el número de Bytes empleados para almacenar la


cadena. Sorpréndase, es el doble que Len (Cadena)

String (n, carácter) Devuelve una cadena de n caracteres como el indicado

Resultado = String (8, "a") ----> Resultado = aaaaaaaa

Resultado = String (8, Chr(65)) ----> Resultado = AAAAAAAA

Resultado = String (8, 65) ----> Resultado = AAAAAAAA

Space (n) Devuelve una cadena formada por n espacios.

Resultado = "A" + Space (6)+ "B" ----> Resultado = A B

LTrim Elimina los posibles espacios que tenga una cadena por
Su izquierda.

Rtrim Elimina los posibles espacios que tenga una cadena por
Su derecha.

Trim Elimina los espacios que tenga una cadena, tanto por su
izquierda como por su derecha. (No elimina los espacios
centrales de la cadena)

Estas tres funciones se emplean para quitar los posibles espacios que pueden resultar
de una entrada de datos. Tienen especial importancia cuando se toman los datos de un archivo
o base de datos, donde fueron introducidos por otro programa.

La función Trim hay que usarla cada vez que convertimos un número a cadena de caracteres.
Cuando usamos Str(Número), la función Str introduce un espacio al comienzo de la cadena
que, en la mayor parte de los casos, produce un error cuando lo vamos a comparar, a introducir
en una base de datos, etc.

(Vea Ejercicio Cap11 del disco)

No se pone ningún ejemplo de estas funciones, pues sería difícil verlo impreso.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 22


InStr (cadena, cadena1) Busca la cadena1 dentro de cadena y devuelve
el número de orden dentro de cadena donde se encuentra la primera letra de cadena1

Resultado = InStr (cadena, "sua") ----> Resultado = 12

StrConv Convierte una cadena de caracteres en otra, según las


instrucciones que le sigan. Puede sustituir a UCase o LCase si la
instrucción es UpperCase o LowerCase respectivamente, o poner la
primera letra de todas las palabras de la cadena en mayúsculas, si la
instrucción es ProperCase.

Resultado = StrConv (cadena, UpperCase) ----> Resultado = CURSO DE


VISUAL BASIC

Resultado = StrConv (cadena, LowerCase) ----> Resultado = curso de visual


basic

Resultado = StrConv (cadena, ProperCase) ----> Resultado = Curso De Visual


Basic
Instrucción Mid

Mid puede usarse también para cambiar el contenido de una cadena. Observe la sutileza entre
Mid como Función de cadena y Mid como Instrucción.

La Instrucción Mid reemplaza un número especificado de caracteres en una variable de cadena


con caracteres de otra cadena.

Sintaxis Mid(cadena1, inicio[, longitud]) = cadena2

Mid (cadena, 7,2)=”AB” ---- > Resultado = Curso AB Visual Basic

Si la cadena que vamos a introducir tuviera más caracteres, tomará solamente los primeros

Mid (cadena, 7,2)=”ABCDE” ---- > Resultado = Curso AB Visual Basic

Funciones Asc y Chr


Estas funciones se utilizan para obtener el número ASCII de un carácter, y para, sabiendo el
número ASCII, hallar el carácter correspondiente.

Función Asc

Devuelve el código de carácter correspondiente a la primera letra de una cadena de caracteres.

Sintaxis MiVariable = Asc (Cadena)

Cadena es cualquier expresión de cadena válida. Si la cadena no contiene caracteres, ocurrirá


un error en tiempo de ejecución.

Ejemplo : Label1 = Asc (“ABCD”) Label1 presentará 65

Nota Hay otra función (AscB) que puede usarse con bytes contenidos en una cadena. En
lugar de devolver el código del carácter para el primer carácter, AscB devuelve el primer byte.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 23


Función Chr

Devuelve el carácter asociado con el código de carácter especificado.

Sintaxis Chr (CódigoCarácter)

El argumento CódigoCarácter es un número en el intervalo de 0 a 255, inclusive, que identifica


a un carácter.

Ejemplo Label1 = Chr (65) Label1 contendrá el carácter A

Como ejemplos de números de caracteres algo especiales se debe señalar el carácter 10


(avance de línea) y el carácter 13 (Retroceso de carro). La tecla ENTER produce ambos
caracteres cada vez que se pulsa.

Otros caracteres importantes son, el Backspace (carácter 8), y el espacio (carácter 32)

Nota Se proporciona otra función (ChrB) para su uso con datos de byte incluidos en una
cadena. En lugar de devolver un carácter, que puede ser de uno o de dos bytes, ChrB siempre
devuelve un solo byte.

FUNCIONES CON NUMEROS


_________________________

Visual Basic puede operar con números tal como lo haría cualquier persona. Conoce las 4
reglas, y puede utilizar paréntesis de la misma forma que los escribimos sobre el papel.

Los operadores que utiliza para las operaciones básicas son:

+ Suma
- Resta
* Multiplicación
/ División
\ División sin decimales
Mod Resto de una división
^ Eleva a un exponente

Ejemplos

Resultado = 12 + 15 ----> Resultado = 27


Resultado = 15 - 12 ----> Resultado = 3
Resultado = 15 * 12 ----> Resultado = 180
Resultado = 15 / 12 ----> Resultado = 1.25
Resultado = 15 \ 12 ----> Resultado = 1
Resultado = 15 Mod 12 ----> resultado = 3
Resultado = 12 ^ 2 ----> Resultado = 144

resultado = ( ( 4 * 3 ) / 2 ) ^ 2 ----> Resultado = 36

Estos operadores se denominan Operadores aritméticos.

Existen otras operaciones que se pueden realizar con números: comparaciones. Los
operadores que realizan comparaciones se denominan Operadores relacionales. El resultado
de las operaciones realizadas con estos operadores solamente admiten dos resultados: True
(Cierto) o False (Falso) Estos operadores son:

= Igual que
<> No igual que
LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 24
< Menor que
<= Menor o igual que
> Mayor que
>= Igual o mayor que

Estos operadores se suelen utilizar en estructuras de programa donde se tome una decisión.

El operador = puede usarse también para comparar cadenas o fechas.

Operadores Lógicos

Estos operadores podemos usarlos con variables Booleanas, es decir, aquellas que solamente
pueden tomar los valores cero y uno, y con caracteres (un carácter = 1 Byte = 8 bits) realizando
la operación correspondiente bit a bit con los 8 bits de cada carácter. Pero en este caso, los
parámetros deben introducirse en decimal. Por ejemplo, si quiere realizar la función And entre
el carácter 15 (00001111) y el 131 (10000011) , debe ponerlo de la forma Resultado = 15 And
132. El resultado de esta operación será el byte 00000011, pero como Ud. ya se habrá dado
cuenta, le devolverá el valor 3. En el ejercicio Cap11 puede ver un ejemplo muy explicativo

Operador Devuelve True si Devuelve False si

And A=True y B=True Cualquier otro caso

Or A=True o B=True A=False y B=False

Xor A=True y B=False A=True y B=True


A=False y B=True A=False y B=False

Eqv A=True y B=True A=True y B=False


A=False y B=False A=False y B=True

Imp A=True y B=True A=True y B=False


A=False y B=True
A=False y B=False

Not A=False A=True

Like A=True A=False

Otras Funciones con números

Int , Fix Devuelven la parte entera de un número con decimales

Int y Fix eliminan la fracción de un número y devuelven el valor entero resultante. La diferencia
entre Int y Fix es que si el número es negativo, Int devuelve el primer entero negativo menor o
igual a número, mientras que Fix devuelve el primer entero negativo mayor o igual a número.
Por ejemplo, Int convierte -8,4 en -9, y Fix convierte -8,4 en -8.

Abs Devuelve el valor absoluto de un número

Sgn Devuelve el signo de un número

Sqr Devuelve la raíz cuadrada de un número

Exp Devuelve el número elevado al exponente


indicado

Log Devuelve el logaritmo natural de ese número

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 25


Trigonométricas

Sin Devuelve el valor del seno de un ángulo


(Expresado en radianes)

Cos Devuelve el coseno de un ángulo (En radianes)

Tan Devuelve la tangente de un ángulo

Atn Devuelve un arco cuya tangente sea el número


(Angulo en radianes)

Funciones para el Cambio de Base de Numeración


Función Hex Devuelve una cadena, es decir, un string, que representa el valor
hexadecimal de un número.

Sintaxis VariabledeCadena = Hex (número)

Si número no es un número entero, se redondea al número entero más cercano antes de ser
evaluado.

Mediante esta función se puede convertir un número de hasta ocho caracteres hexadecimales.

Se pueden representar números hexadecimales directamente, anteponiendo &H. Por ejemplo,


&H10 representa al decimal 16 en la notación hexadecimal.

Función Oct Devuelve la cadena (String) que representa el valor octal de un


número.

Sintaxis VariabledeCadena = Oct (número)

Si número no es entero, se redondea al número entero más cercano antes de ser evaluado.

Puede realizarse la conversión hasta el valor de 11 caracteres octales.

Se pueden representar números octales directamente, anteponiendo &O a números en el


intervalo apropiado. Por ejemplo, &O10 representa a 8 en base diez en la notación octal.

Recuerde que estas dos funciones devuelven una Cadena de caracteres, no un número.
El resultado deberá tratarlo como una cadena de caracteres.

Funciones Cxxx para conversión del tipo de datos.


Son un tipo de funciones que convierten un dato o expresión a un tipo de datos determinado

Función Cbool Convierte una expresión al tipo de datos Boolean.

Sintaxis VariableBooleana = Cbool (expresión)

El argumento expresión es cualquier expresión numérica o expresión de cadena válida.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 26


Si expresión es cero, se devuelve False; de lo contrario, se devuelve True Si la expresión no se
puede interpretar como un valor numérico, ocurrirá un error de tiempo de ejecución.

Función CByte Convierte una expresión al tipo de datos Byte.

Función CCur Convierte una expresión al tipo de datos Currency. (Moneda)

Función CLng Convierte un dato a un tipo Long.

CLng se diferencia de las funciones Fix e Int en que trunca, en vez de redondear, la parte
fraccionaria de un número. Cuando la parte fraccionaria es exactamente 0,5, la función CLng
siempre la redondea al número par más cercano. Por ejemplo, 0,5 se redondea a 0 y 1,5 a 2.

Función CInt Convierte un dato a un tipo Integer.

CInt se diferencia de las funciones Fix y Int en que trunca, en vez de redondear, la parte
fraccionaria de un número. Cuando la parte fraccionaria es exactamente 0,5, la función CInt
siempre la redondea al número par más cercano. Por ejemplo, 0,5 se redondea a 0 y 1,5 a 2.

Función CDbl Convierte una expresión al tipo de datos Double.

Función CSng Convierte una expresión a un tipo de datos Single.

Debe usar las función CByte, CCur, CLng, CInt en lugar de Val para proporcionar
conversiones que reconozcan las variantes internacionales, cuando se convierte de cualquier
otro tipo de datos. Por ejemplo, los diferentes separadores decimales se reconocen
adecuadamente, dependiendo de la configuración de la información local de su PC.
Si la expresión a convertir queda fuera del intervalo aceptable para el tipo de datos a obtener,
ocurrirá un error.

Función CStr Convierte una expresión a un tipo de datos String.

Debe usar la función CStr en lugar de Str para proporcionar conversiones que reconozcan las
variantes internacionales, cuando se convierte de cualquier otro tipo de datos a String. Por
ejemplo, los diferentes separadores decimales se reconocen adecuadamente, dependiendo de
la configuración de la información local de su sistema.

Dependiendo del tipo de dato que se va a convertir, CStr devuelve:

Boolean String conteniendo True o False.


Date String conteniendo una fecha en el formato de fecha corta de su sistema.
Null Un error de tiempo de ejecución.
Empty String de longitud cero ("").
Error String conteniendo la palabra Error seguida del número de error.
Numérico String conteniendo el número.

Función Cvar Convierte una expresión a un tipo de datos Variant.

Función Cdate Convierte una expresión al tipo de datos Date. (Fecha / Hora)

Nota curiosa y a tener muy en cuenta

En algunas ocasiones (no siempre, misterios del VB) cuando hacemos una operación entre
números, cuyas variables que los contienen se han declarado de distinto tipo, puede ocurrir que
dé un error. Por ejemplo, queremos obtener una suma que debe ser un Long, a partir de varios
números tipo Byte. Declaramos las variables de la siguiente forma:

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 27


Dim Suma as Long, I1 As Byte, I2 As Byte, I3 As Byte, I3 As Byte, I5 As Byte

Suma = I1 + I2 + I3 + I4 + i5

El resultado de esta operación es que da un error, pues no entiende que sumando varios Byte
(números comprendidos entre 0 y 255) puedan dar un número de otro tipo. Dará seguramente
el error 6, Overflow. Para que esto no suceda, haremos el truco de convertir el primero de los
números que forman parte en la operación matemática a un Long, y de esta forma, VB ya se da
cuenta que el resultado de esa operación es un Long:

Suma = CLng(I1) + I2 + I3 + I4 + I5

Tenga en cuenta esa observación inicial que NO ocurre en todas las ocasiones. (Y me parece
que era un fallo de los muchos que tenía VB5)

Otras Funciones
Una función curiosa

Timer Tiempo acumulado Devuelve el tiempo (en segundos) que ha


pasado desde las 12 de la noche.

Generación de números aleatorios

Randomize (Numero) Inicia el generador aleatorio tomando como dato de partida


el Numero. Devuelve el resultado en una variable llamada Rnd.

NOTA MUY IMPORTANTE para versiones de VB anteriores a la 6.- Los números aleatorios
generados de esta forma son siempre iguales, eso sí, dependiendo del número que se le
introduzca como parámetro. Esta generación de números no produce números aleatorios pues
como se dijo, dependen del numero que se meta como parámetro, y si este se repite, se repite
la sucesión de números que nos crea el generador aleatorio. (Afortunadamente lo han corregido
en la versión 6)

La forma de obtener números realmente aleatorios es introducir como parámetro un número


que sea variable con el tiempo. Ese número no puede ser otro que el número timer visto antes.
Y siempre con la precaución de que medie mas de un segundo entre dos instrucciones
Randomize. La función toma entonces la forma:

Randomize Timer

La función Randomize devuelve una variable Rnd con un número comprendido entre 0
y 1 (Nunca será 0 ni 1) Leyendo el valor de la variable sucesivas veces, se puede obtener una
sucesión de números aleatorios. No es necesario ejecutar la instrucción Randomize Timer
cada vez que se quiera obtener un dato de la variable Rnd.

Un ejemplo. Generador de números para la Lotería Primitiva

Supongamos que tenemos un formulario con una etiqueta de nombre Label1, un botón de
comando de nombre Command1. Cuando hagamos click sobre el botón de comando deberá
generar un número comprendido entre el 1 y el 49. En el procedimiento click de Command1
pondremos el siguiente código:

Private Sub Command1.click

Randomize Timer

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 28


A = Rnd * 100
A = CInt(A)
Do While A > 49
A = A - 49
Loop
Do While A < 1
A = A + 49
Loop
Label1.caption = A
End Sub

Realice este pequeño programa, con la instrucción Randomize Timer y sin ella.

Funciones con fechas.


Las fechas son cadenas especiales. Visual Basic sabe obtener y tratar la información relativa a
la fecha y la hora. Dispone para ello de una declaración de variable: Date. Una variable
declarada como date puede contener una fecha, una fecha y una hora o una hora solamente.

Date Devuelve la fecha de hoy. Esta fecha la toma del reloj del ordenador.

Time Devuelve la hora actual.

Now Devuelve la fecha y hora actual.

WeekDay Devuelve el día de la semana (En número, 1=Domingo, 2=Lunes,...)

Day Obtiene el día, a partir de una fecha

Month Obtiene el mes a partir de una fecha.

Year Obtiene el año a partir de una fecha.

Hour Obtiene la hora a partir de una hora

Minute Obtiene el minuto a partir de una hora.

Second Obtiene el segundo a partir de una hora.

DateAdd Añade un intervalo de tiempo a una fecha

DateDiff Obtiene el intervalo de tiempo entre dos fechas

DatePart Devuelve una parte de una fecha (semana, trimestre, etc.)

DateSerial Compone una fecha a partir de parámetros relativos

TimeSerial Compone una hora a partir de parámetros relativos.

DateValue Devuelve una fecha a partir de un dato que se le parezca y VB


pueda obtener de él una fecha válida

Mediante estas instrucciones podemos obtener el dato necesario de una fecha u hora. Por
ejemplo, para obtener el día de hoy solamente:

Día = Day (Now) Día será un número

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 29


El día de la semana lo obtendríamos

Diasemana = WeekDay (Now) Diasemana será un número

DateValue, una instrucción que le sacará mucho provecho

Fecha = DateValue (12-07-96)


Fecha = DateValue (12 07 96) Fecha =12/07/96

La función DatePart merece estudio aparte. Con esta función podemos averiguar el mes,
trimestre, semana, día del año, etc.

La sintaxis de esta función es :

VariableNumérica = DatePart (Intervalo, fecha[, primerdíasemana[, primerasemanaaño]])

Valor para Intervalo Obtendremos el


q Trimestre
m Mes
y Día del año
d Día
w Día de la semana
ww Semana
h Hora
n Minuto
s Segundo

El parámetro Primerdíasemana puede ser un número o una constante (veremos a lo largo de


todo el curso, que VB usa constantes que son palabras reservadas por VB que generalmente
comienzan por vb) que indica que día es para nosotros el primero de la semana

Constante Número Primer día de la semana


vbSunday 1 Domingo (predeterminado)
vbMonday 2 Lunes
vbTuesday 3 Martes
vbWednesday 4 Miércoles
vbThursday 5 Jueves
vbFriday 6 Viernes
vbSaturday 7 Sábado

Para el parámetro primerasemanaaño podemos emplear uno de los siguientes números o


constantes:

Constante Valor Descripción

vbFirstJan1 1 Empieza con la semana en la que se encuentra el 1 de enero


(predeterminado).
vbFirstFourDays 2 Empieza con la primera semana que tenga al menos
cuatro
días en el año nuevo. (Standard ISO 8086)
vbFirstFullWeek 3 Empieza con la primera semana contenida
completamente en
el año nuevo.

Por ejemplo, y tomando como referencia para todos los ejemplos el día 22 de Septiembre de
1998, fecha en la que se ha escrito este texto, (Now = 22/09/1998), tenemos :

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 30


Variable = DatePart (“m”, Now) Variable = 10
variable = DatePart ("q", Now) Variable = 3
variable = DatePart ("d", Now) Variable = 22
variable = DatePart ("y", Now) Variable = 265
variable = DatePart ("w", Now) Variable = 3 (Martes, pues el primer día de la semana
era el domingo - Predeterminado)
variable = DatePart ("w", Now, vbMonday) Variable = 2 (Primer día semana = lunes)
variable = DatePart ("ww", Now, vbMonday, vbFirstFourDays)
Variable = 39, que indica el número de la semana dentro del año.

Cuidado con como se escriben las fechas. Una posibilidad es la usada en los ejemplos, pero
solamente vale para el día de hoy. Puede expresar la fecha metiéndola entre dos signos #, pero
en ese caso debe estar expresada en el formato mm/dd/yy (mes/día/año). Ejemplo :

variable = DatePart("ww", #9/22/98#, vbMonday, vbFirstFourDays)

Pero lo mas fácil para el formato de fecha usado en España es meter la fecha entre comillas
dobles, y usar el formato especificado para el país :

variable = DatePart("ww", "22/9/98", vbMonday, vbFirstFourDays)

Con las comillas dobles puede incluso no poner el año. En este caso le pone por defecto, el año
en curso.

variable = DatePart("ww", "22/9", vbMonday, vbFirstFourDays)

Estas tres formas de expresar la fecha funcionan perfectamente, al igual que cuando lo
hacíamos con Now, y el resultado sigue siendo 39.

Nota para recordar de las variables tipo Date

(No se extrañe que esta explicación la encuentre solamente en esta Guía del Estudiante)

Visual Basic trata las fechas como números. Y precisamente como un número Double. Emplea
por lo tanto 8 bytes para representar una fecha. Por ejemplo, al día 12 de Julio de 1999, (Fecha
en la que el autor de este libro alcanzó la respetable edad de #9 años) le corresponde el valor
de 36563. Ese es el número de días transcurridos desde el origen de tiempos tomado por VB
(Y por muchas otras aplicaciones de Microsoft y de otras marcas) hasta ese fatídico día. ¿ Cual
es ese origen del tiempo? El 30 diciembre 1899. ¿Que porqué ese día?. No lo sé. Pero es fácil
intuir que motivos prácticos para que cualquier fecha del siglo XX tuviese un número positivo.
Porque las anteriores a ese día las trata como números negativos. Por ejemplo, el día 12 de
Octubre de 1492, VB lo trata como el día número - 148.732. Ese numero puede conocerlo
utilizando la función CDbl sobre una variable tipo Date. Puede verlo en el ejercicio Cap12 del
disco.

Una hora también es una variable tipo Date. Y una composición Día / Hora también. ¿Que
como trata los minutos dentro de una variable Date? Pues como decimales de ese número
Double. Por ejemplo, la hora 12:00:00 del día 12 de julio de 1999 es para VB

36.563,5

Es decir, la parte decimal representa la fracción de día transcurrido desde el comienzo del día
(medianoche) hasta la hora en cuestión. No debemos confundir esta fracción del día (0,5 para
las 12:00:00) con el valor de la función Timer para ese instante (45.000)) que representa el
número de segundos transcurridos desde la 12 de la noche de ese día.

Cuando se tratan variables tipo Date, VB que es un lenguaje inteligente, interpreta como tipo de
LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 31
datos Date determinados datos que no lo son. Por ejemplo, 12 Julio 1999 es tal y como puede
verse, una sucesión de caracteres. Si ejecutamos el código:

Dim Pepe as Date


Pepe = “12 Julio 1999”
‘ A partir de ahora, Pepe contendrá el valor 36.563
‘ Para ver ese valor basta con hacer
Label1.Caption = CDbl (Pepe)

Al estar Pepe declarada como variable tipo Date, VB busca todas las posibilidades de extraer
una fecha (o una hora) del dato que le estamos metiendo. Otra cosa ocurriría si la
declarásemos como String o Variant. En cualquiera de estos casos, Pepe contendría el literal
introducido, es decir, “12 Julio 1999”

De lo anterior se desprende una cosa, dado que la fecha la guarda como un número, no importa
en que formato le introduzcamos una fecha. Si ponemos que Fecha1 = “12/7/99” es idéntico a
poner fecha1 = 12/07/1999 ó Fecha1 = 1999-07-12. Eso sí, debe reconocer el formato, y luego,
el dato, lo tratará como un número Double. Lo volveremos a ver cuando estudiemos las bases
de datos. Access trata las fechas de idéntica forma.

Función FORMAT

Esta función permite presentar cadenas numéricas o fechas de una determinada forma.
Permite establecer el Formato de esa cadena.

Si recurre a la ayuda de VB acerca de esta función se va a enterar muy poco de lo que puede
dar de sí. La sintaxis que presenta es :

Format(expresión[, formato[, primerdíadesemana[, primerasemanadelaño]]])

Lo mejor que puede hacer con esta definición de la sintaxis de Format es olvidarla. No le aclara
mucho lo que se puede hacer con Format. La función Format se usa para poner una fecha en
un determinado formato. Con la expresión :

FechadeHoy = Format (Now, “yyyy-mm-dd”)

la variable FechadeHoy tendrá el valor 1998-05-21, que se refiere al día 21 de mayo de 1998,
según el formato recomendado por la norma ISO-8601 para la presentación de fechas. Si
hubiésemos puesto la expresión FechadeHoy = Format (Now, “dd/mm/yy”) , la variable
FechadeHoy contendría el valor 21/05/98 referido al día citado.

Las posibilidades de Format llegan también al campo de las cadenas numéricas. Por ejemplo la
cifra 123456 se transformará en las siguientes expresiones, según como empleemos la función
Format

Variable = Format(123456, "Currency") Variable = 123.456 Pts


Variable = Format(123456, "Standard") Variable = 123.456,00

Veamos ahora con un poco mas de conocimiento la sintaxis de Format

Variable = Format (expresión[, formato[, firstdayofweek[, firstweekofyear]]])

No se complique la vida con el tema del primer día de la semana ni la primera semana del año.
No lo usará con frecuencia. Centrémonos mas en el parámetro Formato. Puede tomar muchos
valores. Veamos los principales. Primero para números

Observe que usamos la expresión Variable = Format (1234567,”Formato”) para todos los
LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 32
ejemplos de números.

Para poner los números separados por millares :

Variable = Format(1234567, "##,###,###") Variable = 1.234.567

(Cada carácter # indica que ahí va un número. El separador debe ser una coma, no un punto,
aunque esto depende del idioma que esté usando)

Puede poner una de estas expresiones, eso si, siempre entre comillas dobles :

General Number Muestra el número tal como lo tecleó


Currency En formato de la moneda de su sistema operativo
Fixed Sin separador de millar y dos decimales (1234567,00)
Standard Con separador de millares y dos decimales (1.234.567,00)
Percent Multiplica el número por cien y lo presenta cono
porcentaje(123456700,00%)
Scientific Usa notación científica (1,23E+06)
.

Para fechas (Observe que usamos el ejemplo Format(Now, “Formato”) siendo Now la fecha
y hora actual (21/07/98 a las 22:16:00 )

General Date 21/07/98 22:16:00


Long Date martes 21 de julio de 1998
Medium Date 21-jul-98
Short Date 21/07/98
yyyy-mm-dd 1998-05-21
yy-mm-dd 98-07-21
Long Time 22:19:53
Medium Time 10:20 PM
Short Time 22:20
hh :mm :ss 22 :21 :29
hh :mm 22 :21

RECOMENDACIÓN ISO 8601

Va como cultura general. Esta recomendación dice que el formato de fecha debe ponerse de la
forma yyyy-mm-dd (p.e. 1998-10-05 para referirse al 5 de Octubre de 1998). Para este
formato, pondremos :

FechaISO8601 = Format (Now, “yyyy-mm-dd”)

Tenga presente esta recomendación. La Administración Española está obligada a exigir su


cumplimiento en todas aquellas aplicaciones que realicen intercambios de fecha y hora.

Format dispone de mas opciones. Sería muy largo explicarlas aquí. Para mas información, en
la WEB de Microsoft (www.microsoft.com) puede encontrar mas formatos posibles.

Pero vamos a volver con el tema de las variables tipo Date.

Cuando realizamos el Format sobre una fecha, esta fecha puede ser un literal (un string), o una
variable tipo fecha

Si en Text1 tenemos la expresión 12 Julio 1999, y queremos convertir esa fecha al formato ISO
8601, podemos hacerlo de cualquiera de estas dos formas:

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 33


Private Sub LFormat1_Click()
Dim Pepe As Date
Pepe = Text1.Text
LFormat1 = Format(Pepe, "yyyy-mm-dd")
End Sub

Private Sub LFormato2_Click()


LFormato2 = Format(Text1.Text, "yyyy-mm-dd")
End Sub

La función Format es suficientemente inteligente para darse cuenta que con el formato yyyy-
mm-dd le estamos pidiendo una fecha. Si le metemos una fecha no hay problema (caso de
meterle Pepe, variable declarada como Date). Pero si le metemos una cadena de caracteres
(caso de Text1.Text) intenta obtener de esa cadena una fecha válida. Si lo consigue lo
presenta. Si no lo consigue, dará un error.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 34


MATRICES
__________

Cuando utilizamos varias variables que tienen un significado similar para nosotros, pero que son
distintas (Por ejemplo, el nombre de los alumnos de una clase) podemos utilizar una matriz.
Esta matriz está formada por tantos elementos como alumnos tenga la clase. El nombre
asociado a cada uno de los elementos de la matriz puede ser:

Alumno (n) Donde n es el número por orden de lista de ese alumno.

Las matrices normalmente comienzan a numerar por el número 0. Este comienzo puede no ser
el mas apropiado para la variable que estamos planteando, pues ningún alumno tiene el
número de orden 0. Para hacer que una matriz comience a numerar por el 1 se debe definir
mediante la instrucción:
Option Base 1

que debe colocarse al comienzo del módulo o formulario donde declaremos la matriz.

Para declarar la matriz se hace como con todas las variables, especificando entre paréntesis el
número de elementos que componen la matriz:

Dim Alumno (25) as String

Hemos declarado que la variable alumno es una cadena, y que hay 25 elementos en esa matriz.

Una matriz también se puede declarar de la siguiente forma :

Dim Alumno(1 To 25) as String

Donde le decimos que la variable Alumno tiene 25 elementos, que el primero tiene el índice 1 y
el último tiene el índice 25.

Pero imaginemos que queremos meter en la misma matriz el nombre, primer apellido y
segundo apellido del alumno. Necesitaremos declarar una matriz de 25 por 3. Como todos los
elementos serán cadenas de caracteres, podemos declararla de la siguiente forma:

Dim Alumno (1 To 25, 1 To 3) As String

De esta forma, el primer apellido del alumno que ocupa el puesto número 15 de la clase, será el
elemento:

Alumno (15, 2)

Podemos definir matrices de dimensión superior a dos. Podemos llegar a un máximo de 60


dimensiones. Una matriz de 5 dimensiones se declararía:

Dim Variable ( 1 To N, 1 To M, 1 To P, 1 To Q, 1 To R)

entendiendo que hay N, M, P, Q y R elementos en cada una de las dimensiones


respectivamente.

Una variable ya declarada como una matriz puede redimensionarse a lo largo del programa
mediante la instrucción ReDim

ReDim Alumno (1To 25)

Mediante esta instrucción, estamos ReDimensionando una matriz ya declarada. No se puede


redimensionar una matriz inexistente.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 35


Mediante la declaración 1 To 25 le estamos diciendo que el primer elemento de la matriz es el
1, independientemente de lo que hayamos puesto en OPTION BASE. Si se redimensiona
simplemente con el número de elementos :

ReDim (25)

le estamos diciendo que tiene 25 elementos, pero que el primero sea el 0 ó el 1 depende de
haber puesto OPTION BASE 0 u OPTION BASE 1.

Una matriz puede redimensionarse cuantas veces se quiera a lo largo de la aplicación, pero esa
redimensión no puede afectar al número de dimensiones de la matriz. Si redimensionamos la
matriz perderá la información existente. Para evitar perder la información presente en la
matriz, debe utilizar la sentencia ReDim Preserve.

Si usa la palabra clave Preserve en matrices de dimensión superior a 1, va a encontrarse con


comportamientos no esperados. Como podrá ver en la Ayuda de VB, usando ReDim Preserve
sólo puede cambiar el tamaño de la última dimensión de matriz y no puede modificar en ningún
momento el número de dimensiones. NO es cierto del todo. SÍ lo podrá hacer una sola vez.

Respecto a cambiar el número de dimensiones, si ha declarado la matriz con unas dimensiones


determinadas, ya no podrá cambiar las dimensiones ni con ReDim ni con ReDim Preserve. Le
saldrá un error que dice que las dimensiones de la matriz ya han sido declaradas.
Pero si ha declarado la matriz sin dimensiones :

Dim MiMatriz()

puede cambiar las dimensiones ReDim MiMatriz (1 To 5, 1 To 9)


y volver a cambiarlas ReDim MiMatriz (1 To 8, 1 To 15, 1 To 6)

Observe que no solamente la hemos cambiado dos veces de dimensiones (la primera a 2 y la
segunda a 3), sino que también hemos cambiado el número de elementos en cada dimensión.

Si hubiésemos utilizado ReDim Preserve solamente podríamos haber usado la primera de las
dos líneas anteriores :

ReDim Preserve MiMatriz (1 To 5, 1 To 9)

pero ya no podríamos volver a cambiar el número de dimensiones con la segunda línea. Nos
daría un error.

Con ReDim podemos cambiar el número de elementos de cada dimensión cuantas veces
queramos. Por ejemplo, podemos redimensionar MiMatriz de las siguiente forma :

ReDim MiMatriz (1 To 5, 1 To 9)
ReDim MiMatriz (1 To 15, 1 To 20)
ReDim MiMatriz (1 To 25, 1 To 30)
...........................

Si hubiésemos empleado ReDim Preserve, podríamos cambiar los elementos de todas las
dimensiones de la matriz una vez :

ReDim Preserve (1 To 5, 1 To 9)

a partir de ahora, solamente podemos cambiar los elementos de la última dimensión :

ReDim Preserve (1 To 5, 1 To 20)


ReDim Preserve (1 To 5, 1 To 30)

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 36


es decir, no podremos hacer esto :

ReDim Preserve (1 To 10, 1 To 30) donde se señala en negrita el error.

Esto no causa ningún error en una matriz de una dimensión, ya que si la matriz tiene sólo una
dimensión, puede cambiar el tamaño de esa dimensión porque es la única y la última.

Cuando a lo largo de la aplicación se va redimensionando una matriz, podemos llegar la


circunstancia de que, en un momento determinado, no sepamos las dimensiones de esa matriz.

Para conocer el índice máximo y mínimo de una matriz se usan las funciones UBound y
LBound.

UBound devuelve el mayor subíndice disponible para la dimensión indicada de una matriz.

Sintaxis UBound(nombredelamatriz[, dimensión])

LBound devuelve el mayor subíndice disponible para la dimensión indicada de una matriz.

Sintaxis LBound(nombredelamatriz[, dimensión])

Ejemplo Tengamos una matriz llamada Mimatriz, de tres dimensiones. En un momento de la


aplicación se ejecutó la siguiente instrucción válida :

ReDim Mimatriz (1 To 100, 0 To 3, 5 To 20)

En otro momento queremos tener el control de los índices de esa matriz, y queremos averiguar
el índice menor y mayor de cada una de sus dimensiones :
(IID1= Indice Inferior Dimensión 1, ISD 1 = Indice Superior Dimensión 1, etc. )

IID 1= LBound (Mimatriz, 1) IID1 = 1


ISD1 = UBound (Mimatriz, 1) ISD1 = 100
IID 2= LBound (Mimatriz, 2) IID1 = 0
ISD2 = UBound (Mimatriz, 2) ISD1 = 3
IID 1= LBound (Mimatriz, 3) IID1 = 5
ISD1 = UBound (Mimatriz, 3) ISD1 = 20

Función Split
Una vez visto lo que es una matriz, vamos a ver una función interesante para el tratamiento de
cadenas de caracteres. La función Split

Descripción

Esta función toma una cadena de caracteres compuesta varias subcadenas, separadas entre
ellas mediante un separador, y devuelve una matriz de una dimensión, que contiene esas
subcadenas.

Sintaxis Split (expresión[, delimitador[, contar[, comparar]]])

Donde:

Expresion es la variable que contiene la cadena de caracteres de entrada

Delimitador. Contiene el carácter o caracteres que se usan de delimitador entre


subcadenas

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 37


Contar es un número donde indicamos el número de subcadenas que queremos
extraer. Si no se pone nada, extrae todas las cadenas. Si se pone un valor, extrae el
número de cadenas que le indiquemos. En este caso, en la última cadena, mete el
resto de subcadenas que quedaban sin meter.

Comparar es un valor numérico que nos da cuatro opciones de comparación para


comparar las subcadenas. Este parámetro es solamente para alumnos avanzados

Ejemplo.

En el siguiente ejemplo veremos como separar distintos datos que están dentro de un TextBox
(Text1) separados entre ellos por una coma.

Private Sub Command1_Click()


Dim MiVariable() As String ‘Declaramos una matriz (MiVariable) del tipo String
Dim I As Integer ‘Declaramos una variable auxiliar como numérica
MiVariable = Split(Text1.Text, ",") ‘Ejecutamos la función Split
For I = 0 To UBound(MiVariable) ‘Ejecutamos un bucle para introducir las subcadenas
List1.AddItem MiVariable(I) ‘en un ListBox
Next I
End Sub

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 38


VISUAL BASIC

Tras esta pequeña introducción al lenguaje Basic ya estamos en disposición de encender el


ordenador y comenzar a trabajar con Visual - Basic. Se supone que su PC tiene instalado el
programa Visual Basic 6.0

Entre en el programa VB. Le aparecerá en pantalla algo similar a esto : (Para VB Vers. 6)

Fig. 1.2 Aspecto del entorno de desarrollo de aplicaciones VB

Este es el comienzo del VB . Observe que en esta pantalla existen varias cosas. En la parte
superior , la barra de título del programa Visual Basic, con el texto :

Proyect1 - Microsoft Visual Basic (Diseño)

Por debajo de esta barra de Título del VB, encontramos la barra de menú de VB, con las
leyendas :

Archivo Edición Ver Proyecto Formato Depuración Ejecutar Consulta Diagrama


Herramientas Complementos Ventana Ayuda

Por debajo de esta barra de menú tenemos la barra de herramientas, donde podrá ver varios
iconos, que cada uno representa un determinada operación que Vd. puede realizar. Estas
operaciones está todas en la línea de menú, y puede acceder a ellas abriendo los menús
desplegables que existen en cada una de las palabras Archivo Edición Ver ...... de esta línea
de menú. El hecho de colocar las operaciones mas usuales en un icono en la barra de
herramientas se hace para mayor comodidad del usuario.

A la izquierda o derecha de la pantalla tiene una caja rectangular con varias columnas de
iconos. Esa caja es la Caja de Herramientas (No la confunda con la barra de herramientas de
la parte superior)

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 39


Esta caja de herramientas es, salvando las distancias, lo mismo que una caja de herramientas
real que pueda tener un mecánico para realizar su trabajo. En ella están los iconos que
representan a los controles con los que Vd. va a desarrollar su aplicación VB. No están todos
los que pueden estar, al igual que en una caja de herramientas de un mecánico no están todas
las herramientas que puede usar. Están solamente las mas usuales. Si necesita alguna mas,
puede cogerla de otra parte (barra de Menú, Proyecto | Componentes) y agregarlos a esa caja
de herramientas, al igual que lo haría un mecánico con una herramienta especial, que la
metería en su caja sólo cuando va a realizar un trabajo determinado para el que la necesite.

Posiblemente esta caja de herramientas no le aparezca tal y como la ve en esta figura. Eso
depende de la versión y la personalización. Para añadir un nuevo control haga click en
Proyecto | Componentes y le aparecerá una caja con todos los controles existentes. Puede
seleccionar nuevos controles para añadir a la caja de herramientas, marcando la casilla que
está a la izquierda del nombre del control que quiere introducir. Una vez seleccionados todos los
nuevos controles, haga click en APLICAR . Salga haciendo Click en ACEPTAR, y podrá
observar que esos nuevos controles ya se le han añadido a la caja de herramientas. Esos
controles le aparecerán cada vez que cargue el proyecto actual. No es prudente meter muchos
controles en la caja. Ponga solamente los que necesite normalmente en sus aplicaciones.
Ocupará menos memoria y tardará menos tiempo en cargar el programa VB. Además, cuando
realice una aplicación y la distribuya una vez compilada, Visual Basic entregará en los disquetes
de distribución las DLL’s u OCX’s correspondientes a todos los controles personalizados que
Vd. tenga en la caja de herramientas, los necesite el programa o no los necesite. Esto le va a
suponer que está cargando subprogramas inútiles en el ordenador destino de su aplicación. A la
hora de compilar el programa (Crear archivo .EXE) quite todos los controles personalizados que
no necesite su aplicación. (Sólo los controles personalizados. Los controles comunes -
CommandButton, Label, TextBox, etc.-, no se pueden eliminar de la caja de herramientas)

Para quitar controles de su caja de herramientas, debe proceder de forma análoga, a lo que
hizo para meterlos en la caja de herramientas, pero al revés. No se preocupe a la hora de
quitarlos. Si está utilizando un determinado control, VB no le dejará quitarlo.

En el centro, y ocupando casi toda la pantalla, tenemos el Formulario. Este Formulario es la


interface gráfica de su aplicación, sobre el que podrá añadir los controles que necesite. Lo
veremos mas adelante con todo detalle.

Puede tener dos ventanas más adosadas a la caja de herramientas, una denominada Ventana
de Propiedades, donde puede ver las propiedades del formulario o de cualquier control que
tenga dentro del proyecto, y otra, denominada Ventana de Proyecto, donde puede ver todos
los formularios existentes. Existen otras ventanas, por ejemplo la Ventana de Depuración.
Por cada formulario y cada control que introduzca en el proyecto, le aparecerá otra ventana,
denominada Ventana de código.

No se extrañe de que esta presentación gráfica del Visual Basic coincida con otros sistemas de
desarrollo (Delphi, p.e.). La lógica de desarrollo de una aplicación en Windows ha llevado a
varios fabricantes de software a utilizar un entorno gráfico similar (diríamos idéntico). A Visual
basic le queda el orgullo de ser el primero en utilizarlo. (¡Y el mejor!)

Con lo descrito anteriormente ya tenemos, al menos, fijado el argot con el que expresarnos para
comenzar a estudiar el VISUAL BASIC. Veamos con un poco mas detalle la Ventana de
Código.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 40


Fig. 1.3 Ventana de código

Esta figura le muestra un Formulario con su ventana de código. Cada objeto gráfico de VB
tiene su propia ventana de código. Así, si en este formulario hubiésemos introducido un Label y
dos CommandButton, todos ellos tendrían su propia ventana de código. La ventana de código
la podemos ver haciendo doble click sobre cualquier objeto de nuestro proyecto. En este caso
hemos hecho doble click sobre el único objeto que teníamos : el formulario.

Observe las dos cajas de la parte superior, uno con la inscripción Objeto : que en el momento
que le sacamos la foto tenía Form, y el otro con la inscripción Proc : (procedimiento), que en el
momento de la foto tenía Load. A estas cajas les denominamos Lista de Objetos y Lista de
Procedimientos respectivamente.

Haciendo click sobre la flecha de cada lista, se despliega un menú, en la lista de objetos se
desplegará una lista con los nombres de cada objeto existente en ese momento dentro del
formulario. Haciendo click sobre uno de los nombres, nos presentará la ventana de código de
ese objeto. Todos los objetos gráficos (controles) existentes dentro de un formulario y el propio
formulario aparecerán en la misma lista de objetos.

Haciendo click sobre la flecha de la lista de procedimientos, se despliega la lista con todos los
procedimientos posibles para ese objeto. Siempre saldrá uno. Si tenemos escrito código en uno
de los procedimientos, saldrá por defecto ese procedimiento para el cual hemos escrito el
código. Si no hay código en ninguno de los procedimientos, saldrá el que tenga por defecto
cada objeto.

Solamente nos queda por decir, para cerrar este capítulo, que es un procedimiento.

Para ello vamos a explicar lo que es un evento. Un Evento es algo que le puede ocurrir a un
objeto. En una interface gráfica, lo que le puede ocurrir a un objeto es que se le haga click,
doble click, que se pase el cursor del ratón por encima, etc. Este es el Evento. El
Procedimiento es la respuesta por parte de ese objeto, al evento que le está sucediendo.

Esa respuesta, esa forma de Proceder del objeto al evento que le está sucediendo, debemos
programarla según nuestras necesidades, es decir, debemos escribir el código que necesite
nuestra aplicación como respuesta al evento que acaba de ocurrir. Posiblemente, no queramos
ninguna respuesta a muchos de los eventos que pueden acaecer a un objeto. Cada objeto tiene
muchos eventos y solamente queremos aprovechar los que nos interesan. Para que un evento
no produzca ningún efecto, basta con dejar sin código el procedimiento correspondiente a ese

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 41


evento. En los eventos que queramos que realice alguna operación, le escribiremos en su
procedimiento el código necesario para que esa operación se realice. Sin darnos cuenta, hemos
comenzado a escribir el código de la aplicación.

Observará que el primer elemento del menú desplegable de la lista de objetos se denomina
General. Este no es en realidad ningún objeto, sino un apartado existente en cada formulario,
que, al desplegar su lista de procedimientos tiene la sección de declaraciones, donde
debemos declarar las variables que queremos que afecten a todo el formulario y sus controles,
y tendrá además, los nombres de todos los procedimientos que introduzcamos (véase un
poco mas adelante). En este menú desplegable de la lista de procedimientos del General verá
con frecuencia cosas que Vd. no puso allí. Cosas tales como Command1_click, y en la ventana
un determinado código. Esto ocurre cuando se borra algún control que tenía escrito código en
alguno de sus procedimientos. Visual Basic sabe lo mucho que cuesta escribir el código
asociado a un control. Si borramos un control de nuestro formulario accidentalmente, después
de haber introducido todo el código asociado a él, Visual Basic nos sorprende con que ese
código no lo tira inmediatamente, sino que lo reserva como un procedimiento en ese apartado
General del formulario. Si en realidad queríamos borrar el control y todo su código, debemos
quitarlo de ese apartado General de nuestro formulario, pues en realidad, si no lo queremos, no
hará otra cosa que estorbar. Para quitarlo basta con borrar todo el código que aparece en la
ventana de código cuando hacemos click sobre el nombre del control eliminado. Deberemos
borrar todo el código, incluida la cabecera donde figura el nombre del control eliminado, y la
parte final, que siempre termina con End Sub.

El primer estorbo lo observará si crea otro control con el mismo nombre, cosa fácil ya que VB
da un nombre por defecto a cada control (Command1, Command2....). El código asociado al
control eliminado pasará automáticamente al nuevo control con el mismo nombre.

Una aplicación puede tener todo su código escrito en los sucesivos procedimientos del
formulario y de los controles que tenga ese formulario.
Puede ocurrir que un determinado evento no esté entre los posibles eventos de los controles de
nuestra aplicación. Piense por ejemplo, el evento de que la variable A sea igual a la variable B.
No existe en ninguno de los controles ese procedimiento. No se preocupe, puede crear un
procedimiento que se ejecute cuando su programa lo decida. Podemos añadir cuantos
procedimientos queramos. Estos procedimientos se añaden al formulario, y deberán definirse
por un nombre que Vd. debe elegir. Para que se ejecuten las instrucciones (código) incluido en
ese procedimiento, basta simplemente con nombrarlo por ese nombre.
Para insertar un procedimiento debe ir a la barra de menú, hacer click sobre Herramientas, y en
el menú que le desplegará, volver a hacer click sobre Agregar Procedimiento. VB le presentará
un cuadro donde le pedirá el nombre, si quiere que sea un procedimiento, una función o una
propiedad. A lo largo del curso irá viendo que es cada cosa.

Escribiendo el código en los sucesivos procedimientos, bien en los propios de cada objeto, bien
en los procedimientos que vayamos creando, es posible completar la aplicación. Pero en una
aplicación larga esta forma de escribir el código no sería la mas adecuada. Es mas,
posiblemente sería demasiado engorroso escribirla de esta forma, y muy probablemente
deberíamos escribir el mismo código para varios procedimientos, lo que alargaría inútilmente el
programa y el tiempo de desarrollo.

Para disponer de un sitio donde escribir parte (o la mayor parte) de su programa, puede
introducir uno o varios módulos. Expliquemos lo que es un módulo.

Un Módulo es una parte del programa donde solamente puede escribir código. Es igual que un
formulario, sin interface gráfica. Un profesor de Visual Basic lo expresaba diciendo que un
Módulo es un Formulario sin cara. En un módulo pueden existir procedimientos al igual que en
los formularios, pero como un módulo no tiene interface gráfica, esos procedimientos debe
introducirlos el programador tal y como explicamos un poco mas atrás. El módulo tiene su
propia ventana de código, al igual que un formulario, con un objeto único, el apartado General.
Aquí también tenemos la sección de declaraciones, al igual que los formularios. En esta sección

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 42


de declaraciones se comporta de manera similar a la de los formularios, pero permite algo que
no nos permite la sección de declaraciones de un formulario : Declarar variables que se pueden
utilizar en todo el programa. Esto ya lo ha visto mas atrás, con la sentencia de declaración
Public.

Los módulos se emplean para la declaración de variables globales, y para escribir el código de
la aplicación que sea común a varios formularios. Esto nos evita tener que repetir código
inútilmente. Ese código común se escribirá en un procedimiento que previamente habremos
insertado en este módulo, y lo citaremos por su nombre desde cualquier parte del programa.

Los procedimientos se pueden introducir en los módulos o en los formularios. Y les pasa lo
mismo que a las variables en cuanto a su ámbito. Para agregar un procedimiento debe abrir
una ventana de código (cualquiera) perteneciente al módulo o formulario donde quiera insertar
ese módulo, y a continuación hacer click sobre Herramientas | Agregar Procedimiento de la
Barra de Menú.

Fig. 1.4 Agregando un procedimiento

Nos aparecerá un cuadro donde le debemos poner el nombre de ese procedimiento y elegir el
ámbito (Alcance en la figura) que le queremos dar, público o privado.

Fig. 1.5 Cuadro para agregar un procedimiento o función

Si un procedimiento es público, se podrá acceder a él desde cualquier parte de la aplicación. Si


es privado, solamente desde el módulo o formulario donde se ha introducido.

¿Cual es el nombre por el que podemos llamar a ese procedimiento? Sigue las mismas
normas que para las variables. Si se ha declarado como público en un módulo, se le citará por
su nombre cualquiera que sea la parte del programa desde donde le citemos.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 43


p.e. CalculaGastos

Si se ha declarado como publico en un formulario, deberemos llamarle con el nombre del


formulario, seguido del nombre del procedimiento separado por un punto

p.e. Formulario1.CalculaGastos

Si se ha declarado como privado, se le llamará por el nombre, pero solamente desde el código
del módulo o formulario donde se insertó, puesto que desde otro módulo o formulario no se
verá.

Fíjese en el punto usado como separador entre el nombre del formulario y el nombre del
procedimiento. VB usa como separador un punto. Usa el separador para separar el nombre de
un control y una de sus propiedades (Label1.Caption), para separar el nombre del formulario
del nombre de uno de sus controles (Formulario1.label1.caption) Se irá familiarizando con la
terminología VB según vayamos avanzando en el curso.

Call
En Visual Basic, para ejecutar un procedimiento no hace falta usar la sentencia Call, muy propia
de otros lenguajes de programación. Hay programadores que la usan no sé si porque creen que
es necesario, o porque piensan que queda más bonito. No hace falta pero VB lo soporta. Queda
a gusto del programador usarla o no usarla.

Funciones

Al igual que introducimos Procedimientos, podemos introducir Funciones en nuestra aplicación.


Una Función es un Procedimiento al que le pasamos uno o varios parámetros. (O Ninguno) y
nos devuelve un valor. Verá los Procedimientos y funciones mas adelante (Cap. 15). Al igual
que los Procedimientos, pueden ser públicas (se verán en toda la aplicación) o privadas (se
verán solamente en el formulario o módulo donde estén. Se introducen igual que los
procedimientos,

Main

Merece la pena pararse un poco para estudiar el Procedimiento Main. Para verlo con mas
detalle, comentaremos como comienza a trabajar una aplicación realizada en Visual Basic.

Imaginemos una aplicación que tiene 3 Formularios. En cada uno de ellos tiene código.
Lógicamente la aplicación tendrá que presentar uno de ellos en primer lugar. Deberemos decirle
a Visual Basic cual es el formulario inicial, y será ese por el que empiece. En ese formulario
dispondremos el código necesario para que la aplicación se ejecute en el orden deseado.

Si hacemos click en la Barra de Menú de Visual Basic, en Proyecto | Propiedades


obtendremos el siguiente cuadro de diálogo :

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 44


Fig. 1.6 Cuadro de propiedades del Proyecto

Verá que tiene 5 pestañas, y actualmente tiene abierta la pestaña correspondiente a General, y
tiene desplegada una lista donde nos pide el Formulario Inicial. En esa lista figura también la
expresión Sub Main. Si ponemos como formulario inicial uno de los formularios, la aplicación
comenzará por ese formulario. Si en uno de los Módulos existentes en el proyecto, ponemos
un procedimiento llamado Main, podemos comenzar la ejecución de la aplicación justamente
por ese procedimiento. En ese procedimiento pondremos el código necesario para que,
posteriormente, se muestre uno de los formularios. Esto es muy practico cuando queremos
hacer una función previa a mostrar cualquier formulario (abrir una base de datos, por ejemplo).
Para comenzar la aplicación por Main se elige esa opción en la lista Formulario Inicial.
¡ Recuerde que Main debe estar en un Módulo !

El cuadro de diálogo anterior sirve además para otras cosas. Entre ellas poner el nombre del
proyecto (nombre que no aparecerá por ninguna parte, solo en los datos internos de la
aplicación) y su descripción.

Existe otro cuadro parecido en Herramientas | Opciones donde puede terminar de completar
las condiciones de trabajo. Observe el cuadro “Cuando Inicie sus programas”. Aquí le permite
grabar el programa antes de ejecutar, cosa que le recomiendo para evitar que, al ejecutarlo, por
un código mal puesto se le cuelgue el PC y tenga que volver a empezar. En este cuadro puede
elegir también el formato de la ventana de trabajo formato del editor, etc.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 45


Fig. 1.7 Opciones del entorno de diseño

En la pestaña Avanzado puede cambiar el entorno de trabajo. Le recomiendo el SDI.

Si tenemos la activada la casilla Declaración de variables requerida nos pondrá


automáticamente Option Explicit en el encabezamiento de todas las secciones de
declaraciones de la aplicación. Está en la pestaña Editor (Esto es algo que le recomiendo de
una forma especialmente rigurosa)

Podemos elegir también las ventanas que queremos que estén siempre visibles, y que verifique
automáticamente la sintaxis de una instrucción en el momento de escribirla.

La pestaña de Editor nos permite fundamentalmente 2 cosas :

Ver solamente el código correspondiente al procedimiento que estamos escribiendo ó Ver el


código del Módulo (o Formulario) completo. En este último caso es un poco mas difícil de
manejar la ventana de código, sobre todo si el programador no está muy habituado a ello. Le
presenta procedimiento tras procedimiento, separados por una línea. Para seleccionar una u
otra opción hay que seleccionar o deseleccionar la casilla Ver módulo completo.

Cambiar el color de la letra y del fondo del código, según el tipo que sea (código, comentario,
error devuelto, etc.). Los alumnos mas aventajados y con ganas de marear al profesor,
conocen la forma de poner como invisible una parte del texto del código. Si observa
comportamientos raros en el texto donde escribe el código, revise el cuadro de Colores de
Código.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 46


Ejercicios del Capítulo 1

Nota acerca de los ejercicios de cada capítulo.

Estos ejercicios se proponen a efectos académicos solamente, para facilitar al alumno la


comprensión de lo explicado y estimular el autoaprendizaje. No son perfectos y seguramente
existirá una forma mejor de realizarlos. No se ha pretendido crear programas perfectos, sino
que muestren al alumno parte de lo explicado en el capítulo correspondiente.

Se reúnen en el ejercicio Cap11 tres pequeños programas. Es importante que el alumno


comprenda perfectamente como se ha programado cada una de las líneas. Son tan sencillos
estos ejemplos que dan ganas de saltárselos. Evite esa tentación y vaya paso a paso camino
de la perfección en la programación VB (Antesala de la gloria) entendiendo y sacando
consecuencias de estos pequeños ejercicios. Habrá platos mas fuertes en pocos días.

En la parte de conversión de números a cadenas de caracteres puede ver el comportamiento


de la función Str para convertir números a cadenas de caracteres. Puede observar la longitud
de la cadena resultante contiene un carácter mas de los que cabría esperar. En la etiqueta de
desglose de caracteres, puede observar que el primer carácter es el 32 (espacio), carácter que
se elimina al hacerle la función Trim

En la sección de operadores lógicos puede jugar a aplicar uno de los operadores disponibles a
una pareja de número o a un par de datos booleanos. Observe que para invertir los bits de un
byte basta con hacer el Xor con 255

La tercera parte se parece mas a un programa real.


Veamos un ejemplo de como se puede utilizar la función Xor. Explicaremos lo que es el Cifrado
Xor (Se usó profusamente con los mensajes télex, con un sistema llamado cinta aleatoria. No
entra en este curso explicar lo que era un teletipo. Era, al correo electrónico, lo que la máquina
de vapor al AVE )

Este sistema de cifrado puede utilizarlo en sus aplicaciones para, por ejemplo, cifrar el
Password de entrada y poder guardarlo cifrado en el disco duro de su PC. De cualquier forma,
debo indicarle que este sistema de cifrado al tiempo que simple, es tremendamente vulnerable,
pero si lo acompaña de otras características, lo convierte en un cifrador intrínsecamente seguro
(Vigenere). La explicación mas detallada de algoritmos cifradores se sale por completo de la
intención de este curso.

Supongamos que queremos cifrar la palabra Secreto que es el Password de entrada para una
aplicación. Deberemos usar otra palabra que cifrará a la anterior, que llamaremos Clave. La
clave debe tener, al menos, tantos caracteres como la palabra a cifrar. Imaginemos que clave
es ABCDEFGHIJK

Para cifrar usamos la función Xor de cada una de las letras de Secreto con las
correspondientes letras de la clave. (La primera letra de Secreto con la primera letra de la clave,
la segunda con la segunda, etc.) Pero debemos efectuar la función Xor sobre un número, no
sobre una letra. Por lo tanto convertiremos la letra en un número usando la función Asc Asc
(A) = 65, ya que 65 es el número Ascii que corresponde a la A

Para realizar el Xor del carácter introducido en la variable a, con el carácter introducido en la
variable b haremos:

Chr(Asc(a) Xor Asc(b))

De esta forma, si a = “S” y b = “A” estaremos haciendo

Resultado = 83 Xor 65
LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 47
En este caso, Resultado = 18. Vamos a ver por qué

Si representamos en binario el número 83 83 = 0 1 0 1 0 0 1 1


El número 65 es 65 = 0 1 0 0 0 0 0 1
Haciendo Xor bit a bit Resultado = 0 0 0 1 0 0 1 0 = 18

Luego el resultado de realizar el Xor entre S y A es el carácter 18, que no tiene representación
como una letra.

Si ahora hacemos el Xor entre el resultado y la clave (18 con 65)

65 = 0 1 0 0 0 0 0 1
18 = 0 0 0 1 0 0 1 0
Resultado 2= 0 1 0 1 0 0 1 1 = 83 es decir la letra S

Vemos que descifra usando la misma función que para cifrar .

Si A Xor B = C à A = B Xor C B = A Xor C

No vamos a explicar profundamente el ejercicio. El alumno debe intentar comprender códigos


sencillos como este. Verá en su trabajo profesional que es difícil meterse en la forma de
programar de otra persona. El desentrañar el código de estos ejercicios puede ser una buena
práctica para ello.

El ejercicio Cap12 es un entrenamiento con fechas y formatos. Se sugiere al alumno que


introduzca nuevos formatos, utilice DateDiff, etc. También tiene una parte dedicada a la
conversión de números. Son ampliables por parte del alumno.

LSB Visual Basic – Guía del Estudiante Capítulo 1 Página 48


Visual Basic - Guía del Estudiante Cap. 2
OBJETOS VISUAL BASIC PROPIEDADES, PROCEDIMIENTOS Y METODOS

Vamos a ver en este capítulo como podemos realizar una aplicación en Visual Basic. Comencemos
por abajo.

Una aplicación VB es una aplicación que, generalmente, tiene una interface gráfica. Es decir, es
una aplicación de las típicas de Windows. Y esa interface gráfica está formada por un formulario y
dentro de él, controles. Tanto al formulario como a los controles les denominamos genéricamente
Objetos. Hay objetos VB que no los podemos ver en la interface gráfica. No podemos verlos
porque pese a que son objetos VB, no tienen ninguna representación en la ventana. Son por
ejemplo, los objetos de acceso a datos que veremos profusamente más adelante.

Todos los objetos de Visual Basic tienen Propiedades. (Por ejemplo, el nombre de ese objeto es
una de sus propiedades). Los objetos que tienen parte gráfica tienen además Eventos. Y muchos
de ellos tienen también Métodos

Propiedades, Eventos, Procedimientos y Métodos


Típica pregunta de examen de VB elemental. Veamos que es cada una de estas cosas.

Las propiedades son aquellas características de un objeto que lo define "físicamente", bien por su
forma o color, por su contenido, por la forma en la que va a trabajar… Las propiedades pueden
modificarse cuando estamos diseñando la interface gráfica, mediante lo que llamamos caja de
propiedades, o durante la ejecución del programa. En este caso hay que hacerlo con código
escrito en el propio programa. Veamos ya dos definiciones que se repetirán profusamente a lo largo
del curso

- Tiempo de diseño. Es cuando realizamos una operación durante el diseño. Por ejemplo,
podemos cambiar el color de un control durante el diseño de la aplicación, accediendo a su
propiedad BackColor en la caja de propiedades.
- Tiempo de ejecución. Es cuando esa operación se realiza durante la ejecución del programa.
Si tenemos una línea de código como esta

MiControl.BackColor =RGB(255,0,0)

al ejecutarse esa línea, se cambiará el color del control de nombre MiControl. Hemos cambiado la
propiedad BackColor de ese control en tiempo de ejecución.

Las propiedades pueden ser de lectura y escritura, (se puede cambiar y se puede leer el valor de la
propiedad), sólo de lectura (solamente se puede leer el valor de la propiedad) ó solo de escritura
(hay muy pocas de este tipo). Puede que una propiedad, que es de lectura y escritura en tiempo de
diseño, sea sólo de lectura en tiempo de ejecución (esto es lo que le pasa por ejemplo, a la
propiedad Name - Nombre)

Un evento es todo aquello que le puede ocurrir a un objeto con parte gráfica (Control o Formulario)
Por ejemplo, es un evento el hecho de hacer click sobre ese control, el hecho de pasar el ratón por
encima de él, el hecho de que un control cambie de tamaño…. Los controles tienen muchos
eventos, unos de ellos comunes a casi todos los controles (Evento click, por ejemplo) y otros
exclusivos de un determinado control (El evento Timer solamente lo tiene el control Timer) Puede
ver los eventos de un control haciendo doble click sobre ese control en tiempo de diseño. Le
aparecerá la ventana de código.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 1


Fig. 2.1 Ventana de código

La ventana de código es el lugar donde deberá escribir el código de su aplicación. Puede ver que
existen en ella dos listas desplegables, una a la izquierda (sin desplegar) donde se ve el nombre del
control del cual estamos visualizando el código (en este caso Command1) y otra a la derecha,
donde se despliegan todos los eventos que tiene ese control. Haciendo click en la línea de uno de
esos eventos, aparecerá la ventana de código dedicada a ese evento.

Nota. Fíjese en la parte inferior izquierda de la ventana de código. Hay dos botones, uno que
permite visualizar el código correspondiente a un solo evento, (el de más a la izquierda) y otro que
permiten ver en la misma ventana el código de todos los eventos. Cada programador tiene su
costumbre para ver uno o todos. La práctica le dirá lo que es más práctico para Vd.

Un Procedimiento es el código que introducimos dentro de un evento. No pretendo hacer escuela


con definiciones, puesto que el concepto de evento y procedimiento se confunde con mucha
frecuencia, y no pasa nada por ello. El código introducido en la ventana de código del evento click
será el procedimiento click, el que se introduzca en el evento MouseUp será el procedimiento
MouseUp. No se sorprenda si a lo largo de este libro nos referimos a evento o a procedimiento de
forma equivocada. En el lenguaje coloquial es muy habitual ese error y como decíamos, no pasa
nada por ello.

Estos procedimientos forman parte del programa. Podría hacerse una aplicación que no tuviese
mas código que el introducido en los procedimientos, y muchas veces esa es la realidad.

Un procedimiento puede pasar parámetros. Se dice que pasa parámetros cuando el sistema
aporta datos automáticamente al procedimiento. Por ejemplo, el procedimiento MouseUp, que se
ejecuta cuando levantamos el botón del ratón (también existe el evento MouseDown), pasa los
siguientes parámetros: Número del botón que se ha pulsado, (1=Izdo, 2=Dcho, 3=Central), si está
pulsada la tecla mayúsculas (Shift, 1 si está pulsada, 0 si no está pulsada) y los valores X e Y de la

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 2


posición del cursor del ratón. Podemos ver los parámetros que pasa en la propia definición del
procedimiento, que nos da Visual Basic

Private Sub Command1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)

End Sub

Observe que los parámetros están entre paréntesis, y que queda definido el tipo de variable que es
cada uno de ellos. Podemos usar ese valor dentro del código del procedimiento como un dato más.

Un Método es una operación que la realiza Visual Basic sin necesidad de escribir código para
realizarla. Por ejemplo, si queremos dibujar una línea en un formulario o en la impresora
utilizaremos el método Line. Si queremos dibujar una circunferencia usaremos el método Circle. Si
queremos escribir texto, utilizaremos el método Print. No necesitamos decirle como lo tiene que
haver, puesto que eso ya lo sabe hacer VB sin necesidad de que se lo expliquemos. A los métodos
les tenemos que pasar datos. A eso le llamamos también pasarle parámetros. Los métodos solo
permiten introducir los parámetros que necesita el método para ejecutarse. (En el caso de una
línea, el punto inicial y el final, en el caso del circulo, el radio y las coordenadas del centro. Pueden
pedir parámetros optativos, como el puede ser el color de la línea o circulo.

Espero que le quede claro cada una de estas definiciones. Tendrá tiempo suficiente a lo largo del
curso para verlas, y dentro de muy poco tiempo le serán muy familiares estos conceptos.

EL FORMULARIO

El primer objeto Visual Basic con que nos encontramos es el FORMULARIO. De hecho, cada vez
que iniciamos Visual Basic (VB) nos presenta en pantalla un nuevo formulario, que tiene por defecto
el nombre de Form1

El Formulario es un objeto, que sirve de soporte de otros objetos. El nombre de FORMULARIO lo


toma precisamente porque, al igual que un formulario de papel contiene textos escritos, lugares
donde podemos escribir, figuras, cajas donde podemos elegir una u otra opción, etc., en este
cuadro gráfico que llamamos formulario, podemos introducir textos escritos, lugares donde
podemos escribir, figuras, cajas donde podemos elegir una u otra opción ....

En realidad un formulario es lo que normalmente conocemos por VENTANA. El nombre de


formulario le viene muy bien cuando ese formulario es una ventana donde vamos a introducir datos
alfanuméricos. Cuando en vez de introducir datos, lo que tenemos es, por ejemplo, una ventana
donde se reproducen exactamente los controles de operación de una máquina, parece en principio
que sería mas correcto el nombre de "ventana". De alguna forma lo hay que llamar, y esa forma es
FORMULARIO. Posiblemente a lo largo de estos apuntes nos referiremos al formulario con el
nombre de ventana, o incluso, pantalla. Procuraremos usar el nombre apropiado: FORMULARIO.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 3


Fig. 2.2 Forma inicial del formulario.

Fig. 2.3 Un formulario que parece un equipo de radio (Programa realizado por el autor)

Ejemplo de un formulario para una aplicación industrial. Este formulario reproduce el panel de
control de un transmisor - receptor de radio. En este caso, parece que el nombre de ventana le
viene mejor que el de formulario. Observe que dentro del formulario existen gran cantidad de
objetos. Botones, que hacen la misma función que el botón real en el equipo de radio, y un par de
displays, que muestran un texto, en este caso las frecuencias de transmisión y recepción.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 4


Como cualquier objeto Visual Basic, un formulario tiene propiedades, procedimientos y métodos.

Vamos a ver las propiedades del formulario, pero solo veremos las que son específicas para un
formulario. El resto las podrá ver al final del capítulo. Aquí haremos referencia a esas propiedades
con un asterisco (*) que significa que esa propiedad no tiene una notación especial para los
formularios. Seguiremos esta norma con todos los controles.

PROPIEDADES.

Name Nombre

Define al objeto durante la ejecución del programa. Se introduce en tiempo de diseño y no se puede
variar durante la ejecución. Nombre por defecto: Form1 (Form2 y sucesivos) Este nombre por
defecto debe cambiarse, (debería cambiarse por norma en el momento de introducir el formulario),
ya que de no hacerlo corremos el riesgo de borrar el código existente de otro formulario del mismo
nombre en el momento de guardar la aplicación.

Caption Título

Es el texto que aparecerá en la barra de Título cada vez que aparezca en pantalla este formulario.
No tiene otra función dentro del programa. El programa no accede a este formulario por el título,
sino por el nombre. Puede cambiarse en tiempo de ejecución.

NOTA.- No confundir Nombre (Name) con Título (Caption)

Control Box Menú de Control en la parte sup. Izda. Valor por defecto : True

Propiedad Booleana que admite los valores de true (verdadero) o False (Falso). Si esta propiedad
es True, aparecerá en la esquina superior izquierda el icono (el "menos" en W-3.11) para desplegar
el menú de control de este formulario. Si esta propiedad se pone como False, no aparece dicho
icono y por tanto no se puede desplegar dicho menú.

MinButton
MaxButton Valor por defecto: True

Botones de minimizar y maximizar este formulario. Son igualmente propiedades booleanas, que
admiten el valor True o False. Si están en true, aparecerá la flecha correspondiente. Si están en
False, no aparecerá dicha flecha. Deben configurarse de una u otra forma, dependiendo si se
quiere minimizar / maximizar este formulario durante la ejecución.

Nota. En los formularios MDI child, es necesario poner a true las propiedades ControlBox,
MinButton y MaxButton para poder maximizar el formulario hijo. De no ponerlas a true, sí se
pretende maximizar el formulario hijo, (Propiedad WindowState=2) el formulario no aparece.

BorderStyle Tipo de borde

Define el tipo de borde que tendrá el formulario durante la ejecución. No se puede cambiar en
tiempo de ejecución. Admite los siguientes valores:

0 - None El formulario no tiene borde alrededor

1 - Fixed Single
El formulario tendrá un borde fino, y no podrá cambiarse su tamaño
durante el tiempo de ejecución. Con este valor, el formulario puede tener
un menú de control, barra de título y botones de maximizar y minimizar.
Solo podrá cambiarse de tamaño utilizando estos botones.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 5


2-Sizable
El formulario tendrá borde grueso, y se podrá cambiar su tamaño en
tiempo de ejecución mediante los botones de maximizar y minimizar, y
mediante el arrastre de uno de los bordes con el ratón.

3 - Fixed Dialog
El formulario tendrá borde grueso, y no se podrá redimensionar durante la
ejecución. No puede tener los botones de maximizar ni minimizar.

4 - Fixed ToolWindow
En las versiones de 16 bits de Windows y Windows NT 3.51 y anteriores se
comporta como Fixed Single. No puede cambiar de tamaño. En Windows
95 muestra el botón Cerrar, y el texto de la barra de titulo aparece con un
tamaño de fuente reducido. El formulario no aparece en la barra de tareas
de W95.

5 - Sizable ToolWindow
En las versiones de 16 bits se comporta como Sizable. En W95 muestra el
botón Cerrar y el texto de la barra de titulo aparece con un tamaño de
fuente reducido. El formulario no aparece en la barra de tareas de W95.

Valor por defecto: 2 . Sizable

Nota: Al cambiar a determinados valores, las propiedades MaxButton y


MinButton se ponen a False. Pueden cambiarse a True posteriormente.

Appearance Apariencia Valor por defecto: 3D

Admite los valores 0 (=Flat, plano) y 1 (=3D) Si tiene el valor 1 (3D), el formulario aparecerá con
cierto efecto tridimensional, y los controles que le introduzcamos a este formulario aparecerán
como esculpidos dentro de él. Con valor 0 (Flat) en esta propiedad, el formulario aparecerá durante
la ejecución como una superficie plana. El color de fondo se ve afectado al cambiar esta propiedad.
Si se cambia a 3D, el fondo (Backcolor) toma el color definido en Windows en el Panel de Control.
Si se cambia a Flat, toma el color blanco

Autoredraw Valor por defecto: False

Propiedad Booleana. Esta propiedad, estando en True, permite actualizar el contenido del
formulario y de sus controles incluso cuando no están visibles. Imaginemos que en este formulario
existe un texto, que se haya cambiado por programa mientras este formulario no estaba visible. Si
esta propiedad Autoredraw está en False, al hacer visible este formulario, aparecerá sin reflejar
ese cambio. Si esta propiedad está en True, aparecerá actualizado.

Backcolor Color del fondo

Establece el color del fondo del formulario. Puede cambiarse en tiempo de ejecución.

Valor por defecto: El establecido en el Panel de Control de Windows.

ClipControls Valor por defecto: False

Propiedad Booleana. Establece si un evento Paint vuelve a dibujar el objeto entero (True) o si
solamente dibujan las partes que han sufrido cambios (False)

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 6


DrawMode

Establece un valor que determina el aspecto de la salida de un método gráfico o el aspecto de un


control Shape o Line. Verá mas adelante los efectos de esta propiedad.

DrawStile (*) Valor por defecto : 0

DrawWidth (*) Valor por defecto: 1

Enabled (*)

ForeColor Valor por defecto: Negro

Establece el color del primer plano del formulario. Es el color que tendrán las letras si escribimos en
él, o los dibujos, si lo que hacemos es dibujar. En tiempo de diseño, determina el color de la rejilla,.

FillStyle Tipo de relleno (*)

FillColor Color del relleno (*)

Font Tipo de letra Valor por defecto: El determinado en la personalización.

Especifica el tipo y tamaño de la letra que se usará en el formulario al utilizar el método Print. Al
seleccionar esta propiedad en la ventana de propiedades, aparece un cuadro de dialogo donde se
eligen ambos parámetros.
Cuando introduzca nuevos controles en el Formulario, la propiedad Font de estos controles tomará
el valor que tenga esta propiedad en el Formulario. Puede servirle este pequeño truco para utilizar
en todos los controles una determinada fuente sin tener que teclearla para cada control.

FontTranparent Texto Transparente Valor por defecto: True

Establece si el texto o gráfico de fondo del formulario se muestra (True) o no se muestra entre los
caracteres de texto escritos en el propio formulario.

FontSize Tamaño de letra (*)

FontBold, FontItalic, FontStrikethru, FontUnderline (*)

Height Altura (*)

HelpContextID Identificador de contexto de la Ayuda (*)

Icon Icono

Esta propiedad define el icono que va a representar a este formulario cuando esté minimizado. Si el
formulario es el formulario padre o formulario de inicio de una aplicación, este icono es el que toma
el Asistente de Instalación para colocarlo como icono de apertura del programa en el grupo de
programas Windows correspondiente. Como valor de esta propiedad se le puede asignar
directamente el icono o el nombre de un archivo (con su path correspondiente) que lo contiene,
haciéndolo directamente sobre la caja de propiedades.

Valor por defecto: el icono que se le haya programado en la personalización.

KeyPreview Valor por defecto: False

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 7


Propiedad Booleana. Cuando un formulario tiene dentro de sí varios controles, uno de ellos es el
que está activo. En estas condiciones, si se pulsa una tecla, esa pulsación la recibe en primer
lugar el control que esté activo, y si éste no la procesa, pasa esa pulsación al formulario. Para
hacer que esa pulsación pase previamente por formulario, debe ponerse esta propiedad en True.
Esta propiedad la usará frecuentemente cuando quiera realizar alguna función pulsando una letra.
Pone KeyPreview a True, y puede conocer que tecla se ha pulsado en el procedimiento KeyPress
del formulario. Si la tiene a False, ese procedimiento no se ejecuta ya que la pulsación “no pasa”
por el formulario.

Left Posición del Borde Izquierdo

Indica la posición del borde izquierdo del formulario respecto a la parte izquierda de la pantalla. (Lo
verá mas adelante, la pantalla será para VB el objeto Screen). Normalmente no se introduce como
valor numérico, sino que lo toma automáticamente de la posición que tenga el formulario en el
tiempo de diseño. Puede cambiarse en tiempo de ejecución, para mover el formulario.

LinkMode Valor por defecto: 0

Permite que una aplicación destino inicie una conversación DDE con el formulario (origen de datos).
Puede tomar los siguiente valores:

0 - No hay interacción DDE


1 - Source. Indica que este Formulario es origen de una comunicación DDE. El dato que se
va a traspasar en esa comunicación DDE estará en un TextBox, en un Label o en un
PictureBox de este Formulario.

LinkTopic

Establece el tema al que este formulario va a responder a una conversación DDE, cuando funciona
como origen. Es por este tema por el que se debe llamar a este formulario cuando actúa de origen
en una conversación DDE

MDIChild Valor por defecto: False

Establece que este formulario es un formulario Hijo dentro de un formulario MDI. No se puede
cambiar en tiempo de ejecución. Es una propiedad Booleana

True = es formulario hijo False =No lo es

MouseIcon (*)

MousePointer (*) Valor por defecto: flecha

Picture Gráfico

Mediante esta propiedad podemos poner un gráfico como fondo del formulario. El gráfico puede ser
un bit-map o un fichero .ICO

ScaleHeight, ScaleWidth, ScaleMode,

Indican la unidad de medida de dimensión de altura y anchura del Formulario. ScaleMode indica en
qué unidades de medida se van a medir esas dimensiones. Acepta Twips (1), Point(2), Pixel (3),
Character (4), Pulgadas (Inch) (5), Milímetros (6), Centímetros (7). Si colocamos la propiedad
ScaleMode en cualquiera de estos valores, las propiedades ScaleHeight y ScaleWidth nos
vendrán dadas automáticamente dependiendo del ancho del Formulario, y no se extrañe si

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 8


encuentra para estas propiedades valores tan peregrinos como 4815 y 7423. Al haber elegido la
unidad de medida, los valores de ancho (ScaleWidth) y alto (ScaleHeight) serán los que tengan
que ser, medidos en la unidad que hemos elegido. Podemos elegir una cifra para el ancho y el alto
del Formulario de forma que podamos controlar mejor las distintas posiciones que van a ocupar en
él los controles, los textos o los dibujos. Podemos poner, por ejemplo, que el Formulario mida 400
de ancho (ScaleWidth = 400) y 300 de alto (ScaleHeight = 300) forzándole estas propiedades,
bien en tiempo de diseño en la caja de propiedades, o en tiempo de ejecución mediante código.
Entonces sabemos que el formulario, independientemente de las dimensiones físicas que tenga
sobre la pantalla, medirá 400 de ancho y 300 de alto, y si en estas condiciones queremos colocar
un control o un dibujo justo en el medio del Formulario, sabemos que tenemos que colocarle en las
coordenadas 200, 150. ¿Que unidad de medida estaremos utilizando entonces en el Formulario ?
Unas definidas por el usuario (distintas para el ancho y el alto) que serán las necesarias para que el
Formulario mida de ancho lo que le hayamos puesto en la propiedad ScaleWidth y de alto lo que le
hayamos puesto en la propiedad ScaleHeight. Observe que la propiedad ScaleMode se ha
cambiado automáticamente a User (0) al introducir las dimensiones de ancho y alto que nosotros
queremos.

Estas unidades de medida afectarán a los controles que metamos en este Formulario. Se medirán
en su ancho y alto con la unidad de medida definida para el ancho y alto del Formulario.
Lógicamente también afectará a las propiedades Left y Top de los controles, pero estas
propiedades se verán afectadas además por las propiedades ScaleLeft y ScaleTop del Formulario
que se verán a continuación.

ScaleLeft, ScaleTop

Estas propiedades, medidas en la unidad de medida elegida para el ancho y alto mediante las
propiedades ScaleMode, ScaleWidth y ScaleHeight anteriores, expresan las coordenadas
iniciales de la parte izquierda y de la parte superior respectivamente del Formulario. Estas
propiedades no afectan a la posición del Formulario en la pantalla (Si está maximizado seguirá
ocupando toda la pantalla, si está en “Normal” ocupará el mismo sitio que se dio en tiempo de
diseño). Supongamos que se le asigna a un Formulario, las propiedades ScaleWidth = 400, y
ScaleHeight = 300. Si colocamos un control justamente en el centro del Formulario tendrá sus
propiedades Top =150 y Left=200. Si ponemos ahora las propiedades del Formulario ScaleLeft a
30 y ScaleTop a 10, ese control, para seguir en el centro del Formulario deberá tener sus
propiedades Top a 160 (150 + 10) y Left a 230 (200 + 30).

Recuerde que las medidas de un formulario crecen, desde la esquina superior izquierda, según
avanzamos hacia abajo y hacia la derecha.

Como aclaración de las relaciones entre distintas unidades de medida, puede ver en la siguiente
table la correspondencia entre cada una de ellas y la unidad imaginaria Twip.

1 Point=20 Twips ; 1Pixel=15 Twips : 1 Charecter=240 Twips ; 1 Inch (pulgada) =1440 Twips
1mm=56,52 Twips 1 cm=566 Twips

Tag (*)

Top Posición del borde superior

Esta propiedad establece la posición del borde superior del formulario respecto a la parte superior
de la pantalla (Objeto Screen). Normalmente no se introduce como valor numérico sino que lo toma
automáticamente de la posición que tenga el Formulario durante el tiempo de diseño Este valor
puede cambiarse durante la ejecución para, conjuntamente con Left, variar la posición del
Formulario. Los valores de Top y Left definen la esquina superior izquierda del Formulario.

Visible (*) Valor por defecto: True

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 9


Width Ancho (*)

WindowState

Establece el estado en el que aparecerá el formulario cuando se activa y presenta en pantalla.


Admite tres opciones:
0 - Normal El formulario recupera la posición y tamaño que tenía en el tiempo de diseño.
1 - Minimizado El formulario aparece minimizado, representado por su icono.
2 - Maximizado El formulario aparece maximizado, ocupando toda la pantalla.

EVENTOS DEL FORMULARIO

Se explican a continuación los eventos de un formulario. Recuerde que un evento es lo que le


puede ocurrir a un formulario o control (p.e. Evento Click) y un procedimiento es el código escrito en
ese evento, que se ejecutará cuando ocurra el evento.

Evento Activate Activación


Este evento se ejecuta al convertirse el formulario en formulario activo. Esto sucede múltiples veces
cuando tenemos en el programa mas de un formulario. Sólo uno de ellos puede ser el formulario
activo. Este procedimiento no pasa parámetros. No debe emplearse para los parámetros iniciales
del formulario. Úsese para este fin el evento Load o el Initialize.

Evento Click Click


Este evento se ejecuta cuando hacemos Click (con cualquier botón del ratón) en una parte del
formulario que no esté ocupada por un control. Para que se ejecute el evento Click es necesario
que no se ejecute el procedimiento MouseDown. (Que no tenga código escrito en el evento
MouseDown). Existe una diferencia entre el evento click del formulario y el de cualquier control : en
el formulario se ejecuta con cualquiera de los botones del ratón, y en los controles, solamente con
el botón izquierdo. Este evento no pasa parámetros.

Evento DblClick Doble click


Este evento se ejecuta cuando hacemos doble click con cualquier botón del ratón sobre una parte
del formulario que no esté ocupada por un control. Este evento no se ejecuta si tenemos escrito
código en el procedimiento Click. No pasa parámetros.

Evento Deactivate Desactivación


Se produce cuando el formulario deja de ser el formulario activo. Vea Activate. No pasa
parámetros.

Evento DragDrop Acción de Soltar durante el Drag & Drop (*)


Evento DragOver Pasar el ratón por encima en una operación de Drag & Drop (*)

Evento GotFocus El formulario obtiene el foco

Este evento ocurre cuando el formulario toma el foco. Cosa un poco difícil, ya que para que el
formulario tome el foco debe ocurrir, o que no tenga ningún control capaz de tomar el foco, o que
todos los controles existentes en el formulario y que puedan tomar el foco, estén desactivados. No
se suele usar este procedimiento.

Evento Initialize Inicialización del formulario

Se produce al cargar por primera vez el formulario. Esto significa que si en una aplicación
cargamos ese formulario una vez (la primera) se realiza este evento, pero si descargamos el

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 10


formulario (con Unload Formxx) y luego lo volvemos a cargar (con Formxx.Show), esta segunda
vez (y sucesivas) no se produce este evento

Evento KeyDown Pulsar una tecla (Instante en que se ha pulsado)


Evento KeyPress Pulsar una tecla
Evento KeyUp Soltar una tecla (Instante en que se levanta)

Estos tres eventos solamente se producirán en el formulario cuando la propiedad KeyPreview está
a True. (Vea propiedad KeyPreview)

Estos tres procedimientos son excluyentes y tienen la jerarquía con el orden siguiente: KeyDown,
KeyPress y KeyUp. Si el procedimiento KeyDown tiene código que pueda realizar una operación, no
se ejecutará el procedimiento KeyPress ni el KeyUp. Si es el procedimiento KeyPress quien tiene el
código que ejecuta una operación, no se ejecutará el KeyUp. Para que realice esta exclusión es
necesario que el código pueda realizar alguna operación.

Pasa los siguientes parámetros:

KeyDown : KeyCode As Integer, Shift As Integer


KeyPress : KeyAscii As Integer
KeyUp : KeyCode As Integer, Shift As Integer

KeyCode es el código ASCII de la tecla pulsada. KeyAscii es el código ASCII de la tecla pulsada.
La diferencia entre KeyCode y KeyAscii es que el primero se refiere a las teclas del teclado (Todas
las letras y números, teclado numérico, Alt, F1 a F12, etc.) mientras que KeyAscii solamente tiene
valor cuando se pulsa una tecla de letra o número. Puede observar que el KeyCode de un número
tecleado en el teclado numérico es distinto del KeyCode de ese mismo número pulsado en el
teclado alfanumérico. No se confunda con el hecho de que el KeyCode de algunas teclas coincida
con el KeyAscii. No es lo mismo.
Shift indica si está pulsada la tecla “Mayúsculas”. Contiene un 1 si está pulsada, 0 si no lo está.

Evento LinkError Error de enlace


Evento LinkExecute Ejecución de un enlace de datos
Evento LinkOpen Romper el enlace

Estos tres procedimientos ocurren cuando el formulario forma parte de un enlace DDE. Vea el
capítulo del DDE para mas detalles.

Evento Load Cargar el formulario

Este evento es se ejecuta en el momento de la carga del formulario. Es el que presenta en la


ventana de código por defecto, es decir, uno de los mas usados en el formulario. Y es el mas usado
porque es el mas apropiado para introducirle a ese formulario los valores y parámetros iniciales,
abrir bases de datos, etc.
Se ejecuta después del evento Initialize del formulario, pero este evento Load, al contrario que el
Initialize, se ejecuta cada vez que cargamos el formulario. Para introducir código de inicialización
debe utilizar este evento Load. Este evento no pasa parámetros.

Evento LostFocus Perder el foco


Ocurre cuando el formulario pierde el foco. Y un formulario solo puede perder el foco cuando lo
tenía. Cosa que no es fácil que ocurra, tal como se explicó en el Evento GotFocus.

Evento MouseDown Pulsar una tecla del ratón


Ocurre cuando se pulsa cualquier botón del ratón, estando el cursor encima de un punto del
formulario libre de controles. Pasa como parámetros Button (Botón pulsado, 1 = Izquierdo, 2 =
Derecho, 3 = Central), Shift (Tecla de Mayúsculas) y la posición del puntero del ratón sobre el

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 11


formulario (X e Y). Este evento puede usarse para muchas cosas. Una de ellas, muy típica, iniciar
una operación de Drag & Drop manual, usando la particularidad de que como pasa la tecla Shift
como parámetro, puede obligarse a pulsar esa tecla para iniciar el D & D, evitando así cualquier
activación accidental.

Evento MouseMove Mover el ratón (Detecta la posición del ratón sobre el


formulario)
Se produce cada vez que se mueve el ratón sobre el formulario. Tenga cuidado al usar este evento,
ya que cualquier movimiento del ratón lo va a desencadenar. Por eso, siempre se usa con una
condición (que esté pulsada la tecla de mayúsculas, que esté pulsado uno de los botones del ratón,
etc.). Los parámetros que pasa son Button As Integer, Shift As Integer, X e Y As Single.

Evento MouseUp Soltar una tecla del ratón


Este evento sucede cuando se levanta la tecla pulsada del ratón. Pasa como parámetros Button
(Botón pulsado, 1 = Izdo, 2 = Dcho, 3= Central) Shift (Mayúsculas), X e Y (Single) como posición
del puntero del ratón
Este evento suele usarse para mostrar PopupMenús, deshacer una operación iniciada con
MouseDown, etc.

Evento Paint Redibujar tras un cambio de tamaño


Se produce al cambiar el tamaño del formulario, tras el evento Resize, excepto cuando se
minimiza. Puede aprovecharse para redibujar el contenido del formulario (de ahí su nombre) tras un
cambio de tamaño. No pasa parámetros

Evento QueryUnload Confirmación de descarga


Este procedimiento se ejecuta cuando el formulario recibe la instrucción de descargarse. Todavía
estamos a tiempo de evitar que se descargue. Por lo tanto es aquí donde suele colocarse una caja
de mensaje donde se obliga al usuario a ratificar o revocar la orden de descarga del formulario. En
caso de que en realidad no queramos descargarlo, basta con poner Cancel = True (o Cancel = 1) y
no se producirá la descarga. Pasa como parámetros Cancel As Integer, UnloadMode As Integer.

Cancel es un parámetro que debemos introducir para abortar la descarga del formulario. Si se pone
a un valor distinto de 0, se detiene la descarga.

UnloadMode es un valor o constante que nos da el sistema, dependiendo de la causa que ha


provocado la descarga del formulario.

Constante Valor
vbFormControlMenu 0 El usuario eligió el comando Cerrar del menú Control del
formulario o hizo click en el X del mismo.
vbFormCode 1 Se invocó la instrucción Unload desde el código.
vbAppWindows 2 La sesión actual del entorno operativo Microsoft Windows
está finalizando.
vbAppTaskManager 3 El Administrador de tareas de Microsoft Windows está cerrando la
aplicación.
vbFormMDIForm 4 Un formulario MDI hijo se está cerrando porque el
formulario MDI padre también se está cerrando.

Este procedimiento no se ejecuta cuando sale de la aplicación mediante la instrucción End.


Solamente se ejecuta cuando con la instrucción Unload, o con el comando Cerrar del menú Control
del formulario, o haciendo click en el X del mismo. El evento QueryUnload se utiliza con frecuencia
para guardar la configuración actual de la aplicación.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 12


Evento Resize Cambio de tamaño

Se ejecuta cuando cambia el tamaño del Formulario, bien porque le cambia con las flechas del
ratón arrastrando uno de sus bordes, bien porque lo maximizamos, ponemos a tamaño intermedio
o minimizamos. Puede usar este evento para redistribuir o cambiar el tamaño de los controles. No
pasa parámetros.

Evento Terminate

Este evento se produce al descargar el formulario, después de QueryUnload y Unload. Aquí ya no


podemos abortar la descarga. Solamente podremos, por ejemplo, guardar la configuración usada
por la aplicación, para que vuelva a arrancar con la última configuración usada.

Este evento no se produce si sale de la aplicación con la instrucción End. Solamente si lo hace
mediante Unload (Unload Me, p.e.) o con el comando Cerrar o el X del formulario. Me permito
recomendarle que No termine sus aplicaciones mediante End. No podrá usar los eventos
QueryUnload, Unload ni Terminate.

Evento Unload Descargar el formulario

Este evento se produce en el momento en el que se descarga el formulario. Pasa como parámetro
Cancel, al igual que lo hace QueryUnload. Es la última oportunidad de cancelar la descarga del
formulario, haciendo Cancel = True o Cancel = cualquier valor distinto de 0.

Este procedimiento no se ejecuta cuando sale de la aplicación mediante la instrucción End.


Solamente se ejecuta cuando con la instrucción Unload, o con el comando Cerrar del menú Control
del formulario, o haciendo click en el X del mismo.

Eventos del OLE

Existen varios eventos relacionados con el OLE de Windows. Se estudiarán cuando se estudie el
OLE. De momento se enumeran con los parámetros que pasan.

Evento OLECompleteDrag (Effect As Long)


Evento OLEDragDrop (Data As DataObject, Effect As Long, Button As Integer, Shift As _
Integer, X As Single, Y As Single)
Evento OLEDragOver (Data As DataObject, Effect As Long, Button As Integer, Shift As _
Integer, X As Single, Y As Single, State As Integer)
Evento OLEGiveFeedback (Effect As Long, DefaultCursors As Boolean)
Evento OLESetData (Data As DataObject, DataFormat As Integer)
Evento OLEStartDrag (Data As DataObject, AllowedEffects As Long)

LOS CONTROLES MAS ELEMENTALES DE VISUAL BASIC


Una vez introducido un Formulario, se pueden colocar los objetos (controles) que forman parte de
la aplicación. Estos controles se irán viendo en próximos capítulos.

Los controles, lo mismo que el Formulario, tienen Propiedades, Procedimientos y Métodos.

Para colocar un control en un Formulario, basta con “tomarlo” de la caja de herramientas existente
en la parte izquierda de la pantalla de VB y llevarlo al Formulario. Si no existiese el control deseado
en la caja de herramientas, deberemos ir a “cogerlo” a Proyecto | Componentes de la barra de

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 13


menú de VB. Se elige el nuevo control, marcando la caja de opción a la izquierda de su nombre, y
haciendo click en ACEPTAR. Este control ya pasa a la caja de herramientas.

No se deben introducir mas controles de los necesarios. Sobre todo, cuando vaya a compilar el
proyecto. Si tiene metido en la caja de herramientas un control que no necesita, lo introducirá en los
discos de distribución igual que si lo necesitara.

COMMAND BUTTON BOTON DE COMANDO

El Command Button es un objeto que sirve para introducir datos a través de la pantalla. El Botón de
Comando tiene la siguiente forma:

El botón de comando puede usarse para la entrada de datos con el ratón, o para validar cualquier
operación. El tamaño puede cambiarse a voluntad, pero la forma siempre es rectangular. En la
figura anterior vemos dos botones de comando, uno de ellos (el Command2) marcado con unos
puntos en su contorno. Estos puntos nos permiten variar su tamaño en tiempo de diseño. También
puede cambiarse su tamaño y posición en tiempo de ejecución.

(Las propiedades marcadas con (*) no varían de la descripción general, hecha al final del capítulo)

PROPIEDADES

Name Nombre (*)

Caption Título (*)


Es el texto que aparece en el botón. Puede cambiarse en tiempo de ejecución. No tiene otra
función dentro del programa.

Appearance Apariencia (*)

Backcolor Color de fondo (*)


Esta propiedad permite cambiar el color del botón cuando la propiedad Style está puesta a
Graphycal. Si la propiedad Style esta puesta a Standars, esta propiedad solamente controla el
color de un pequeño cuadrado que aparece rodeando el título. Puede cambiarse en tiempo de
ejecución.

Cancel
Establece un valor que indica si un botón de comando es el botón Cancelar de un formulario. Es
una propiedad booleana, y admite los valores True o False. Puede utilizar la propiedad Cancel para
dar al usuario la opción de cancelar los cambios que no se han hecho efectivos y devolver el
formulario a su estado anterior. En un formulario sólo puede haber un botón de comando con la
propiedad Cancel = True.

Causes Validation

Esta propiedad habilita o deshabilita la ejecución del evento Validate del control que tenía el foco
antes de cambiar el foco a este control. El evento Validate de un control se ejecuta inmediatamente
antes de que pierda el foco. (Se dice que un control tiene el foco cuando es ese control el que está
activado). Al hacer click sobre el botón de comando, siempre habrá algún control que pierda el foco

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 14


para que lo tome el botón de comando. Si el botón de comando tiene la propiedad Causes
Validation a True, se ejecutará el evento validate de ese control que acaba de perder el foco. Si
está a false, no se ejecutará. Observe que esta propiedad afecta a un control diferente del que
ostenta la propiedad.

Default
Establece un valor que determina el control CommandButton que es el botón de comando
predeterminado de un formulario. Sólo un botón de comando de un formulario puede ser el botón
de comando predeterminado. Cuando Default se define a True para un botón de comando, se
define automáticamente a False para el resto de los botones de comando del formulario. Cuando la
propiedad Default del botón de comando está establecida a True y su formulario primario está
activo, el usuario puede elegir el botón de comando (invocando su evento Click) presionando
ENTRAR. Cualquier otro control que tuviera el enfoque no recibe evento de teclado (KeyDown,
KeyPress o KeyUp) de la tecla ENTRAR a menos que el usuario haya movido el enfoque a otro
botón de comando del mismo formulario. En este caso, al presionar ENTRAR se elige el botón de
comando que tiene el enfoque en lugar del botón de comando predeterminado.

DisabledPicture, DownPicture Estas propiedades solamente están disponibles cuando se


pone la propiedad Style a Graphycal. Permiten poner un icono diferente para el estado de
deshabilitación del botón (Cuando está la propiedad Enabled = False) o cuando el botón está
pulsado respectivamente. Juntamente con la propiedad Picture permite hacer un juego de
imágenes sobre el botón que varían de acuerdo a su estado o posición.

DragIcon Icono en la operación de arrastre (*)

DragMode Modo de iniciar el Drag & Drop (*)

Enabled Habilitado (*)

Font Fuente (*)

Height Altura (*)

HelpContextID Número de Contexto para la Ayuda (*)

Index Indice (*)

Left Posición de su parte izquierda. (*)

MaskColor Establece cual es el color de la imagen del botón que actuará como máscara para
producir zonas transparentes. Para ello, la propiedad UseMaskColor debe estar a true. (¡)

MouseIcon Icono para el puntero del ratón (*)

MousePointer Puntero ratón (*)

Picture. Solamente está disponible cuando la propiedad Style está puesta a Graphical.
Pone un icono sobre el botón.

Style Define el estilo del botón, aceptando dos valores: Graphycal y Standard. Poniendo
esta propiedad a Graphycal podemos cambiar el color del botón 8con la propiedad Backcolor) e
incluso introducir un fráfico (en la propiedad Picture, DownPicture o DisabledPicture.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 15


UseMaskColor Determina si el color asignado en la propiedad MaskColor se usa como máscara
para crear zonas transparentes. No he sido capaz de sacar partido a esta propiedad.

TabIndex Nº de orden para tabulador (*)

TabStop Sale del control de la tecla TAB (*)

Tag Valor auxiliar (*)

ToolTipText Etiqueta de información (W95) (*)

Top Posición de la parte superior (*)

Visible Visible (*)

WhatsThisHelpID (Propiedad, Windows 95) (*)

Width Ancho (*)

PROCEDIMIENTOS DEL BOTON DE COMANDO

Click DragDrop DragOver GotFocus


KeyDown KeyPress KeyUp LostFocus
MouseDown MouseMove MouseUp

¡ El botón de Comando no tiene el procedimiento DbClick !

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 16


LABEL ETIQUETA

Una etiqueta es un control que nos permite presentar un texto. La etiqueta debe usarse en aquellos
casos en los que exista una información estática o dinámica que no deba ser cambiada por el
operador.

Puede adoptar estas formas: con borde tridimensional, borde plano o sin borde, y el texto
justificado a la izquierda, a la derecha o centrado.

Se ha incluido la trama para poder observar los límites de la etiqueta sin borde.

PROPIEDADES

Alignment Justificación

Establece si el texto se justifica a la izquierda, a la derecha, o se centra sobre la etiqueta.

Appearance Apariencia Plana o tridimensional. (*)

Autosize Si está a True, el tamaño de la etiqueta se ajusta al tamaño del texto de su


propiedad Caption

Backcolor Color de fondo (*)

BackStyle Tipo de fondo Opaco o transparente.

Cuando se selecciona transparente, se ve solamente el texto de la etiqueta, dejando ver como


fondo entre las letras, el color o Picture del formulario. Cuando se selecciona opaco, este texto se
vé sobre un fondo gris.

BorderStyle Tipo de borde

Sin borde o con borde. En caso de haber elegido en la propiedad Appearance el modo
tridimensional, y eligiendo con borde en esta propiedad, el aspecto adopta una forma como
incrustada en el formulario.

Caption Título (*)

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 17


DataSource DataField

Establecen el control data asociado y el campo de la base de datos que se presentará en la


propiedad Caption. Estas propiedades permiten presentar los datos de una Base de Datos
mediante un procedimiento muy sencillo, con la ayuda de un control Data (Se verá mas adelante)

DragIcon DragMode Enabled Font ForeColor Height


Index Left (*)

LinkItem LinkMode LinkTimeout LinkTopic

Estas propiedades establecen la forma en que debe llevarse a cabo una conexión DDE con otra
aplicación. Se verán con mas detalle al estudiar los enlaces DDE

MouseIcon MousePointer Name TabIndex Tag ToolTipText


Top (*)

UseMneumonic

Es una propiedad Booleana. Devuelve o establece un valor que indica si al incluir el signo (&) en el
texto de la propiedad Caption del control Label se define una tecla de acceso.

Los valores que puede tomar son True o False.

True (Predeterminado) Los caracteres (&) que aparezcan en el texto de la propiedad Caption
definen al carácter siguiente como tecla de acceso. El signo (&) no aparece en el Caption del
control Label.
False Los caracteres (&) que aparezcan en el texto de la propiedad Caption aparecen como tales
en el Caption del control Label.

En tiempo de ejecución, al presionar ALT+ la tecla de acceso definida en la propiedad Caption del
control Label, el enfoque se desplaza al control siguiente al control Label en el orden de tabulación.

Visible WhatsThisHelpID Width (*)

WordWrap

Devuelve o establece un valor que indica si un control Label con el valor True en su propiedad
AutoSize se expande vertical u horizontalmente para adaptarse al texto especificado en su
propiedad Caption. Es una propiedad Booleana.

True El control Label se expande o contrae horizontal y verticalmente para adaptarse al texto y al
tamaño de la fuente. Contempla para la expansión horizontal la colocación de los espacios del
texto.
False (Predeterminado) El texto no se ajusta a la siguiente línea; el control Label se expande o
contrae horizontalmente para adaptarse a la longitud del texto y verticalmente para adaptarse al
tamaño de la fuente y al número de líneas.

Nota Si se establece False en AutoSize, el texto siempre se ajustará a la línea siguiente,


independientemente del tamaño del control Label y del valor de la propiedad WordWrap. Esto
puede ocultar parte del texto, ya que el control Label no se expande en ninguna dirección.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 18


PROCEDIMIENTOS DEL LABEL

Click Change DbClick DragDrop


DragOver LinkClose LinkError LinkNotify

TEXT BOX CAJA DE TEXTO

Las cajas de texto son los controles en los que Visual Basic presenta o introduce textos. Es por
tanto un control bidireccional. Normalmente se usan para introdución de textos, o para la
presentación de aquellos que el operador pueda cambiar. Para cambiar o escribir un texto en una
caja de texto, basta con conseguir que esa caja de texto tenga el foco y teclear el texto en el
teclado. Esto se puede lograr, bien haciendo click con el ratón en esa caja de texto, bien con la
tecla TAB, bien por programa.

La caja de texto no se debe usar nunca para presentar textos que el operador de la aplicación no
deba cambiar. Úsese para ello la etiqueta, control no bidireccional, que además tiene la ventaja de
ocupar menos memoria de programa.

Las cajas de texto pueden tener una o varias líneas, según esté la propiedad Multiline. La
capacidad máxima de una caja de textos es de 64 Kbytes.

La forma de una caja de texto es la siguiente, dependiendo de las propiedades BorderStyle y


Appearance:

PROPIEDADES

Alignment Justificación

Establece si el texto se justifica a la izquierda, a la derecha, o se centra sobre la etiqueta. Esta


propiedad solamente tiene efecto cuando la propiedad Multiline está a True, ignorándose en caso
contrario. Es decir, permite colocar el texto justificado a la derecha cuando ese texto puede ser de
varias líneas. Si la propiedad Multiline está a False, se justifica siempre a la izquierda.
Esta propiedad no puede cambiarse en tiempo de ejecución, pero sí puede leerse en que condición
está.

Appearance Backcolor (*)

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 19


BorderStyle Tipo de borde

Sin borde o con borde. En caso de haber elegido en la propiedad Appearance el modo
tridimensional, y eligiendo con borde en esta propiedad, el aspecto adopta una forma como
incrustada en el formulario.

DataField Nombre de un Campo


DataSource Nombre de un control Data
Establecen el control Data y el campo donde está el texto que se llevará a la propiedad Text. Estas
propiedades permiten presentar de una forma muy sencilla datos de una Base de Datos. Se verán
cuando se estudie el control Data y el motor de bases de datos

DragIcon DragMode (*)

Enabled Habilitado
Propiedad Booleana que habilita o deshabilita la etiqueta Cuando está deshabilitado (Enabled =
False), no tienen efecto los eventos que se produzcan sobre el TextBox. No se puede escribir el él
ni pasarle el foco, pero sí se le puede cambiar el texto mediante el programa. Puede ser una buena
alternativa para impedir que el usuario pueda cambiar un determinado texto. Esta propiedad puede
variarse en tiempo de ejecución.

Font ForeColor Height HelpContextID Index Left (*)

LinkItem LinkMode LinkTimeout LinkTopic


Estas propiedades establecen la forma en que debe llevarse a cabo una conexión DDE con otra
aplicación. Se verán con mas detalle al estudiar los enlaces DDE

Locked
Establece si el texto se puede editar, es decir, cambiar. Cuando se pone esta propiedad a True, el
texto existente en la caja puede resaltarse con el ratón, e incluso copiarlo al portapapeles, pero no
puede variarse tecleando un nuevo texto. Se puede cambiar por programa, cambiando la propiedad
Text.
Si está en False, puede cambiarse el texto mediante teclado.

MaxLenght
Indica, si se establece, la longitud máxima del texto. Si no se establece o si se pone valor 0, permite
cualquier longitud de texto.

MouseIcon Puntero del ratón personalizado (*)


MousePointer Puntero ratón
Lo típico para esta propiedad es el I-Beam (barra vertical)

Name Nombre (*)

PasswordChar
En ocasiones, es conveniente que no se pueda leer lo que se escribe en la caja de texto, caso por
ejemplo de la entrada de un password o palabra de paso. Esta propiedad nos permite indicar un
carácter que sustituye a cualquier carácter que tenga la caja de texto. (Típicos el * o ?). El texto que
tenga en la propiedad Text no cambia por el hecho de presentar en pantalla un carácter distinto.
Esta propiedad puede cambiarse en tiempo de ejecución. Para quitar el PasswordChar basta con
forzarlo al carácter nulo : Text1.PasswordChar = “”

La propiedad PasswordChar se ignora cuando la propiedad Multiline está a True.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 20


ScrollBars
Cuando la propiedad Multiline de la caja de texto está a True, se pueden colocar barras de
desplazamiento del texto hacia arriba y abajo, o hacia los lados. Esto nos permite tener una caja de
texto de tamaño reducido y poder leer en ella un texto mayor que la propia caja. Esta propiedad
puede tomar los siguiente valores :

0 - No salen barras
1 - Barras de desplazamiento horizontal
2 - Barras de desplazamiento vertical
3 - Ambas barras.

TabIndex Tag (*)

Text Texto
La caja de texto no tiene la propiedad Caption. Su equivalente es la propiedad Text que es el texto
que tiene en su interior.

Top Visible WhatsThisHelpID Width (*)

PROCEDIMIENTOS DE LA CAJA DE TEXTO

Click Change DblClick DragDrop DragOver GotFocus


KeyDown KeyPress KeyUp LinkClose

FRAME RECUADRO

Se obtiene directamente de la caja de herramientas

Tiene la siguiente forma :

Un control Frame proporciona un agrupamiento identificable para controles. También puede utilizar
un Frame para subdividir un formulario funcionalmente por ejemplo, para separar grupos de
controles OptionButton.

Para agrupar controles, en primer lugar trace el control Frame y, a continuación, meta los controles
dentro de Frame. De este modo podrá mover al mismo tiempo el Frame y los controles que
contiene. Si traza un control fuera del Frame y, a continuación, intenta moverlo dentro de éste, el

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 21


control se colocará sobre el Frame, pero no pertenecerá a el. Es decir, si es un OptionButton este
se comportará como si estuviese fuera del Frame, aunque físicamente esté dentro de el.

Cuando un control Frame tiene dentro otros controles, y hacemos invisible al Frame, mediante su
propiedad Visible = False, los controles interiores al Frame quedan también invisibles. Los
controles Frame se utilizan para poner dentro de ellos diversos controles, que solo aparecerán en el
programa cuando se cumpla una determinada condición. Cuando esa condición se cumpla, se
pone la propiedad Visible del Frame a True y se verán todos los controles que tiene dentro. Si no se
cumple esa condición, se pone la propiedad Visible del Frame a False y no se verá ni el Frame, ni
los controles que contiene.

PROPIEDADES
Las señaladas con (*) no presentan novedades respecto a las ya
comentadas para los controles precedentes.

Appearance Backcolor Caption (*).

ClipControls
Si esta propiedad está a True, los métodos gráficos en eventos Paint vuelven a dibujar el objeto
entero. Antes del evento Paint se crea una zona de recorte alrededor de los controles no gráficos
del formulario. Si esta propiedad está a False dibujarán solamente las áreas últimamente
expuestas. En tiempo de ejecución, esta propiedad es de sólo lectura.

DragIcon DragMode (*)

Enabled
Cuando esta propiedad está a False, tanto los procedimientos asociados al propio control Frame
como todos los controles dentro del Frame estarán inhabilitados. Si esta propiedad está a True,
todos ellos están habilitados.

Font (*)
ForeColor
Color de las letras del título del Frame.

Height HelpContextID Index Left MouseIcon MousePointer


Name TabIndex Tag Top (*)

Visible
Cuando un Frame está con la propiedad Visible = False, tanto el propio Frame como todos los
controles interiores a el serán invisibles.

WhatsThisHelpID Width (*)

PROCEDIMIENTOS DEL FRAME

Click DblClick DragDrop DragOver MouseDown


MouseMove MouseUp

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 22


CHECK BUTTON Y OPTION BUTTON (BOTONES DE ELECCION Y OPCION)

Se obtienen directamente de la caja de herramientas.

Dada la similitud de ambos controles, se comentan conjuntamente.

El control CheckBox, o casilla de verificación, permite elegir una opción (activada/desactivada,


True/False) que el usuario puede establecer o anular haciendo click. Una X en una casilla de
verificación indica que está seleccionada, activada, o con valor True. Cada casilla de verificación es
independiente de las demás que puedan existir en el formulario, pudiendo tomar cada una de ellas
el valor True o False, a voluntad del operador.

Un control OptionButton muestra una opción que se puede activar o desactivar, pero con
dependencia del estado de otros controles OptionButton que existan en el formulario.

Generalmente, los controles OptionButton se utilizan en un grupo de opciones para mostrar


opciones de las cuales el usuario sólo puede seleccionar una. Los controles OptionButton se
agrupan dibujándolos dentro de un contenedor como un control Frame, un control PictureBox o un
formulario. Para agrupar controles OptionButton en un Frame o PictureBox, dibuje en primer
lugar el Frame o PictureBox y, a continuación, dibuje dentro los controles OptionButton. Todos
los controles OptionButton que están dentro del mismo contenedor actúan como un solo grupo, e
independientes de los controles OptionButton de otros grupos distintos.
Aunque puede parecer que los controles OptionButton y CheckBox funcionan de forma similar,
hay una diferencia importante: Cuando un usuario selecciona un OptionButton, los otros controles
del mismo grupo OptionButton dejan de estas disponibles automáticamente. Por contraste, se
puede seleccionar cualquier número de controles CheckBox.

En el ejemplo de la figura, existen tres grupos de OptionButton, uno en un PictureBox, que actúa,
al tiempo que como cuadro de imagen, como contenedor de controles OptionButton. Otro grupo

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 23


está en el interior de un control Frame, y el otro grupo está en el formulario. Los tres grupos son
independientes entre sí, pero interiormente al grupo solamente puede seleccionarse uno de los
OptionButton que lo componen.

En el formulario también existen tres CheckBox, que como puede verse, se pueden seleccionar los
que se desee, sin ningún tipo de exclusión entre ellos.

PROPIEDADES

Las señaladas con (*) son comunes a ambos controles y no presentan novedades respecto a las ya
comentadas para los controles precedentes.

Alignment Común a ambos controles.

Admite los siguientes valores :

0 - Left Justify
1 - Right Justify

Cuando se elige el valor 0, justificado a la izquierda, el título del control aparece a la derecha del
botón, pegado a la figura del botón. Cuando se elige el valor 1, justificado a la derecha, el título
(Caption) aparece a la izquierda del botón, comenzando en la parte izquierda del cuerpo total del
control, es decir, no tiene porqué aparecer con su parte derecha pegado al botón, caso que el
cuerpo total del control se haya hecho mas largo que la palabra del título.

Appearance Backcolor Caption (*).

DataField DataSource Propiedades del CheckBox solamente.


Establecen el control Data asociado y el campo donde están los datos (True / False) que se
llevarán a la propiedad Value . Al igual que en los controles Label y TextBox esta propiedad nos
permite visualizar datos de una base de datos de una forma muy sencilla. En este caso, el
CheckBox solamente permite presentar (logicamente) datos de tipo Booleano.

DragIcon DragMode Enabled Font ForeColor (*)

Height Común a ambos controles.


La altura del control solamente afecta a la colocación del Titulo (Puede ponerse un título largo en
varias líneas), no al tamaño del botón, que es invariable.

HelpContextID Index Left MouseIcon MousePointer Name


TabIndex TabStop Tag Top (*)

Value Común a ambos controles


El valor de esta propiedad indica si el control está seleccionado (Value = 1) o no seleccionado
(Value = 0 ó Value = False). Esta propiedad puede cambiarse en tiempo de ejecución. Mediante
esta propiedad, podemos tanto forzar el valor como leerlo.

Atención. Presenta una diferencia entre uno y otro control respecto a la forma de expresarse
respecto a su valor cuando está seleccionado. Para forzar que el control NO esté seleccionado, o
para leer el Value cuando no está seleccionado, podemos utilizar tanto Value = 0 como Value =
False. Sin embargo, cuando lo que se quiere es poner la propiedad a True hay una diferencia entre
ambos controles.
Para el OptionButton podemos utilizar indistintamente las siguiente formas :

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 24


Option1.Value = True Option1.Value = 1

Con cualquiera de ellas seleccionaremos ese control por programa.


Para el CheckBox solamente se podrá usar para este propósito la instrucción :

Check1.value = 1

El poner como Value el valor True nos dará en este control un error.

Para la lectura del Value, existe una diferencia entre el valor devuelto por el CheckBox y el
devuelto por el OptionButton.

Para leer el dato existente en un CheckBox es necesario utilizar la forma :

variable = Check1.Value donde variable tomará el valor 1 (no True)

Para el control OptionButton emplearemos una instrucción igual :

variable = Option1.Value donde variable tomará el valor True (no 1)

Visible WhatsThisHelpID Width (*)

PROCEDIMIENTOS

Click DblClick (Solo OptionButton) DragDrop DragOver GotFocus


KeyDown KeyPress KeyUp LostFocus

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 25


LIST BOX Y COMBO BOX
Estos dos controles, debido a su similitud, se estudian conjuntamente.

Se obtienen directamente de la caja de herramientas :

Un control ListBox muestra una lista de elementos en la que el usuario puede seleccionar uno o
más. Si el número de elementos supera el número que puede mostrarse, se agregará
automáticamente una barra de desplazamiento al control ListBox.

Un control ComboBox combina las características de un control TextBox y un control ListBox. Los
usuarios pueden introducir información en la parte del cuadro de texto y seleccionar un elemento en
la parte de cuadro de lista del control. En resumen, un ComboBox es la combinación de un
ListBox, que se comporta como si de un ListBox se tratase, y de un TextBox, con
comportamiento análogo a un TextBox sencillo, con la particularidad aquí de que el texto se le
puede introducir por teclado, o elegir uno de los que figuran en la parte ListBox del Combo.

Estos controles toman la siguiente forma :

Puede verse en la figura un ejemplo de presentación de un ListBox (izquierda), un ComboBox con


la lista desplegada (Centro) y un ComboBox con la lista sin desplegar (Combo2 a la derecha).

La lista tiene varios elementos. Cada línea de esta lísta es un elemento de la lista. Como el número
de elementos de la lista tiene mas elementos de los que le podían caber, generó automáticamente
la barra de desplazamiento vertical.

El ComboBox está normalmente sin desplegar. Se despliega cuando se hace click con el ratón en
la flecha que tiene en su parte derecha (véase fig. Anterior). Al desplegarse, muestra la lista con
todos sus elementos. Haciendo click con el ratón en cualquiera de sus elementos, el elemento
elegido pasa a la parte TextBox del Combo y la lista vuelve a replegar.

El ListBox (y por tanto el ComboBox) tiene unas propiedades y métodos particulares que
solamente se pueden aplicar durante el tiempo de ejecución :

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 26


Propiedades
ListCount - Indica el número de elementos que tiene la lista
ListIndex - Indica el número de orden del elemento seleccionado dentro de la lista.
Text - Obtiene el elemento seleccionado.
List (n) - Obtiene el elemento cuyo orden dentro de la lista es n.
Métodos
AddItem - Añade un elemento a la lista.
RemoveItem - Elimina un elemento de la lista.
Clear – Borra todos los elementos de la lista

ListCount valdrá 0 si la lista no tiene ningún elemento, y n si tiene n elementos.

Para seleccionar un elemento de la lista, basta con hacer click con el ratón sobre él. Ese elemento
se resaltará con fondo en azul. Una vez seleccionado un elemento, la propiedad ListIndex tomará
el valor del número de orden que ocupa ese elemento en la lista, comenzando por el 0 para el
elemento que ocupa el primer lugar. Si no se selecciona ningún elemento, el valor de la propiedad
ListIndex será -1. El primer elemento de la lista es ListIndex 0, y el valor de la propiedad
ListCount siempre es uno más que el valor mayor de ListIndex.

En el ComboBox la propiedad Text contiene el texto que contenga la parte TextBox del Combo,
bien haya sido introducida desde teclado o mediante la recuperación de un elemento la parte
ListBox del mismo.

Ejemplos

Supongamos que tenemos un ListBox llamado List1, y un ComboBox llamado Combo1. Se


enumeran distintas formas de obtener información de ellos.

Variable = List1.Listcount
Variable contendrá un número con el número total de elementos de la lista List1.

Variable = List1.ListIndex
Variable contendrá un número con el número de orden del elemento de la lista
seleccionado en ese momento.

List1.AddItem “ELEMENTO NUEVO”


Añade un elemento a List1. En este caso, el elemento añadido es la palabra
ELEMENTO NUEVO.

Variable = “VISUALBASIC”
List1.AddItem Variable
Añade un elemento a List1. En este caso, el elemento añadido es la palabra
VISUALBASIC.

Variable = List1.Text
Variable contendrá el elemento que estaba seleccionado en List1. (Variable será
una cadena de caracteres)

Variable = List1.List (n)


Variable contendrá el elemento que ocupa el número de orden n dentro de la lista.

Variable = List1.List (List1.ListIndex)


Variable contendrá el elemento que estaba seleccionado en List1. Se ha utilizado la

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 27


propiedad List para obtener el elemento, y en vez de introducir un número para
definir el elemento que se desea, se introdujo el valor ListIndex de List1, que es
concretamente, el número de orden del elemento seleccionado en ese momento.
Observe que poner List1.List (List1.ListIndex) es idéntico a poner List1.Text.

List1.RemoveItem (n)
Elimina el elemento n de List1.

List1.RemoveItem (List1.ListIndex)
Elimina el elemento que estaba seleccionado en ese momento.

List1.listIndex = n
Selecciona el elemento n de List1 (Se resalta en azul el elemento n)

PROPIEDADES DE ListBox y de ComboBox

Las señaladas con (*) son comunes a ambos controles y no presentan novedades respecto a las ya
comentadas para los controles precedentes.

Appearance Backcolor (*)

Columns Propiedad de ListBox solamente.

Determina si los elementos se presentan en una sola columna o en varias columnas, y la forma de
presentar los elementos en el ListBox. Si esta propiedad se pone a 0 la lista tendrá solamente una
columna, y presentará los elementos uno debajo de otro. Cuando los elementos sean mas que los
que se pueden presentar en la lista, aparecen automáticamente unas barras de desplazamiento
vertical.
Si la propiedad se pone a un número distinto a 0, el ListBox es de tipo multicolumna, presentará en
cada columna los elementos que le quepan dependiendo de su dimensión vertical, y tendrá tantas
columnas como sea necesario para albergar el número de elementos que tenga. Presentará en su
cuadro tantas columnas como se le indique en el valor de esta propiedad, y si no puede presentar
todos los elementos en las columnas que muestra, le aparecerán barras de desplazamiento
horizontales para poder movernos por todas las columnas que tenga.
Recuerde : El número que se le asigna a la propiedad Columns no indica el número de columnas
que tendrá el ListBox sino el número de columnas que presenta.

Esta propiedad puede asignarse en diseño, mediante la caja de propiedades, o en tiempo de


ejecución mediante una instrucción como esta :

Nombrelista.Columns = número
.
Esta propiedad no puede definirse a 0 o cambiada desde 0 en tiempo de ejecuciones decir, no se
puede convertir en tiempo de ejecución un ListBox de múltiples columnas en un ListBox de columna
única o un ListBox de columna única en un ListBox de múltiples columnas. Sin embargo, sí es
posible cambiar durante la ejecución el número de columnas de un ListBox de múltiples columnas.

DataField DataSource .
Establecen el control Data asociado y el campo donde están los datos que se llevarán al TextBox o
ComboBox para presentar datos procedentes de una Base de Datos.

DragIcon DragMode Enabled Font ForeColor Height


HelpContextIDIndex (*)
ItemData Propiedad muy importante.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 28


Devuelve o establece un número específico para cada elemento de un control ComboBox o
ListBox.

Sintaxis NombreDeLaLista.ItemData(índice) [= número]

NombreDeLaLista Nombre del ListBox o ComboBox.


índice El número de un elemento concreto del objeto.
número El número que se asocia con el elemento especificado.

La propiedad ItemData es una matriz de valores enteros largos cuyo número de elementos es el
valor de la propiedad ListCount del control. Los números asociados con cada elemento se pueden
usar para cualquier fin. Por ejemplo, se puede usar en la confección de una lista de teléfonos, el
número de identificación de un empleado, etc. Cuando se rellena el ListBox, también se rellena los
elementos correspondientes de la matriz ItemData con los números correspondientes.
La propiedad ItemData se usa a menudo como índice de una matriz de estructuras de datos
asociados con los elementos de un control ListBox.

Nota Cuando se inserta un elemento en una lista con el método AddItem, el elemento también se
inserta automáticamente en la matriz ItemData. Sin embargo, el valor no se reinicializa a cero;
retiene el valor que estaba en esa posición antes agregar el elemento a la lista. Cuando se usa la
propiedad ItemData, asegúrese de establecer su valor al agregar nuevos elementos a la lista.

Left (*)

List Es el contenido de la lista.


Si la lista de elementos es corta e invariable, pueden introducirse los elementos en el cuadro de
propiedades durante el diseño.

MouseIcon MousePointer Name (*)

Sorted

Establece o devuelve un valor que indica si los elementos de un ListBox o ComboBox se


colocan automáticamente en orden alfabético. Los valores que puede adoptar son True o
False.

True Los elementos de la lista se ordenan alfabéticamente (sin distinguir entre


mayúsculas y minúsculas).
False (Predeterminado) Los elementos de la lista no se ordenan alfabéticamente.

Cuando esta propiedad tiene el valor True, Visual Basic se encarga de casi todo el
procesamiento de cadenas necesario para mantener el orden alfabético, incluyendo el
cambio de los números de índice cuando se agregan o eliminan elementos.

Nota El uso del método AddItem para agregar un elemento en una posición específica de
la lista puede romper el orden alfabético, y los elementos agregados con posterioridad
pueden no ordenarse correctamente.

TabIndex TabStop Tag Top Visible WhatsThisHelpID Width (*)

PROCEDIMIENTOS

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 29


Click Change (Solo ComboBox) DblClick DragDrop DragOver
DropDown (Solo ComboBox) GotFocus KeyDown KeyPress
KeyUp LostFocus MouseDown (Solo ListBox) MouseMove (Solo ListBox)
MouseUp (Solo ListBox)

NOTA MUY IMPORTANTE

El procedimiento Change del ComboBox solamente se efectúa cuando el cambio se produce


mediante la entrada de un texto DESDE EL TECLADO, no por un cambio en la parte Text de este
control, producido al llevar un elemento desde la parte List a la parte Text.

CONTROLES HScrollBar y VScrollBar


Son dos controles similares, para introducir un dato cuasi-analógico en una aplicación. Se toman
directamente de la caja de herramientas, y tienen un aspecto parecido al de un control de volumen
de un equipo de música. El HScrollBar está en posición horizontal, y el VScrollBar en posición
vertical.

Mediante estos controles se pueden introducir datos variando la posición del cursor.

PROPIEDADES de HScrollBar y VScrollBar

Las señaladas con (*) son comunes a ambos controles y no presentan novedades respecto a las ya
comentadas para los controles precedentes.

DragIcon DragMode Enabled Height HelpContextID Index (*)

LargeChange
Esta propiedad establece la variación de la propiedad Value cada vez que se hace click en el
interior de la barra de desplazamiento, en la parte por donde pasa el cursor.

Left (*)

Max
Esta propiedad establece el valor máximo para la propiedad Value, es decir, el valor de esta
propiedad cuando el cursor está en su parte máxima. (Recuerde que el cursor está en el máximo,
cuando está mas a la derecha, caso del HScrollBar, o cuando está en la parte mas baja, caso del

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 30


HScrollBar.

Min
Esta propiedad establece el valor mínimo para la propiedad Value, es decir, el valor de esta
propiedad cuando el cursor está en su parte mínima. (Recuerde que el cursor está en el mínimo,
cuando está mas a la izquierda, caso del HScrollBar, o cuando está en la parte mas alta, caso del
HScrollBar.

MouseIcon MousePointer Name (*)

SmallChange
Esta propiedad establece la variación de la propiedad Value cada vez que se hace click en las
flechas superior o inferior de la barra de desplazamiento.

TabIndex TabStop Tag Top (*)

Value
Esta propiedad lee o establece el valor dado por la posición del cursor. Este valor tiene un mínimo,
establecido por Min y un máximo, establecido por Max. Esta propiedad es la que se debe leer para
conocer la posición del cursor.

Visible WhatsThisHelpID Width (*)

PROCEDIMIENTOS DE HScrollBar y VScrollBar

Change DragDrop DragOver GotFocus KeyDown KeyPress


KeyUp LostFocus Scroll

Comentario El Procedimiento Change se produce cuando, tras mover el cursor, se suelta el


botón del ratón. Esto produce el efecto de que el cambio que se tenga que producir con el
movimiento del cursor no se realiza de una manera continua. El procedimiento Scroll se realiza en
el instante que se está moviendo el cursor. Por lo tanto, es este procedimiento el que se debe usar
para conseguir el efecto de un cambio continuo mientras se está moviendo el cursor.

TIMER TEMPORIZADOR
Este objeto permite establecer temporizaciones. Presenta una novedad respecto a los controles
estudiados hasta ahora. El control Timer solamente se ve durante el tiempo de diseño. En tiempo
de ejecución, el control permanece invisible.

La temporización producida por el Timer es independiente de la velocidad de trabajo del ordenador.


(Casi independiente. El timer no es un reloj exacto, pero se le parece)

Se toma directamente de la caja de herramientas, y tiene el aspecto siguiente :

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 31


PROPIEDADES

Enabled Index (*)

Interval
El valor de esta propiedad nos dará el intervalo de tiempo (en milisegundos) en que se producirá un
evento Timer y consecuentemente, realizará el procedimiento asociado a este evento. Si el valor de
la propiedad Interval está a 0 (Predeterminado), no se produce el evento Timer. (El control Timer
está deshabilitado cuando la propiedad Interval = 0)

Left Name Tag Top (*)

PROCEDIMIENTOS

Timer

Se produce cada vez que se cumple un intervalo completo.

CONTROL SHAPE
Se toma directamente de la caja de herramientas :

Shape es un control gráfico que se muestra como un rectángulo, un cuadrado, una elipse, un
círculo, un rectángulo redondeado o un cuadrado redondeado.

Un control Shape no actúa como contenedor de controles. (Esto quiere decir que un control Shape
nunca le servirá, por ejemplo, para albergar varios OptionButton y pretender que sean
independientes de otros controles OptionButton que se encuentren fuera del control Shape.

Este control no tiene Procedimientos. En realidad, solamente sirve para mostrar un determinado
gráfico, envolver gráficamente a otros controles, pero no tiene ninguna aplicación en cuanto a
programa. Es un “adorno” para sus aplicaciones.

PROPIEDADES

Backcolor (*)

BackStyle
Esta propiedad establece si Shape permite ver a su través (Transparent) o n lo permite (Opaque)

BorderColor
Establece el color del borde.

BorderStyle

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 32


Establece el tipo de borde. Puede ser : Transparent, (No se ve el borde), Solid, (Borde de línea
continua),Dash, (línea a rayas), Dot, (línea a puntos), Dash-Dot, (línea de raya - punto), dash-Dot-
Dot, (línea de raya - punto - punto), InsideSolid, (raya continua)

El efecto de establecer la propiedad BorderStyle depende del valor de la propiedad BorderWidth. Si


BorderWidth no es 1 y BorderStyle no es 0 o 6, BorderStyle se establece como 1.

BorderWidth
Establece el ancho de la línea.

DrawMode FillColor FillStyle Height Index Left Name (*)

Shape
Establece la forma del control. Puede ser : Rectangular, cuadrado, redondo, ovalado, cuadrado con
esquinas redondeadas y rectangular con esquinas redondeadas.

Tag Top Visible Width (*)

PROCEDIMIENTOS No tiene.

CONTROL LINE

Se toma directamente de la caja de herramientas

Line, al igual que Shape, es un control gráfico que solamente sirve para poner una línea en un
formulario. Del mismo modo, no tiene procedimientos, por lo que no sirve para aportar código al
programa. Solo sirve para aportar una característica gráfica, es un adorno.

PROPIEDADES

BorderColor
Establece el color de la línea.

BorderStyle
Establece el tipo de línea : Puede ser : Transparent, (No se ve la línea), Solid, (Línea
continua),Dash, (línea a rayas), Dot, (línea a puntos), Dash-Dot, (línea de raya - punto), dash-Dot-
Dot, (línea de raya - punto - punto), InsideSolid, (raya continua)

BorderWidth
Establece el ancho de la línea.

DrawMode Index Left Name Tag Visible (*)


X1, X2 Y1, Y2 Establece las coordenadas y del inicio y final

PROCEDIMIENTOS No tiene.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 33


AÑADIR CONTROLES A LA CAJA DE HERRAMIENTAS

Los controles descritos hasta ahora son parte de los que aparecen en la caja de herramientas mas
elemental de Visual Basic. Estos, otros que se estudiarán en el capítulo 4 (Controles para mostrar
imágenes), el control Data y el contenedor OLE que se estudiarán en la segunda parte del curso,
son los que están incluidos en la caja de herramientas mas elemental. La razón es que estos
controles vienen como lo más elemental de Visual Basic, como lo que es imprescindible para que
funcione una aplicación realizada en VB. La pregunta es ahora, ¿qué es lo más elemental de VB?

Son tres DLLs, Visual Basic For Aplications (MSVBVM60.DLL), Visual Basic Runtime Objets And
Procedures (MSVBVM60.DLL\3) y Visual Basic Objets And Procedures (VB6.OLB). Una aplicación,
por muy elemental que sea, necesita esos tres ficheros. Pero posiblemente no haya ninguna
aplicación práctica que se pueda realizar con esos controles. Hay más. Lo que ocurre es que hay
que introducirlos en la caja de herramientas. Para ello, basta con desplegar el menú de Proyecto
de la barra de menú:

Eligiendo el elemento Componentes de este menú desplegado nos muestra todos los componentes
existentes en el disco, que podremos sacar a nuestra caja de herramientas para poder utilizarlos.
En la siguiente figura puede ver el cuadro con los controles existentes en el PC del autor. Puede
observarse que está seleccionado el control Calendar, y en la parte de abajo puede verse la
ubicación y nombre del fichero que contiene ese control (MSCAL.OCX). No todos los controles
son de Microsoft. Observe que hasta Kodak realiza (o le realizan) controles. Existen muchas
empresas que venden controles, unas con mejor calidad que otras. En este tema debe tener
especial precaución con los controles que se distribuyen de forma gratuita por Internet. No utilice
nunca un control adquirido por este procedimiento si no tiene plena confianza en el origen del
mismo y lo ha probado concienzudamente. Suelen fallar con bastante frecuencia y, lógicamente, no
tienen ninguna garantía. Sea prudente y utilice solamente aquellos controles de firmas de

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 34


reconocido prestigio, y que le puedan aportar garantía de funcionamiento. Obviamente estos
controles suelen ser de pago.

Estos controles que adquiere con posterioridad a la instalación del Visual Basic hay que
registrarlos. No se asuste. No se trata de registrarlos ante el fabricante para poder utilizarlos. Se
trata de introducirlos en el registro de Windows. Con ello Windows conoce el CLSID de ese control,
su ubicación en el disco duro (los controles suelen estar en C:\Windows\System, pero pueden estar
en cualquir otra carpeta). Windows necesita registrarlos para poder encontrarlos. Para registrar un
control se utiliza el programa Regsvr32.exe. Para registrar un control basta con ejecutar este
programa, pasandole como parámetro el nombre y ubicación del control a registrar. Esto se hace
en Inicio | Ejecutar. Por ejemplo, para registrar el conjunto de controles VB_GuiaEst.Ocx
introduciríamos ese fichero Ocx en C:\Windows\System y a continuación ejecutamos:

regsvr32 c:\windows\system\ VB_GuiaEst.Ocx

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 35


El conjunto de todos los controles es la colección Controls

Verá a lo largo del curso que Visual Basic utiliza mucho las colecciones. Una de ellas es la
colección Controls, que es el conjunto de todos los controles existentes en un formulario.

Visual Basic trata a las colecciones como un objeto más. Así, las colecciones tienen sus
propiedades. No vamos a entrar en demasiados detalles de momento, pero una de las propiedades
de todas las colecciones en Count, que es precisamente el número de elementos que componen
esa colección.

La numeración de los elementos de una colección siempre va del 0 al n-1, siendo n el número de
elementos de esa colección.

Vamos a ver una expresión que nos puede ayudar mucho. Sirve para saber a que tipo de control
pertenece un determinado elemento. Esa expresión es TypeOf y siempre se debe usar con una
sentencia condicional If y aplicarla solamente sobre una variable tipo objeto. (No se preocupe al
leer esto, es muy fácil) (No se puede utilizar con Select Case)

Una variable tipo objeto es una variable que no contiene un dato numérico o string. Contiene un
objeto. Por ejemplo, un control.

Podemos declarar una variable como Control

Dim Pepe as Control

Pepe será un control. Ahora podemos poner

For Each Pepe in Controls ‘ Para cada valor que tome Pepe haciedole recorrer todos
‘ los elementos de la colección Controls
If TypeOf Pepe Is TextBox Then ' Si pepe es un TextBox ….
Pepe.Locked = True ' lo bloquea
End If
Next Pepe

Puede usar este código para bloquear todos los TextBox de un formulario. Se mete en un
procedimiento llamado Bloquear (p.e.) y cada vez que queramos bloquear todos los TextBox del
formulario basta con citar a este procedimiento. Un código similar sería

Dim I As Integer
For I = 0 To Controls.Count - 1
If TypeOf Controls(I) Is TextBox Then
Controls(I).Locked = True
End If
Next

(Observe que en la segunda versión, trabajamos directamente sobre los elementos de la colección,
que se distinguen unos de otros mediante el Indice colocado entre paréntesis. En este caso, la
variable I que tomará los valores entre 0 y n-1)

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 36


Resumen de Propiedades de los controles Visual Basic
Caption Título

Es el texto del control o lo que figura en la barra de menú del formulario. Puede cambiarse en
tiempo de ejecución.

DragMode Modo de iniciar una operación de Drag & Drop


Establece un valor que determina si se usa el modo de arrastre manual o automático en una
operación de arrastrar y colocar. Los valores posibles de esta propiedad son:

0 Manual
1 Automático

DrawStile Estilo de dibujo

Establece el estilo de línea de la salida de métodos gráficos:


Valores: 0 - Línea continua
1 - Rayas
2 - Puntos
3 - Raya - Punto
4 - Raya - Punto - Punto
5 - Transparente
6 - Continuo interior.

DrawWidth Ancho de la línea

Establece el ancho de una línea dibujada. El valor debe expresarse en pixeles.

Enabled Activado

Propiedad Booleana. Si está en True, el formulario o control está activado y se puede interactuar
con él. Si está en False, se desactiva, impidiendo de esta forma, que se pueda trabajar con él.
Puede variarse en tiempo de ejecución. Cuando un control está deshabilitado (Enabled = False), el
control no tiene efecto, y su apariencia varía, presentando un tono pálido tanto en su cuerpo como
en su título.

FillStyle Tipo de relleno

Establece el modo de rellenar controles Shape, o figuras (círculos o cuadrados) creados con los
métodos gráficos Circle y Line.

Valores: 0 - Continuo
1 - Transparente
2 - Línea Horizontal
3 - Línea Vertical
4 - Diagonal hacia arriba
5 - Diagonal hacia abajo
6 - Cruzado
7 - Diagonal cruzada

FillColor Color de relleno

Especifica el color del relleno contemplado en FillStyle.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 37


Font Fuente
Es el tipo de letra para el título o el texto del control. Puede cambiarse en tiempo de ejecución.

FontSize Tamaño de letra

Establece el tamaño de la letra que se usará en ese formulario o control (U otro objeto VB, p.e. el
Printer). Esta propiedad puede variarse en tiempo de ejecución. El tamaño debe expresarse en
puntos. Máximo, 2160 puntos.

FontBold, FontItalic, FontStrikethru, FontUnderline

Permiten, en tiempo de ejecución, cambiar un texto a negrita, cursiva, tachado y subrayado. Son
propiedades Booleanas True / False

Height Altura

Define la altura de un formulario o control. El valor de esta propiedad no se introduce normalmente


como un dato numérico, sino que toma el valor automáticamente, dependiendo de las dimensiones
del objeto durante el tiempo de diseño. Puede cambiarse durante el tiempo de ejecución.

HelpContextID Número de Contexto

Establece un número de contexto asociado para este formulario. Este número se aplica para
determinar la ayuda interactiva asociada a este formulario o control. Vea mas adelante, el tema
Ayuda de Windows.

Puede tomar los siguientes valores : 0 - No se especifica número de contexto


>0 Un entero que especifique un contexto válido.
Index Indice

En el caso de que se tengan varios controles que realicen una función similar (Las teclas numéricas
de una calculadora, p.e.) puede hacerse un array con estos controles. Todos tendrán el mismo
nombre, y se diferencian por un índice. La propiedad Index de ese control toma el número de ese
índice.

Left Posición de su parte izquierda.

Indica la posición del control, concretamente de la parte izquierda del mismo. Normalmente esta
propiedad no se introduce numéricamente, sino que la toma automáticamente de la posición que se
le de al control en tiempo de diseño. Puede cambiarse en tiempo de ejecución.

MouseIcon Valor por defecto: ninguno

Establece un icono personalizado para el puntero del ratón cuando esté encima del Formulario o
control. Este icono puede ser un Bitmap de los existentes en el directorio Icons de Visual Basic o
cualquiera que tengamos. Si se pone 99 como valor de la propiedad MousePointer (siguiente),
cada vez que el puntero del ratón pase por este Formulario o control, cambiará su forma y adoptará
la del icono elegido.

MousePointer Valor por defecto: flecha

Determina la forma del puntero del ratón cuando se coloca encima del formulario o control. Puede
elegirse uno de los punteros preestablecidos (15 en total) o el personalizado visto en la propiedad
anterior. Para elegir ese icono personalizado, debemos poner en esta propiedad el valor 99.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 38


TabIndex Nº de orden para tabulador

Cuando disponemos de varios controles en un mismo formulario, solamente uno de ellos tiene el
foco. Esta expresión de tener el foco significa que ese control está remarcado y en esa condición, si
pulsamos la tecla ENTER haría el mismo efecto que hacer click con el ratón en ese control, o, en el
caso de un TextBox, las letras pulsadas en el teclado van a ese TextBox.

Podemos variar el foco de un control a otro mediante la tecla TAB (TABulador).Esto es necesario,
ya que existen ordenadores que no disponen de ratón (típico de algunos portátiles). En estos casos,
para elegir uno u otro control debemos pulsar repetidas veces la tecla TABulador. El foco irá
cambiando de uno a otro control (pueden ser controles de distinto tipo) cada vez que pulsemos la
tecla TABulador. Esta propiedad TabIndex marca el orden que seguirá el foco a través de cada
control.

TabStop Sale del control de la tecla TAB

Propiedad Booleana. Cuando esta propiedad está a False, el botón no tomará el foco cuando se
pulse la tecla del Tabulador. Sin embargo sigue manteniendo el índice de la propiedad TabIndex
descrita anteriormente. Puede cambiarse en tiempo de ejecución. Esto nos permite descartar algún
botón de tomar el foco, cuando por facilidad para el usuario, sea conveniente en determinados
puntos del programa.

Tag Valor auxiliar

Esta propiedad no la usa directamente Visual-Basic. Sirve para asociar al formulario información
adicional para fines externos a la programación. Pero también le puede servir para almacenar en
ella una variable para que la use un código ajeno al formulario. El autor de esta Guía del Estudiante
tiene por costumbre utilizar la propiedad Tag del formulario inicial para guardar el parámetro que se
le pasa a algunos programas para acceder a ellos con unos determinados privilegios. Resumiendo,
está ahí para lo que el programador quiere.

Top Posición de la parte superior

Indica la coordenada de la parte superior del control. Puede variarse durante el tiempo de
ejecución. Esta propiedad, juntamente con Left definen la esquina superior izquierda del botón de
comando. Normalmente esta propiedad no se introduce numéricamente, sino que la toma
automáticamente de la posición que se le den al botón en tiempo de diseño. Puede cambiarse,
cambiando el valor a esta propiedad, en tiempo de ejecución.

Visible

Propiedad Booleana. Asignándole el valor True al control o formulario, será visible, y asignándole el
valor False, no se verá. Este valor puede cambiarse durante el tiempo de ejecución para ocultar y
hacer visible el formulario o control correspondiente.

WhatsThisHelpID (Propiedad, Windows 95)

Devuelve o establece un número de contexto asociado a un objeto. Se utiliza para dotar a las
aplicaciones de Ayuda interactiva con el menú emergente ¿Qué es esto? de la Ayuda de W 95.

Width Ancho

Define la anchura del formulario o control. Normalmente no se introduce como valor numérico sino

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 39


que lo toma automáticamente del tamaño que tenga el formulario o control durante el tiempo de
diseño. Juntamente con Height define el tamaño del objeto. Puede cambiarse durante el tiempo de
ejecución

RESUMEN DE LOS EVENTOS DE LOS OBJETOS VISUAL BASIC

Evento Click Hacer Click con el botón izquierdo del ratón

Lo tienen casi todos los controles y el formulario. Es el evento habitual para introducir el código que
queremos que realice el programa al hacer click sobre un determinado control. No es el único
evento donde podemos hacerlo, pues también tenemos otros muy parecidos (MouseDown,
MouseUp), pero que funcionan de distinta forma. El evento Click en el formulario se efectúa cada
vez que pulsamos uno de los botones del ratón. En los controles, sólo con el botón izquierdo.

Si un control tiene el foco, se ejecutará su evento Click al pulsar ENTER o la barra espaciadora.

El evento Click no pasa parámetros

Evento DragDrop Acción de Soltar durante el Drag & Drop


Se produce cuando se ‘suelta’ el ratón sobre un formulario o control, durante una operación de Drag
& Drop. Pasa los parámetros Source As Control, X As Single, Y As Single, donde Source es el
control donde se originó el Drag & Drop, y X e Y las coordenadas del puntero del ratón en el
momento de soltar. Vea el capítulo de Drag & Drop

Evento DragOver Arrastrar por encima


Ocurre cuando se pasa por encima de un formulario o control durante la operación de Drag & Drop.
Pasa los parámetros Source As Control, X As Single, Y As Single, State As Integer. Los
parámetros son los mismos que en el procedimiento anterior. State es un entero que indica el
estado de transición del puntero sobre el formulario. Toma los siguientes valores :

0 = Entra (El puntero del ratón está entrando al formulario o control).


1 = Deja (El puntero del ratón está saliendo del formulario o control).
2 = Sobre (El puntero del ratón se desplaza de una posición a otra dentro del formulario o
control). Vea el capítulo de Drag & Drop

Evento GotFocus Tomar el Foco


Ocurre este evento cuando el control toma el foco. Tomar el foco significa que se acaba de
convertir en el control activo. (por ejemplo, cuando llevamos el cursor y hacemos click sobre un
Text Box. Hay algunos controles que no tienen procedimiento GotFocus porque nunca toman el
foco (Label, p.e.)

Evento KeyDown Pulsar una tecla (Ocurre cuando el control tiene el foco)
Se produce sobre el control que tiene el foco al pulsar una tecla, justo en el instante que llega a su
posición inferior. Pasa como parámetros el KeyCode As Integer y el Shift As Integer. El KeyCode
es el código de la tecla (no confundir con Keyascii, que es el código de la letra. Hay teclas que no
tienen Keyascii y sí tienen KeyCode F1, F2, ...Insert, ) Shift es la posición de la tecla Mayúsculas
(1=pulsada, 0=levantada)

Evento KeyPress Pulsar una tecla (Ocurre cuando el control tiene el foco)
Este evento se produce después del KeyDown, y pasa como parámetro el KeyAscii As Integer, que
es el código Ascii de la letra cuya tecla se ha pulsado.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 40


Evento KeyUp Levantar la tecla pulsada (Ocurre cuando el control tiene el foco)
Ocurre al levantar la tecla, después del KeyPress. Pasa como parámetros los mismos que
KeyDown, KeyCode As Integer, Shift As Integer

Estos tres eventos se producen también en el formulario (y antes que en el control), si el formulario
tiene la propiedad KeyPreview = True
LinkClose
LinkError
LinkNotify
LinkOpen

Son eventos relacionados con el DDE (Intercambio Dinámico de Datos). Ocurren respectivamente
cuando se cierra el enlace DDE, cuando ocurre un error en el enlace, cuando han cambiado los
datos en origen y en destino se ha establecido la propiedad LinkMode a Notify, y cuando se inicia
una conversación DDE. Vea el capítulo dedicado al DDE para mas detalles.

LostFocus

Ocurre cuando el control pierde el foco. Este evento es muy importante, por ejemplo en un Text
Box, para dar el formato adecuado al texto contenido en ese Text Box, o para comprobar que es
correcto, etc.

MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)

Se ejecuta en el instante de apretar el botón de mouse, cuando está el puntero encima del
formulario o control correspondiente. Pasa como parámetros el botón pulsado (1= izquierdo, 2 =
derecho, 3 = centro), la tecla mayúsculas (Shift=1 significa pulsada, =0 no pulsada) y las
coordenadas X e Y del puntero del ratón.

MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

Se ejecuta cuando pasa por encima del formulario o0 control el puntero del ratón

MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)

Similar a MouseDown, pero cuando se levanta el botón.

Existen mas eventos. No se van a mencionar aquí todos, pues se irán viendo según avance el
curso.

Y no se preocupe si este capitulo le ha resultado muy pesado. Les pasa a todos. El próximo va a
ser mas divertido.

LSB Visual Basic - Guía del Estudiante Cap. 2 Página 41


Visual Basic - Guía del Estudiante Cap. 3
Controles (Continuación) El CommonDialog
CONTROLES DE BUSQUEDA DE FICHEROS

El CommonDialog es un control del que se libran muy pocas aplicaciones. Dada la importancia
de este control, se le dedicaba en versiones anteriores de la Guía del Estudiante un capitulo
único. En esta edición se le a anexado el estudio sobre los controles para la búsqueda de
ficheros. El conocimiento de este capítulo es fundamental si desea llegar a ser un buen
programador de VB.

CUADRO DE DIALOGO CommonDialog

Normalmente se encuentra en la caja de herramientas

Este control no se presenta en tiempo de diseño mas que con un simple icono :

El cuadro de diálogo, CommonDialog se utiliza para varias funciones :

· Abrir Ficheros
· Guardar Ficheros
· Elegir colores
· Seleccionar Impresora
· Seleccionar Fuentes

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 1


CommonDialog mostrando la función Abrir. Nótese el icono para crear nueva carpeta, objeto del
comentario siguiente.
En realidad el cuadro de diálogo permite conocer datos con los cuales, y mediante el código
adecuado, abriremos o guardaremos ficheros, elegiremos colores o seleccionaremos fuentes.
Es decir, el CommonDialog NO realiza mas funciones que mostrar ficheros existentes, fuentes
disponibles, colores, para que, mediante código, abramos esos ficheros o usemos una
determinada fuente.

La expresión anterior se ha recuadrado porque ya no es completamente cierta. El


CommonDialog no es un control propio de Visual Basic, sino de Windows. Y la versión de este
control que Windows pone en W98 permite que pueda crear una nueva carpeta. Ya hace algo
directamente. No se extrañe que el CommonDialog empleado en su aplicación pueda crear una
nueva carpeta sin que Vd. lo haya diseñado para eso. Al introducir el control en la aplicación
está introduciendo la versión más moderna del mismo.

Dependiendo de la aplicación para la que vaya a usarse se deberá activar de distintas formas.
Si el cuadro de diálogo se va a usar para seleccionar la impresora y para otras
aplicaciones, es recomendable usar uno exclusivamente para seleccionar la impresora.
Esta última recomendación se debe a que, para el control de la impresora, el CommonDialog SI
realiza las funciones de selección de impresora predeterminada. Esta diferencia operativa hace
que si usamos el mismo CommonDialog para seleccionar impresora y abrir ficheros, por
ejemplo, se “cuelgue” el CommonDialog.

El control CommonDialog es un control personalizado (Microsoft CommonDialog Control


COMDLG32.OCX), y como casi todos los controles personalizados presenta un asistente de
propiedades propio. Puede accederse a las propiedades mediante el cuadro de propiedades
típico de otros controles, o mediante el asistente, pulsando el botón derecho del ratón con el
puntero colocado encima del icono del cuadro de diálogo.

Analizando las propiedades, vemos que tiene gran cantidad de ellas. Esto es porque agrupa
todas las propiedades correspondientes a la cinco funciones que puede desarrollar. Se detalla a
continuación la forma de usar el CommonDialog para cada aplicación.

Se entiende que el nombre - Name - que se ha puesto para el cuadro de diálogo en todos los
ejemplos es CD1)

CUADRO DE DIALOGO MOSTRANDO FUENTES

Para mostrar el cuadro de diálogo correspondiente a Tipos de Letra ( Fonts ), debe ejecutarse
la instrucción:

CD1.ShowFont

y haber puesto, en la propiedad Flags del cuadro de diálogo, el valor de 1, 2 ó 3,


correspondiente respectivamente a los tipos de letra de la pantalla, de la impresora o ambos.
(Véase la propiedad Flags mas adelante) Si no pone uno de estos valores, le dirá que no
tiene fuentes instaladas.

Los valores que se pueden obtener de este cuadro de dialogo son:

CD1.FontName Indica el nombre de la fuente


CD1.FontSize Indica el tamaño de la fuente
CD1.Color Indica el color de la fuente (Abrir con Flags=256+1, 2 ó 3)
CD1.FontBold = (True / False) Si es True, se ha elegido "Negrita"
CD1.FontItalic = (True / False) Si es True, se ha elegido "Cursiva"
CD1.FontStrikethru = (True / False) Si es True, se ha elegido "Tachada "

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 2


CD1.FontUnderline = (True / False) Si es True, se ha elegido "Subrayada"
Si se elige una versión Negrita Cursiva serían True las opciones FontBold y FontItalic

El cuadro de diálogo que se presenta es el siguiente: (CommonDialog Mostrando fuentes, con


la propiedad Flags = 263)

El objeto Font no puede aplicarse al CommonDialog. Es decir, no podemos poner :


Variable = CD1.Font.Size sino Variable = CD1.Fontsize
En el ejemplo que acompaña a este capítulo, puede ver como se introducen las características
de una determinada fuente elegida en un cuadro de texto.

Programa de ejemplo. Mediante un CommonDialog elegimos el tipo de letra de un TextBox


(TbPrueba) y escribimos un texto de prueba con todas las letras del abecedario.

Private Sub BMostrarFonts_Click()


CD1.Flags = 259
'Muestra las fuentes de la pantalla (1), las de la impresora (2)y muestra las opciones de
'tachado, subrayado y color (256) 1 + 2 + 256 = 259
CD1.ShowFont
TbPrueba.FontName = CD1.FontName
TbPrueba.FontSize = CD1.FontSize
TbPrueba.FontBold = CD1.FontBold
TbPrueba.FontItalic = CD1.FontItalic
TbPrueba.FontUnderline = CD1.FontUnderline
TbPrueba.FontStrikethru = CD1.FontStrikethru
If TbPrueba = "" Then
TbPrueba = "Texto de prueba" & vbCrLf & vbCrLf
TbPrueba = TbPrueba & "The Quick Brown Fox Jumps Over The Lazy Dog 1234567890"
End If
End Sub

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 3


CUADRO DE DIALOGO MOSTRANDO COLOR

Para mostrar el cuadro de diálogo correspondiente al color, se deberá ejecutar la instrucción:

CD1.ShowColor

El cuadro de diálogo puede tener una de estas dos formas (Dependiendo de su propiedad
Flags):

(Si la parte derecha del cuadro no sale, se saca haciendo click en Definir colores
personalizados.)

El número correspondiente al color elegido se puede conocer analizando la propiedad color de


cuadro de diálogo. En nuestro ejemplo, lo obtendríamos con

Variablecolor = CD1.Color

donde Variablecolor contendrá un número correspondiente al color elegido. Variablecolor debe


declararse como tipo Long

Programa de ejemplo. Mediante un CommonDialog elegimos el color de fondo de un TextBox


(TbPrueba).

Private Sub BColores_Click()


CD1.Flags = 2
'Hace que el cuadro de diálogo se muestre completo
CD1.ShowColor
TbPrueba.BackColor = CD1.Color
End Sub

Nota acerca del número del color.

Para establecer un color por medio de código, se pondrá un valor de color a la propiedad
correspondiente de ese objeto. El valor del color puede establecerse de tres formas que se
comentan a continuación.

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 4


Colores en Visual Basic.

Visual Basic acepta para especificar un color, tres procedimientos: Mediante el número de
color, mediante la sentencia RGB ( rojo, verde, azul ) o mediante la función QBColor.

Por número

El número que representa el color en VB está formado por la suma de la componente roja, la
componente verde y la componente azul. Podríamos verlo muy bien en numeración
Hexadecimal:

Color = Hex XX YY ZZ

Donde ZZ es un número Hexadecimal que representa la cantidad del color rojo. El mínimo
estaría en 0 (H00) y el máximo en 255 (HFF)

YY representaría la cantidad de color verde y XX la de color azul, ambos con los mismos límites
explicados para el rojo.

Por ejemplo: el rojo puro sería: Hex(0000FF) = 255


el verde puro sería: Hex(00FF00) = 652280
el azul puro sería: Hex(FF0000) = 16711680

Una mezcla de un poco de rojo (HB1), otro poco de verde (H56) y otro poco de azul (H1F) daría
el siguiente número:

Hex(1F56B1) = 2053809

El número de color puede estar comprendido entre 0 (correspondiente al negro) y el 16777215


(correspondiente al blanco. Observe que esa cantidad, 16.777.215 (FFFFFF en hexadecimal)
corresponde a los famosos 16 millones de colores de las tarjetas gráficas.

Si queremos poner el color de fondo a un control Label, usaremos la propiedad Backcolor. Si el


Label se llama Label1, pondríamos la instrucción

Label1.Backcolor = 12345678

Por la sentencia RGB

Se puede expresar el color, poniendo simplemente RGB (rojo, verde, azul), donde rojo es un
número entre 0 y 255 que indica la cantidad de color rojo que se aporta al color, verde un
número comprendido entre 0 y 255 indicando la cantidad de verde, y lo mismo para azul.
Esta es la forma mas sencilla de poner la propiedad color, y con la que mejor controlaremos el
mismo.

Si queremos poner al Label anterior un color mediante la sentencia RGB, ejecutaríamos la


sentencia :

Label1.Backcolor = RGB (128, 30, 100)

Mediante la Función QBColor (Obsoleta. Se introduce por motivos de compatibilidad)

Esta función se ha puesto en Visual Basic para compatibilidad con los colores que se usan en
Quick-Basic y Qbasic. Mediante esta función se obtienen solamente 16 colores.

Sintaxis Objeto.QBColor(color)

El argumento color es un número entero entre 0 a 15, según la siguiente lista:

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 5


Número Color Número Color

0 Negro 8 Gris
1 Azul 9 Azul claro
2 Verde 10 Verde claro
3 Aguamarina 11 Aguamarina claro
4 Rojo 12 Rojo claro
5 Fucsia 13 Fucsia claro
6 Amarillo 14 Amarillo claro
7 Blanco 15 Blanco brillante

Para el mismo Label anterior, usaríamos la sentencia :

Label1.Backcolor = QBColor (12)

Fin de la nota acerca del número del color

CUADRO DE DIALOGO MOSTRANDO IMPRESORAS

Nota: Si utiliza un CommonDialog para impresoras y otras aplicaciones, puede tener


problemas. Utilice un CommonDialog exclusivamente para impresoras.

Para presentar el cuadro de elección de impresora, ejecute la instrucción:

CD2.ShowPrinter

(A este cuadro de dialogo le hemos llamado CD2 para evitar los problemas referidos en la
nota).

Aparecerá el siguiente cuadro de diálogo:

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 6


La impresora elegida puede conocerla llamando a la propiedad DeviceName de un objeto que
aún no hemos visto: el objeto Printer. Este objeto es el encargado de pasar al Administrador de
Impresión todos los trabajos de impresión que generen las aplicaciones Visual Basic:

Nombredelaimpresora = Printer.DeviceName

Para que la impresora quede como impresora por defecto de Windows, debe tener a True la
propiedad PrinterDefault del cuadro de diálogo.

El cuadro mostrado para la impresora dependerá de la impresora que tenga instalada en su


ordenador, por lo puede observar diferencias respecto a la figura mostrada anteriormente.

Programa Ejemplo. Muestra el cuadro de dialogo de impresoras

Private Sub BImpresora_Click()


CD1.ShowPrinter
End Sub

EL COMMONDIALOG PARA ABRIR Y GUARDAR ARCHIVOS

Posiblemente las opciones mas usadas del cuadro de diálogo. Para presentar el cuadro de
diálogo correspondiente a Abrir Archivo, debe ejecutar la instrucción:

CD1.ShowOpen

Si lo que necesita es abrir el cuadro de diálogo para guardar un fichero, debe ejecutar la
instrucción :
CD1.ShowSave

pero antes deberá introducir el filtro o filtros de archivos que necesite. Ojo, ¡ ANTES !
Un filtro sirve para que en el cuadro de diálogo se presenten solamente los ficheros de nuestro
interés. Se pueden seleccionar por el nombre, la extensión o las dos cosas. La sintaxis para
introducir un filtro es la siguiente:

CD1.Filter = "Descripción del fichero|nombre.extensión"

donde "nombre" puede ser un nombre o usar caracteres comodín. Lo mismo para "extensión"

Por ejemplo, para buscar archivos ejecutables, con cualquier nombre y extensión .EXE

CD1.Filter = "Ficheros ejecutables |*.exe"

Observe el carácter separador entre la descripción de los ficheros (Ficheros ejecutables) y el


parámetro de busca (*.EXE). No ponga ningún espacio entre el separador y los caracteres de
busca. El separador es el carácter ASCII 124.

Puede buscar varios tipos de ficheros, separando los caracteres de busca por medio del
carácter punto y coma (;)

CD1.Filter = "Ficheros ejecutables |*.EXE;*.COM;*.BAT"

Puede también introducir dos filtros, separados por el separador | (En una línea solamente).

CD1.Filter=”Ficheros de un tipo |*.EXE |Ficheros de otro |*.COM |Otros ficheros |*.BAT”

Por ejemplo : CD1.Filter = "Ficheros Word |*.DOC|Ficheros Write |*.WRI"

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 7


¡ No se pueden poner dos líneas con filtros, se quedaría solamente con la última !

En este caso, cuando se presente el cuadro de diálogo, solamente presentará uno de los filtros,
y deberá seleccionar manualmente el otro en un cuadro situado en la parte inferior izquierda del
cuadro de diálogo. Para predeterminar cuál de los dos filtros saldrá sin tener que seleccionarlo,
deberá ejecutar esta instrucción, ANTES de invocar el cuadro de diálogo

CD1.FilterIndex = 2

En este caso, aparecerá por defecto el filtro escrito en segundo lugar. El orden de los filtros
comienza por 1.

El cuadro de diálogo deberá presentar un directorio. Este directorio con el que, por defecto,
aparece el cuadro de diálogo, se puede introducir mediante la propiedad InitDir, que deberá
contener el nombre del directorio y su path. Si no se especifica, comenzará por el directorio
actual.

Para conocer el nombre del fichero elegido, se emplea la propiedad FileName :

Nombrefichero= CD1.filename

El nombre del fichero, Nombrefichero en la sentencia anterior, viene con su path, es decir,
nombre y dirección completa, por lo que puede emplearse directamente la salida del
CommonDialog para abrir un fichero.

El cuadro de diálogo de abrir o cerrar tiene esta forma :

El cuadro de guardar es similar. Observe que en este caso hemos desplegado la segunda
opción de filtro de ficheros :

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 8


Como ve ambos cuadros son prácticamente iguales. Solamente se difieren en que uno pone
Abrir y el otro Guardar como en su barra de título. También en que el cuadro Guardar como
presenta los nombres de los ficheros con un tono apagado. Funcionalmente difieren. Por
ejemplo, si quiere guardar un fichero con un nombre ya existente, y dependiendo de la
propiedad Flags que verá mas adelante, le aparecerá la siguiente advertencia :

Si desea otra leyenda en la barra de título, puede cambiarla usando el asistente de


propiedades, que lo obtendrá colocando el cursor del ratón sobre el icono del CommonDialog y
pulsando el botón derecho. Haga click sobre Propiedades en el popmenú que se presenta.
Aparecerá esto :

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 9


PRESENTAR AYUDAS

Mediante el CommonDialog se puede presentar un fichero de ayuda. (Ficheros del tipo .HLP
de Windows)

Pese a que se pueden presentar estos ficheros basándonos en el CommonDialog, es


preferible usar directamente el programa WinHelp.Exe, que puede ejecutarlo mediante la
función Shell :

VariableID = Shell (“WinHelp.Exe FicheroAyuda.hlp”,1)

Para mostrar el fichero de ayuda debe poner el nombre (y Path) del fichero de ayuda en la
propiedad HelpFile del CommonDialog

CD1.HelpFile = "C:\MiCarpeta\MiFicheroAyuda.HLP"

Puede mostrar el índice, o una página concreta de ese fichero. Para ello debe jugar con la
propiedad HelpCommand, que le va a indicar al CommonDialog qué ayuda debe mostrar.

CD1.HelpCommand =Valor

Las opciones para valor son:

1 &H1 cdlContext
Muestra la Ayuda de un contexto determinado. Cuando se usa esta valor, también se
debe especificar un contexto con la propiedad HelpContext.
2 &H2 cdlQuit
Notifica a la aplicación Ayuda que el archivo de Ayuda especificado ya no se está
utilizando.
3 &H3 cdlContents
Muestra el tema de contenido de ayuda, definido con la opción Contents de la sección
[OPTION] del archivo .HPJ.
3 &H3 cdlIndex
Muestra el índice del archivo de Ayuda especificado. Las aplicaciones sólo deben
utilizar este valor para un archivo de Ayuda con índice único.
4 &H4 cdlHelpOnHelp
Muestra la Ayuda para utilizar la propia aplicación Ayuda.
5 &H5 cdlSetContents

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 10


Determina el tema de contenido a mostrar cuando el usuario presiona la tecla F1.
5 &H5 cdlSetIndex
Establece el contexto especificado en la propiedad HelpContext como índice actual
para el archivo especificado en la propiedad HelpFile. Este índice seguirá siendo el
actual hasta que el usuario acceda a un archivo de Ayuda distinto. Utilice este valor sólo
para los archivos de Ayuda con más de un índice.
8 &H8 cdlContextPopup
Muestra en una ventana emergente un tema de Ayuda determinado, identificado por un
número de contexto definido en la sección [MAP] del archivo .HPJ.
9 &H9 cdlForceFile
Asegura que WinHelp muestre el archivo de Ayuda correcto. Si se muestra el archivo
correcto, no sucede nada. Si se muestra un archivo incorrecto, WinHelp abrirá el
correcto.
257 &H101 cdlKey
Muestra la Ayuda sobre una palabra reservada determinada. Al usar esta opción,
deberá especificar también una palabra reservada con la propiedad HelpKey.
258 &H102 cdlCommand
Ejecuta una macro de Ayuda.
261 &H105 cdlPartialKey
Muestra el tema de la lista de palabras claves que coincide con la palabra pasada en el
parámetro dwData, si sólo se encuentra uno. Si se encuentra más de uno, aparecerá el
cuadro de diálogo Buscar mostrando los temas encontrados en el cuadro de lista Ir a. Si
no se encuentra ninguno, se mostrará el cuadro de diálogo Buscar. Para que aparezca
el cuadro de diálogo Buscar sin pasar una palabra reservada, utilice un puntero largo a
una cadena vacía.

Si queremos que se muestre el índice de la ayuda, pondríamos esta propiedad de la forma :

CD1.HelpCommand = cdlHelpIndex

Para mostrar la página que se ha puesto en el fichero de ayuda como Contexto 2 (En Sección
[MAP] del fichero .HPJ (Vea Creación de Ficheros de Ayuda),

CD1.HelpCommand = cdlHelpContext
CD1.HelpContext = 2

Para mostrar la Ayuda de la Ayuda de Windows :

CD1.HelpCommand = cdlHelpHelpOnHelp

Una vez establecidas estas propiedades, mostraremos la ayuda con el Método ShowHelp

CD1.ShowHelp

Repitiéndole que no se debe usar el CommonDialog para mostrar ayudas, pero para cumplir el
objetivo de plasmar en este texto la mayor información acerca de cada control, se enumeran a
continuación el resto de propiedades que afectan a la presentación de ayuda :

HelpFile
HelpContext
HelpKey

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 11


PROPIEDADES DEL CommonDialog

La Propiedad Action

La propiedad Action se incluye en la versión 4 de VB solamente por motivos de compatibilidad


con anteriores versiones. Realiza las mismas funciones que ShowFont, ShowColor,
ShowPrinter, ShowOpen y ShowSave. No debe usarse esta propiedad, sino los equivalentes
citados, en previsión de que pueda ser eliminada en futuras versiones.

La sintaxis de Action es : Nombre.Action [= valor]

Valor Descripción

0 Ninguna acción.
1 Muestra el cuadro de diálogo Abrir.
2 Muestra el cuadro de diálogo Guardar como.
3 Muestra el cuadro de diálogo Color.
4 Muestra el cuadro de diálogo Fuente.
5 Muestra el cuadro de diálogo Impresora.
6 Ejecuta WINHELP.EXE.

NO utilice la propiedad Action. Utilice en su lugar ShowFont, ShowPrinter, ShowSave,


ShowOpen , ShowColor y ShowHelp

CancelError

Devuelve o establece un valor que indica si se genera un error cuando el usuario elige
el botón Cancelar.

Sintaxis : objeto.CancelError = (True / False)

True Se genera un error.


False (Predeterminado) No se genera ningún error.

Cuando se establece True en esta propiedad, se producirá el error número 32755


(cdlCancel) cada vez que el usuario elija el botón Cancelar.

Debe poner esta propiedad a true cuando quiera detectar que se ha pulsado el botón
CANCELAR. Luego, debe detectar con la rutina de detección de errores adecuada, si el
error producido ha sido el 32755. De ser así, es que han pulsado ese botón, y Vd.
procederá en consecuencia.

Color
Esta propiedad es de lectura / escritura
De escritura :Establece el color predeterminado con que aparecerá el CD para elegir
color. Puede introducirse como RGB o numéricamente, como se explicó mas atrás.
Para que aparezca este color predeterminado, debe poner la propiedad Flags a 1.
De lectura : Entrega el color elegido, bien en el cuadro de elección de color, bien en el
cuadro de elección de fuente.

Copies
Establece el valor predeterminado para número de copias que aparecerá en el CD
cuando se abra para elegir impresora.

DefaultExt
Devuelve o establece la extensión de archivo predeterminada para el cuadro de diálogo.

Sintaxis objeto.DefaultExt [= cadena]

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 12


Puede utilizar esta propiedad para especificar una extensión de archivo
predeterminada, como por ejemplo .TXT o .DOC.
Importante para el CommonDialog de Guardar: Cuando se guarde un archivo sin
extensión, se le agregará automáticamente la especificada en esta propiedad.

DialogTitle
Devuelve o establece la cadena mostrada en la barra de título del cuadro de diálogo.

Sintaxis Nombre.DialogTitle [= título]

Esta propiedad puede introducirse en la ventana de propiedades, o por programa.


Puede utilizar esa propiedad para mostrar el nombre del cuadro de diálogo en la barra
de título.

Nota El control CommonDialog ignora el valor de la propiedad DialogTitle cuando


muestra los cuadros de diálogo Color o Fuente.

El título predeterminado para un cuadro de diálogo Abrir es Abrir, y para un cuadro de


diálogo Guardar como es Guardar como.

FileName
Devuelve o establece la ruta y el nombre de archivo de un archivo seleccionado. La
lectura de esta propiedad devuelve el nombre del archivo seleccionado actualmente en
la lista. Si no hay ningún archivo seleccionado, FileName devuelve una cadena vacía.

Filter
(Explicada mas atrás)

Devuelve o establece los filtros que aparecen en el cuadro de lista Tipo de un cuadro de
diálogo.

Sintaxis CD1.Filter [= descripción1 |filtro1 |descripción2 |filtro2...]

Utilice el símbolo de canalización ( | , (ASCII 124) ) para separar los valores de


descripción y de filtro. No incluya espacios antes ni después del símbolo de
canalización, pues aparecerían en los valores de descripción y valor.

Al especificar más de un filtro en un cuadro de diálogo, utilice la propiedad FilterIndex


para especificar el filtro predeterminado.

Nota para los que no tiene teclado de 102 teclas. Para obtener el carácter ASCII 124, pulse la
tecla ALT y, sin dejar de pulsarla, teclee 124 en el teclado numérico.

FilterIndex
Devuelve o establece un filtro predeterminado para un cuadro de diálogo Abrir o
Guardar Como.

Sintaxis CD1.FilterIndex [= número]

Esta propiedad indica el filtro predeterminado cuando se han especificado varios filtros
para un cuadro de diálogo Abrir o Guardar. El índice del primer filtro definido es 1.

Flags Propiedad que tiene distintos significados para cada tipo de cuadro de diálogo.
Tiene la misma sintaxis para todos los cuadros.

Sintaxis CD1.Flags [= valor]

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 13


El parámetro valor establece distintas alternativas, dependiendo de cada cuadro.

Para el cuadro de diálogo Color

Las opciones para valor son:

1 &H1& cdlRGBInit
Establece como valor de color inicial para el cuadro de diálogo el indicado en su
propiedad Color.

2 &H2& cdlFullOpen
Hace que el cuadro de diálogo se muestre completo al crearlo, incluyendo la sección
que permite al usuario crear colores personalizados. Sin esta opción, el usuario debe
elegir el botón de comando Definir colores personalizados para mostrar tal sección.

4 &H4& cdlPreventFullOpen
Desactiva el botón de comando Definir colores personalizados, evitando que el
usuario defina colores.

8 &H8& cdlShowHelp
Hace que el cuadro de diálogo muestre un botón Ayuda.

Se pueden poner varias de estas condiciones, poniendo como valor Flags la suma de los
valores de cada una de las condiciones a poner.

Para los cuadros Abrir y Guardar

Las opciones para valor son:

1 &H1& cdlReadOnly
Hace que la casilla de verificación Sólo lectura aparezca marcada inicialmente al crear
el cuadro de diálogo. Este indicador también señala el estado de la casilla Sólo lectura
cuando el cuadro de diálogo está cerrado.
2 &H2& cdlOverwritePrompt
Hace que el cuadro de diálogo Guardar como genere un cuadro de mensaje si el
archivo seleccionado ya existe. El usuario deberá confirmar que desea sobrescribir el
archivo.
4 &H4& cdlHideReadOnly
Oculta la casilla de verificación Sólo lectura.
8 &H8& cdlNoChangeDir
Hace que el cuadro de diálogo restablezca como directorio actual el que lo era en el
momento de abrirse.
16 &H10& cdlShowHelp
Hace que el cuadro de diálogo muestre el botón Ayuda.
256 &H100& cdlNoValidate
Especifica que el cuadro de diálogo común permita caracteres no válidos en el nombre
de archivo devuelto. Funciona tanto con el cuadro de Abrir como con el de Cerrar.
Tenga cuidado a la hora de crear un archivo con nombre no válido !
512 &H200& cdlAllowMultiselect
Especifica que el cuadro de lista Nombre de archivo admita selecciones múltiples. El
usuario puede seleccionar más de un archivo en tiempo de ejecución presionando la
tecla MAYÚS y utilizando las teclas FLECHA ARRIBA y FLECHA ABAJO para
seleccionar los archivos deseados. Al hacerlo, la propiedad FileName devolverá una
cadena con los nombres de todos los archivos seleccionados. Los nombres están
delimitados en la cadena con espacios.
1024 &H400& cdlExtensionDifferent

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 14


Indica que la extensión del nombre de archivo devuelto es distinta de la especificada en
la propiedad DefaultExt. Este indicador no estará activado si la propiedad DefaultExt
es Null, si las extensiones coinciden, o si el archivo no tiene extensión. El valor de este
indicador puede comprobarse al cerrar el cuadro de diálogo.
2048 &H800& cdlPathMustExist
Especifica que el usuario sólo pueda introducir una ruta de acceso válida. Si se
establece este indicador y el usuario introduce una ruta no válida, aparecerá un
mensaje de advertencia.
4096 &H1000& cdlFileMustExist
Especifica, para el cuadro de Abrir, que el usuario sólo pueda escribir en el cuadro de
texto Nombre de archivo nombres de archivos existentes. Si este indicador está
activado y el usuario introduce un nombre de archivo no válido, aparecerá una
advertencia. Este indicador activa automáticamente cdlPathMustExist.
8192 &H2000& cdlCreatePrompt
Especifica, para el cuadro de diálogo de abrir, que si no existe el fichero consulte al
usuario antes de crear un archivo que no existe actualmente. Esta advertencia dice :
Este Archivo no existe ¿desea crearlo ? y aparecen los botones de ACEPTAR y
CANCELAR. Si el usuario pulsa aceptar el CommonDialog se cierra normalmente, si
se le pulsa CANCELAR desaparece esta advertencia y el CommonDialog espera a
que se le escriba o seleccione otro fichero. Este indicador establece automáticamente
los indicadores cdlPathMustExist y cdlFileMustExist.
16384 &H4000& cdlShareAware
Especifica que se ignoren los errores al compartir archivos.

32768 &H8000& cdlNoReadOnlyReturn


Especifica que el archivo devuelto no tenga el atributo de Sólo lectura ni esté en un
directorio protegido contra escritura. Presenta un aviso (tanto en el cuadro de abrir
como en el cerrar) que impide elegir un fichero de estas características.

Se pueden poner varias de estas condiciones, poniendo como valor Flags la suma de los
valores de cada una de las condiciones a poner.

Para el cuadro Mostrar Fuentes:

Las opciones para valor son:

1 &H1& cdlScreenFonts
Hace que el cuadro de diálogo muestre solamente las fuentes de pantalla que admite el
sistema.
2 &H2& cdlPrinterFonts
Hace que el cuadro de diálogo muestre solamente las fuentes que admite la impresora,
especificadas por la propiedad hDC.

3 &H3& cdlBoth
Hace que el cuadro de diálogo muestre las fuentes de impresora y de pantalla
disponibles. La propiedad hDC identifica el contexto de dispositivo asociado a la
impresora
4 &H4& cdlShowHelp
Hace que el cuadro de diálogo muestre un botón Ayuda.
256 &H100& cdlEffects
Especifica que el cuadro de diálogo permita efectos de tachado, subrayado y color.
1024 &H400& cdlANSIOnly
Especifica que el cuadro de diálogo sólo permita seleccionar las fuentes que utilizan el
juego de caracteres de Windows. Si se establece este indicador, el usuario no podrá
seleccionar una fuente que sólo contenga símbolos.
2048 &H800& cdlNoVectorFonts
Especifica que el cuadro de diálogo no permita seleccionar fuentes vectoriales.

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 15


4096 &H1000& cdlNoSimulations
Especifica que el cuadro de diálogo no permita simulaciones de fuente de interfaz de
dispositivo gráfico (GDI).

8192 &H2000& cdlLimitSize


Especifica que el cuadro de diálogo seleccione sólo los tamaños de fuente
comprendidos en el rango especificado por las propiedades Min y Max.

16384 &H4000& cdlFixedPitchOnly


Especifica que el cuadro de diálogo seleccione sólo fuentes de espaciado fijo.
32768 &H8000& cdlWYSIWYG
Especifica que el cuadro de diálogo permita seleccionar solamente fuentes disponibles
al la vez en la pantalla y en la impresora. Si se establece este indicador, también deben
establecerse cdlBoth (sume 3 a este número) y cdlScalableOnly (sume 131072 a este
número)

65536 &H10000& cdlForceFontExist


Especifica que aparezca un cuadro de mensaje cuando el usuario intente seleccionar
una fuente o un estilo que no existan.
131072 &H20000& cdlScalableOnly
Especifica que el cuadro de diálogo permita seleccionar solamente fuentes escalables.

262144 &H40000& cdlTTOnly


Especifica que el cuadro de diálogo permita seleccionar solamente fuentes TrueType.

Nota Antes de mostrar el cuadro de diálogo Fuentes, debe establecer cdlScreenFonts,


cdlPrinterFonts o cdlBoth en la propiedad Flags. En caso contrario, se producirá el error No hay
fuentes. (O dicho de otra forma, Flags=1, 2 ó 3)

Se pueden poner varias de estas condiciones, poniendo como valor Flags la suma de los
valores de cada una de las condiciones a poner.

Para el Cuadro de Diálogo Imprimir

(Observará seguramente que lo que se describe a continuación no se cumple siempre.


Depende de las impresoras que tenga Vd. instaladas)

Las opciones para valor son:

0 &H0& cdlAllPages
Devuelve o establece el estado del botón de opción Todas las páginas.
1 &H1& cdlSelection
Devuelve o establece el estado del botón de opción Selección. Si no se
especifica cdlPageNums ni cdlSelection, el botón de opción Todas estará
seleccionado.
2 &H2& cdlPageNums
Devuelve o establece el estado del botón de opción Páginas.
4 &H4& cdlNoSelection
Desactiva el botón de opción Selección.
8 &H8& cdlNoPageNums
Desactiva el botón de opción Páginas y el control de edición asociado.
16 &H10& cdlCollate
Devuelve o establece el estado de la casilla de verificación Intercalar.
32 &H20& cdlPrintToFile
Devuelve o establece el estado de la casilla de verificación Imprimir a un
archivo.

64 &H40& cdlPrintSetup

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 16


Hace que el sistema muestre el cuadro de diálogo Configurar impresora en
lugar de Imprimir. Use este Flag cuando lo que desea es cambiar la impresora
predeterminada.
128 &H80& cdlNoWarning
Evita que aparezca una advertencia cuando no hay una impresora
predeterminada.

256 &H100& cdlReturnDC


Devuelve un contexto de dispositivo para la impresora seleccionada en el
cuadro de diálogo. El contexto se devuelve en la propiedad hDC del cuadro de
diálogo.
512 &H200& cdlReturnIC
Devuelve un contexto de información para la impresora seleccionada en el
cuadro de diálogo. Un contexto de información proporciona un método rápido
de obtener información sobre el dispositivo sin crear un contexto de dispositivo.
El contexto de información se devuelve en la propiedad hDC del cuadro de
diálogo.
2048 &H800& cdlShowHelp
Hace que el cuadro de diálogo muestre el botón Ayuda
262144 &H40000& cdlUseDevModeCopies
Si un controlador de impresora no admite copias múltiples, al establecer este
indicador se desactiva el control de edición de número de copias. Si el
controlador sí admite múltiples copias, al establecer este indicador el cuadro de
diálogo almacenará el número de copias solicitado en la propiedad Copies.

524288 &H80000& cdlDisablePrintToFile


Desactiva la casilla de verificación Imprimir a un archivo.
1048576 &H100000& cdlHidePrintToFile
Oculta la casilla de verificación Imprimir a un archivo.

Propiedades que afectan al tipo de letra.

Las seis propiedades siguientes nos dan las características especiales de la fuente elegida
(negrita, cursiva, etc.). Una vez seleccionado el tipo de letra, el valor de estas propiedades
contiene la opción elegida para la letra (si FontBold=True es que hemos elegido negrita, etc.)

FontBold
Propiedad Booleana que establece o devuelve que el tipo de letra usado es Negrita.

Sintaxis Variable = CD1.FontBold

Los valores de Variable son:

True Se ha elegido negrita False (Predeterminado) No se ha elegido negrita.

FontItalic
Propiedad Booleana que establece o devuelve que el tipo de letra usado es Cursiva.

Sintaxis Variable = CD1. FontItalic

Los valores de Variable son:

True si se ha elegido cursiva, False (Predeterminado) en caso contrario.

FontStrikethru

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 17


Propiedad Booleana que establece o devuelve que el tipo de letra usado es Tachada.

Sintaxis Variable = CD1. FontStrikethru

Los valores de Variable son:

True si se ha elegido tachado, False (Predeterminado) en caso contrario.

FontUnderline
Propiedad Booleana que establece o devuelve que el tipo de letra usado es Subrayado.

Sintaxis Variable = CD1.FontUnderline

Los valores de Variable son:

True, si se ha elegido subrayado, False (Predeterminado) en caso contrario

FontName

Devuelve el nombre de la fuente elegida. Es una variable tipo String

Sintaxis Variable = CD1.FontName

(Variable toma el valor del nombre de la fuente. Por ejemplo, Variable = “Arial”

En general, deberá modificar FontName antes de establecer los atributos de tamaño y


estilo con las propiedades FontSize, FontBold, FontItalic, FontStrikethru y
FontUnderline.

Nota En tiempo de ejecución puede obtener información sobre las fuentes disponibles
a través de las propiedades FontCount y Fonts. Lo verá mas adelante

FontSize

Devuelve de la fuente elegida. Debe ser una variable tipo Integer o Long

Sintaxis Variable = CD1.FontSize

donde Variable será una expresión numérica que especifica el tamaño de fuente a
utilizar, en puntos.

Nota Las fuentes disponibles en Visual Basic varían dependiendo de la configuración


del sistema y de los dispositivos de presentación e impresión. En las propiedades
relacionadas con las fuentes sólo pueden establecerse valores para los que exista una
fuente.

En general, deberá modificar FontName antes de establecer los atributos de tamaño y


estilo con las propiedades FontSize, FontBold, FontItalic, FontStrikethru y
FontUnderline. Sin embargo, cuando especifique un tamaño inferior a 8 puntos para
una fuente TrueType, primero deberá establecer el tamaño en puntos con la propiedad
FontSize, luego especificar la propiedad FontName y después establecer de nuevo el
tamaño con FontSize. El entorno operativo Microsoft Windows utiliza una fuente
distinta para las fuentes TrueType con un tamaño inferior a 8 puntos.

Index

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 18


Igual que el ya estudiado para otros controles.

InitDir
Devuelve o establece el directorio de archivos inicial.

Sintaxis objeto.InitDir [= cadena]

La sintaxis de la propiedad InitDir consta de las siguientes partes:

objeto Nombre que define al CommonDialog


cadena Expresión de cadena que especifica el directorio de archivos inicial.

Si no se especifica esta propiedad, se utilizará el directorio actual.

Left y Top

Estas propiedades solamente afectan a la colocación del icono en el formulario. No


afectan a la colocación del CommonDialog durante la ejecución. La posición del
CommonDialog en tiempo de ejecución no puede controlarse.

Esta afirmación de que la posición del CommonDialog no es controlable es válida para


sistemas a 32 bytes. En VB 4 de 16 bits, el CommonDialog aparece aproximadamente
en la parte superior izquierda del formulario que lo contiene. Algunos programadores
han optado por poner un formulario para contener solamente al CommonDialog, y así,
controlando la posición de ese formulario, poder controlar la posición (aproximada) en
la que aparece el CD.

Esto no ocurre para sistemas a 32 bytes, en los que el CD aparece siempre en la parte
superior izquierda de la pantalla, independientemente de donde esté el formulario que
lo contiene.

MaxFileSize

Devuelve o establece el tamaño máximo del nombre de archivo abierto con el control
CommonDialog.

Sintaxis objeto.MaxFileSize [= valor]

La sintaxis de la propiedad MaxFileSize consta de las siguientes partes:

objeto = Nombre que define al CommonDialog


valor = Número entero que especifica el tamaño máximo del nombre de archivo en
bytes. El rango de esta propiedad es 132KB. El valor predeterminado es 256.

Name
Nombre que define al CommonDialog

PrinterDefault

Devuelve o establece una opción que determina si la configuración elegida por el


usuario en el cuadro de diálogo Imprimir se utiliza para modificar la configuración
predeterminada de impresora del sistema.

Sintaxis CD1.PrinterDefault = True / False

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 19


True Las opciones que elija el usuario en el apartado Configurar del cuadro de
diálogo Imprimir (selección de la impresora, orientación, etcétera) se utilizan para
modificar la configuración de impresora almacenada en el Registro).
False Las opciones que elija el usuario no se utilizan para modificar la configuración
de impresora predeterminada del sistema.

Utilice esta propiedad, que por defecto está a True, para poner o no poner como
impresora predeterminada, la impresora seleccionada con el CommonDialog. Puede
por ejemplo, querer imprimir un texto en una impresora determinada, pero solo ese
texto, y no quiere cambiar la impresora predeterminada por el hecho de haber
seleccionado en este momento otra impresora. Ponga esta propiedad a False (recuerde
que por defecto está a True) para que la impresora seleccionada no se quede como
impresora por defecto.
Tag

Lo mismo que se ha explicado para otros controles.

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 20


CONTROLES DE BUSQUEDA DE FICHEROS

CONTROLES DE BUSQUEDA DE FICHEROS Y DIRECTORIOS

Estos controles apenas si se usan. La razón es que el CommonDialog ya estudiado sustituye


con creces a estos tres controles en su conjunto. Sin embargo, para determinadas
necesidades sí son muy prácticos. Estúdieselos con el mismo entusiasmo que si no existiese el
CommonDialog.

Al tratarse de controles tipo Lista, le recomiendo que lea el capítulo correspondiente al ListBox.
Le aclarará sobre todo los términos empleados para definir los elementos de la lista, que en
este caso, son los ficheros de una carpeta, las carpetas de un disco o los discos visibles desde
la máquina.

· DriveListBox, DirListBox Y FileListBox.

Se obtienen directamente de la Caja de Herramientas, en los iconos siguientes:

· DriveListBox permite elegir una unidad de disco.


· DirListBox muestra los directorios existentes en un árbol.
· FileListBox muestra los ficheros existentes en un determinado directorio.

Tal como indica su nombre, estos controles son listas. Repase el control ListBox para recordar
sus propiedades.

DriveListBox

Este control permite elegir una unidad de disco válida en tiempo de ejecución. Utilice este
control para mostrar una lista de todas las unidades válidas del sistema de un usuario. Puede
crear cuadros de diálogo que permitan al usuario abrir un archivo de una lista en cualquier
unidad disponible.

DriveListBox desplegado y sin desplegar Name (nombre) por defecto List1

Posee las propiedades típicas de cualquier control VB respecto a su geometría y color. Las
propiedades mas destacables de este control son : Drive, List, ListCount y ListIndex

Drive devuelve el nombre de la unidad de disco seleccionada :

Variable = List1.Drive Variable = a : (ó c :[MS-DOS_6] ó D )

Este control se trata de una lista como su nombre indica, y posee las propiedades List,
ListCount y ListIndex para permitir al usuario tener acceso a elementos de la lista.

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 21


List (n) devuelve el texto que define a la unidad colocada en el lugar n. El número n comienza
por 0. Por ejemplo, en la figura anterior, List1.list(1) devolverá c :[MS-DOS_6]

ListCount proporciona información acerca del número de unidades de disco disponibles (En el
ejemplo, List1.ListCount será 3, que corresponde a los tres discos disponibles - disco C :, disco
A : y disco D : )

ListIndex devuelve el índice del disco seleccionado en la lista (0 para el primero, n-1 para el
último)

Utilizando el control DriveListBox en combinación con DirListBox y FileListBox, podrá


realizar un explorador de ficheros en cualquier disco de su ordenador.

DirListBox.

Presenta un cuadro de la siguiente forma:

donde puede verse el árbol completo de un directorio. El DirListBox solamente presenta


directorios. No presenta ficheros.

Aparte de las propiedades geométricas de todos los controles, el DirListBox presentas las
siguientes propiedades particulares :

Path
Devuelve o establece la ruta de acceso actual. No está disponible en tiempo de diseño.

Sintaxis Nombre.Path [= pathname]

donde

Nombre es el nombre del DirListBox


pathname Una expresión de cadena que evalúa en el nombre de vía de acceso del directorio
por defecto del DirListBox..

El valor de la propiedad Path es una cadena que indica una ruta de acceso, como
C:\WINDOWS\SYSTEM. El valor predeterminado es la ruta de acceso actual

Cuando se cambia la propiedad Path en tiempo de ejecución se genera un evento Change.

Nota El valor que devuelve Path es distinto del de List (ListIndex). Path devuelve siempre un
mismo camino, bien el que se le haya impuesto mediante esta misma propiedad Path, y si no
se le ha impuesto con anterioridad, el que tenga por defecto. List (ListIndex) devuelve el
camino completo del directorio seleccionado, y, como era de esperar, cambia cada vez que
cambiamos la selección del directorio.

List, ListCount y ListIndex

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 22


Al igual que cualquier lista, el DirListBox tiene las propiedades List, ListCount y ListIndex.

ListIndex devuelve el valor del índice del directorio seleccionado. El valor devuelto es cero
cuando está seleccionado el primer directorio de los situados al final del árbol, 1 para el
siguiente, etc. Toma el valor -1 cuando se selecciona el directorio inmediatamente superior al
último nivel, el valor -2 cuando se selecciona el directorio situado 2 niveles jerárquicos por
encima del último nivel, etc.

ListCount devuelve un valor numérico igual al número de directorios existentes en el último


nivel, independientemente de los directorios que tuviesen por arriba.

List (n) devuelve una cadena de caracteres con el camino completo del elemento cuyo orden
sea el señalado entre paréntesis. Si en vez de n colocamos el ListIndex nos devolverá,
logicamente, el camino del elemento seleccionado.

FileListBox

Esta lista nos presenta los ficheros existentes en un directorio.

Como se puede apreciar, cuando el número de ficheros supera el número que puede presentar,
aparecen automáticamente las flechas de scroll verticales.

Esta lista de ficheros tiene las siguientes propiedades destacables :

Path

Devuelve o establece la ruta de acceso de su directorio actual. No está disponible en tiempo de


diseño. Este directorio puede ser el que se le haya impuesto mediante esta propiedad Path, o el
que tenga por defecto. (El directorio por defecto sería el del ejecutable de la aplicación)

Si le ponemos el nombre por defecto, List1, para todos los ejemplos :

variable = List1.Path Variable = C:\Archivos de programa\Microsoft Visual Basic32 (p.


e.)

ListCount

Devuelve el número total de ficheros que hay en ese directorio.

Variable = List1.ListCountVariable = 19 (p. e.)

ListIndex

Devuelve un número con el índice del elemento seleccionado. Como todas las listas, devuelve -
1 si no hay ningún elemento seleccionado. El primer elemento de una lista tiene el índice = 0.

Filename

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 23


Devuelve el nombre del fichero seleccionado.

List (n)

Devuelve el nombre del fichero que ocupa el lugar n en la lista.

Variable = List1.List (5) Variable = nombre del fichero que ocupa el 5º lugar en la lista.

Si en lugar de n ponemos el valor de ListIndex :

variable = List1.List (List1.ListIndex) obtendremos el nombre del fichero seleccionado.

Observe que en este último caso, el resultado es el mismo que el de List1.Filename

Veamos otras propiedades del FileListBox

Pattern
Devuelve o establece un valor que indica los nombres de archivo mostrados en un
control FileListBox en tiempo de ejecución.

Sintaxis objeto.Pattern [= valor]

La sintaxis de la propiedad Pattern consta de las siguientes partes:

objeto : Nombre del Control FileListBox

valor: Expresión de cadena que indica una especificación de archivo, como *.* o *.FRM. La
cadena predeterminada es *.*, que obtiene una lista de todos los archivos. Además de utilizar
caracteres comodín, también puede especificar varios modelos, separándolos con
caracteres punto y coma (;). Por ejemplo, con *.EXE; *.BAT se obtendría una lista con todos los
archivos ejecutables y todos los archivos por lotes de MS-DOS.

Comentarios

La propiedad Pattern juega un papel clave en el diseño de las funciones de examen y


tratamiento de archivos de una aplicación. Puede utilizar Pattern en combinación con otras
propiedades de control de archivos para proporcionar al usuario formas de explorar archivos o
grupos de archivos similares. Por ejemplo, en una aplicación dedicada a iniciar otros
programas, podría hacer que sólo apareciesen los archivos .EXE en el cuadro de lista de
archivos (*.EXE).
Al modificar el valor de la propiedad Pattern se genera un evento PatternChange.

Archive, Hidden, Normal, System

Devuelven o establecen un valor que determina si un control FileListBox presenta los archivos
con los atributos Archive, Hidden, Normal o System.

El atributo Archive de un fichero indica si se ha variado ese fichero después de la última copia
de seguridad.
El atributo Hidden indica si el fichero se trata de un fichero oculto.
El atributo Normal indica que el fichero es un fichero “normal” (No está oculto ni es de sistema).
El atributo System de un fichero indica que el fichero es un fichero de sistema.

Sintaxis
objeto.Archive [= booleano]
objeto.Hidden [= booleano]
objeto.Normal [= booleano]
objeto.System [= booleano]

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 24


Las sintaxis de la propiedades Archive, Hidden, Normal y System tiene la siguiente partes:
objeto :Nombre del FileListBox
booleano :Una expresión booleana (True / False) que especifica el tipo de archivos
presentados.

El valor booleano puede presentar los siguientes valores :


True :(Predeterminado para Archive y Normal) Presenta archivos con el atributo de la propiedad
en el control FileListBox.
False : (Predeterminado para Hidden y System) Presenta archivos sin el atributo de la
propiedad en el control FileListBox.

Use estas propiedades para especificar el tipo de archivos a presentar en un control


FileListBox, basándose en los atributos de archivos estándar usados en el entorno operativo. La
definición de estas propiedades en el código en tiempo de ejecución hace que el control
FileListBox presente sólo aquellos archivos con los atributos especificados.
Por ejemplo, en una operación de buscar y reemplazar se podrían presentar solamente
archivos del sistema estableciendo la propiedad System a True y las demás propiedades a
False. También, como parte del procedimiento de copia de seguridad, se podría establecer la
propiedad Archive a True para relacionar solamente aquellos archivos modificados a partir de la
última copia de seguridad.

PROCEDIMIENTOS del FileListBox

Click Change DragDrop DragOver GotFocus


KeyDown KeyPress KeyUp

SENTENCIAS DE MANEJO DE DIRECTORIOS Y FICHEROS

El Directorio Actual

Se llama directorio Actual al directorio que está actualmente en uso, bien porque haya sido
forzado el control correspondiente a tener ese directorio en su propiedad Path, bien porque, al
no haberse forzado ninguno, utilice el directorio por defecto.

El directorio por defecto es el último que se ha seleccionado por algún procedimiento. Por
ejemplo, al arrancar una aplicación, el directorio por defecto será el mismo donde se encuentra
el ejecutable. Pero si a lo largo de la aplicación cambiamos el directorio, seleccionando otro
mediante un CommonDialog, ese directorio es el que queda por defecto. Asegúrese en sus
aplicaciones que siempre elige la propiedad Path antes de presentar ficheros o directorios a
través de los controles anteriores, para evitar que pueda mostrarle ficheros de un directorio no
deseado.

Puede comprobar cual es el directorio actual. La función CurDir nos devuelve el directorio
actual.

Ejemplo : Introduzca una línea de código con la siguiente sentencia

Variable = CurDir Al ejecutarla la variable Variable contendrá la información :

Variable = C:\Archivos de programa\Microsoft Visual Basic32 (p. e.)

Puede darse el caso de que desee conocer el directorio actual de varias unidades de disco. Por
ejemplo, puede estar trabajando en el directorio C:\CursoVB\Ejemplos y ser este el directorio
actual en el disco C :, y tener un disquete en la unidad A : en el que la última vez que trabajó fue
en el directorio A :\ApVB\Tema1 y ese es su directorio por defecto en el disco A. Para conocer
el directorio actual del disco C : no necesitó especificar la unidad, ya que era precisamente la

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 25


unidad C la unidad actual. Para conocer el directorio actual de la unidad A emplearía la
expresión :

Variable = CurDir (“A”) Variable tomará entonces el valor Variable = “A :\ApVB\Tema1”

Decíamos que el disco C era la unidad actual. También podemos cambiar la unidad actual,
mediante la sentencia ChDrive seguida de una letra (entre comillas dobles)

Ejemplo ChDrive “A” cambia la unidad actual a la unidad A. Observe que el


parámetro A no tiene que llevar los dos puntos ( : ), aunque si
lo desea, puede ponerlos. También es indiferente que la letra
sea mayúscula o minúscula.

También podemos forzar a que un directorio sea el directorio por defecto. La sentencia que
tendremos que usar en ChDir.

Ejemplo : ChDir “C :\Windows\System” cambiaría el directorio actual al especificado.

Podemos incluso crear un directorio. Usaremos para ello la sentencia MkDir. Esta sentencia
crea el directorio con el nombre indicado, sobre el directorio actual.

Si el directorio actual es el C:\VB\Icons y ejecutamos la sentencia :

MkDir “Varios” crearíamos el directorio C:\VB\Icons\Varios

Podemos incluso eliminar un directorio. La sentencia para eliminar un directorio es RmDir

¡ Cuidado ! Visual-Basic no le advertirá que puede borrar algo que no desea. Asegúrese muy
bien mediante un aviso al usuario cada vez que elimine un directorio.

Vamos a ver ahora como podemos ver los nombres de los ficheros existentes en un
determinado directorio. Muy sencillo, con un FileListBox. Efectivamente, así podría ser para
presentarlos en pantalla. Sin embargo, si deseamos imprimir la lista de ficheros existentes,
guardarla en un fichero, etc., tenemos una forma que facilita esta labor. Igual que en DOS. La
función Dir

A esta función le debemos añadir como parámetro el criterio de búsqueda, criterio formado por
los caracteres o comodines que deseemos. Dir devuelve solamente el nombre de un fichero,
por lo que tendremos que repetirla tantas veces como ficheros tenga el directorio. Pero
solamente tendremos que introducir el criterio de búsqueda la primera vez.

En el siguiente ejemplo, sacaremos por impresora los nombres de los ficheros existentes en el
directorio actual : (Este código lo meteremos en el procedimiento click de un botón de
comando)

fichero = Dir("*.*") ‘Le decimos que imprima todos (*.*)


Do Until fichero = "" ‘Hasta que fichero sea una cadena de longitud cero..
Printer.Print fichero ‘Imprime la variable fichero en la impresora
fichero = Dir ‘Toma el nombre de otro fichero
Loop ‘Vuelve a Do Until .....

Printer.EndDoc ‘Termina la impresión y saca la hoja de la impresora

Ya sabemos sacar el directorio. Vamos a ver que otras cosas se pueden hacer con ficheros.

Función Kill. A poco Inglés que sepa se habrá dado cuenta que esta función sirve para quitarse
algo de enmedio. Esta función borra un fichero del disco.

Kill “C:\CursoVB\Ejemplos\Ejemplo1.txt”

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 26


borra el fichero Ejemplo1.txt, que se encuentra en el disco C, directorio \ CursoVB\Ejemplos

Función FileCopy. Copia un fichero. La sintaxis de esta función es la siguiente :

FileCopy Origen, Destino

Si tenemos un TextBox llamado Text1 donde vamos a introducir el nombre (con su Path) del
fichero origen, otro TextBox donde introduciremos el nombre (con su Path) que queremos dar a
la copia, para copiar ese fichero ejecutaremos la sentencia :

FileCopy Text1.Text, Text2.Text

Si queremos copiar un fichero del disco A, en el directorio CursoVB y de nombre Ejemplo1 al


disco y directorio C:\CursoVB\Ejemplos y con el mismo nombre que tenía en el disco A, es
decir, Ejemplo1, ejecutaremos la sentencia :

FileCopy “A :\CursoVB\Ejemplo1” , “C:\CursoVB\Ejemplos\Ejemplo1”

Observe la necesidad de dobles comillas para especificar que es, precisamente lo escrito en el
código, lo que indica el origen y el destino. En el caso anterior no llevaba dobles comillas,
debido a que era el contenido de un TextBox lo que se usaba para indicar el origen y el destino.

La instrucción Name cambia el nombre de un fichero. No solamente puede cambiar un nombre,


puede incluso moverlo de sitio, pero siempre en la misma unidad de disco.

La sintaxis de Name es la siguiente :

Name nombrerutaantiguo As nombrerutanuevo

Donde nombrerutaantiguo es una expresión de cadena que indica el nombre del fichero (con
su path) al que se le quiere cambiar el nombre, y nombrerutanuevo es una expresión de
cadena que especifica el nombre nuevo y, si se desea mover de directorio, la nueva ubicación
del archivo y la unidad de disco. El nombre y ubicación especificados en nombrerutanuevo no
pueden ser los de un archivo existente.

Tanto nombrerutanuevo como nombrerutaantiguo deben encontrarse en la misma unidad de


disco. Si la ruta de acceso especificada en nombrerutanuevo existe y es distinta de la ruta de
acceso especificada en nombrerutaantiguo, la instrucción Name coloca el archivo en el nuevo
directorio o carpeta y cambia el nombre del archivo, de ser necesario. Si nombrerutanuevo y
nombrerutaantiguo tienen distintas rutas de acceso y el mismo nombre de archivo, Name
coloca el archivo en la nueva ubicación, sin cambiar el nombre del archivo. Por medio de Name
se puede mover un archivo de un directorio o carpeta a otro, pero no se puede mover un
directorio o carpeta.

Si se utiliza Name con un archivo abierto se produce un error. Antes de cambiar el nombre de
un archivo, se debe cerrar.

En el ejemplo, vamos a cambiar el nombre del fichero C:\CursoVB\Ejemplos\Ejemplo1 por el de


C :\CursoVB\Ejemplos\Prueba1

Name “C:\CursoVB\Ejemplos\Ejemplo1” As “C :\CursoVB\Ejemplos\Prueba1”

En el siguiente, aparte de cambiarlo de nombre, le cambiamos de directorio.

Name “C:\CursoVB\Ejemplos\Ejemplo1” As “C :\CursoVB\Ejercic\Prueba1”

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 27


Existe una función que le permite conocer el volumen de un fichero : FileLen. Mediante esta
instrucción podrá saber, por ejemplo, si un fichero le va a caber en lo que le queda libre de un
disquete, el tiempo previsto para enviarlo por módem, etc.

La sintaxis es la siguiente :

Variable = FileLen("C:\CursoVB\Ejemplos\Ejemplo1")

Variable tomará un valor numérico igual al número de bytes del fichero.

Otra función para el tratamiento de ficheros es FileDateTime, que le permite conocer la fecha y
hora de creación o de la última modificación de un fichero.

La sintaxis es, para el caso del ejemplo :

Variable = FileDateTime ("C:\CursoVB\Ejemplos\Ejemplo1")

Variable puede tomar un valor como el siguiente : Variable = 13/02/97 14:59:20

(Observe que de esta función se obtiene una variable de cadena.) Puede aprovechar esta
función para borrar o hacer Backup de determinados ficheros que tengan mas de un tiempo de
permanencia, sustituir ficheros por versiones mas recientes, etc.

Podemos obtener y modificar los atributos de un fichero. Los atributos de un fichero se refieren
a si son de solo lectura, ficheros ocultos, de sistema, si ha sido modificado desde la última vez
que se ha realizado un Backup,

Para conocer los atributos de un fichero, utilizaremos la función GetAttr. Esta función devuelve
un número, que representa la suma de los atributos de un archivo, directorio o carpeta o una
etiqueta de volumen.

Sintaxis Variable = GetAttr (nombreruta)

Donde nombreruta es una expresión de cadena que especifica un nombre de archivo, con su
Path y unidad de disco.

El valor devuelto por GetAttr es un número, igual a la suma de los siguientes valores de
atributos:

Valor Constante Descripción

0 vbNormal Normal.
1 vbReadOnly Sólo lectura.
2 vbHidden Oculto.
4 vbSystem Archivo de sistema.
16 vbDirectory Directorio o carpeta.
32 vbArchive El archivo ha sido modificado después de efectuar la última
copia
de seguridad.

Si la expresión nombreruta representa un directorio, se lo indicará devolviendo el valor 16.

Para cambiar un atributo utilizaremos la función SetAttr. La sintaxis de esta función es la


siguiente

Sintaxis SetAttr nombreruta , atributos

Donde nombreruta es una expresión de cadena que especifica un nombre de archivo, con su
Path y unidad de disco, y atributos es una o varias de las constantes o valores anteriores, cuya
suma especifica los atributos de archivo.

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 28


Dado que el valor 16 indica que lo expresado en nombreruta es un directorio, no puede
pretenderse darle a ese directorio atributos que solamente se pueden aplicar a un fichero, ni
puede pretender darle a un fichero un valor en el que entre el 16 como sumando. Estos casos le
producirán un error en tiempo de ejecución.

Si pretende establecer los atributos de un archivo abierto, se producirá un error en tiempo de


ejecución.

Existe una función, que no tiene nada que ver con la anterior, aunque puede parecerlo por su
parecido semántico y que también devuelve atributos, pero de otro tipo. Esta función es FileAttr

Función FileAttr

Devuelve el modo de apertura de un archivo. Logicamente debe referirse a un archivo abierto


en el momento de ejecutar esta función. Vea para mas detalles la sentencia Open.

Sintaxis variable = FileAttr (numerocanal , tipoinformación)

Donde numerocanal es el número del canal de apertura de ese archivo, y tipoinformación es el


tipo de información que deseamos de ese fichero. Si tipoinformación = 1 nos devuelve el modo
de apertura del fichero, según la siguiente lista

Valor Modo del archivo

1 Entrada
2 Salida
4 Aleatorio
8 Añadir
32 Binario

La Ayuda de VB dice que tipoinformación puede ser =2 para que FileAttr devuelva información
sobre el selector de archivos del sistema operativo. Algunas veces la información de ayuda de
VB promete cosas que, sin dudar de que sean ciertas, son difíciles de comprobar.

Esta función no tiene una gran aplicación práctica, ya que comprueba la forma en la que hemos
abierto un archivo. Información que conocemos desde el mismo momento de abrirlo.

LSB Visual Basic - Guía del Estudiante Capítulo 3 Página 29


Visual Basic - Guía del Estudiante Cap. 4
CONTROLES PARA MOSTRAR IMÁGENES
CREAR CONTROLES EN TIEMPO DE EJECUCIÓN
EL EXAMINADOR DE OBJETOS
_________________________________________________________________
Una imagen representa una figura, bien natural (tipo fotografía) o sintética. Para presentar una
imagen es necesario hacerlo sobre un objeto que la admita. Los objetos que admiten una imagen
son:

· Formularios
· PictureBox
· Image

Existen mas controles gráficos que se irán viendo a lo largo del curso. Estos tres son los mas
usados y con los que comenzaremos a trabajar.

Para mostrar una imagen en cualquiera de estos objetos, es necesario especificarlo en su


propiedad Picture. La forma de especificarle al objeto la imagen que debe presentar puede
hacerse de dos formas:

· En la caja de propiedades, si no se va a variar la imagen durante la aplicación.


· Mediante una instrucción para cambiar esta propiedad. La instrucción es la siguiente:

Nombreobjeto.Picture = LoadPicture (Path, Fichero)

Por ejemplo, si tenemos un formulario llamado Form1 y queremos rellenarlo con una imagen
contenida en el fichero de Windows metafile DOLLAR.WMF que se encuentra en el directorio
C:\VB\METAFILE\BUSINESS, deberemos ejecutar la instrucción:

Form1.Picture = LoadPicture (“C:\VB\METAFILE\BUSINESS\DOLLAR.WMF”)

Para "descargar" esa imagen de ese formulario, basta con ejecutar la misma instrucción sin fichero
alguno:

Form1.Picture = LoadPicture ( )

También pueden tomar la imagen desde otro control de imagen, mediante un procedimiento de
Intercambio Dinámico de Datos (DDE) (Solo el PictureBox)

Puede también meter una imagen en una variable, y luego poner en uno de los controles citados
anteriormente la imagen guardada en la variable. Este método es muy rápido, ya que no necesita
acceder al disco para buscar una imagen, pero emplea mucha memoria RAM, ya que la variable )o
variables conteniendo la(s) imágenes están en la RAM.

Para ello debemos declarar una o varias variables tipo Picture, y meter en ellas una imagen
mediante el método LoadPicture. Vea en el capitulo 7 (Métodos Gráficos - Método LoadPicture) un
ejemplo muy ilustrativo.

EL FORMULARIO
Ya hemos visto lo que es el Formulario. Simplemente podemos añadir a lo ya dicho, que un
formulario tiene la propiedad Picture, con lo que podemos poner como fondo un bit-map, un fichero
de icono ( .ICO) o un Metarchivo (.WMF). Un fondo gráfico sobre el Formulario puede convertir una

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 1


aplicación de buena a excelente. No intente nunca mejorar una aplicación mediocre con un fondo
artístico en un Formulario.

Además de presentar imágenes, se puede escribir texto en un formulario. Para ello se utiliza el
método gráfico Print que veremos en el capítulo de métodos gráficos

CONTROL PICTURE BOX

Este objeto se encuentra en la caja de herramientas estándar:

Este objeto permite presentar todo tipo de ficheros gráficos (.BMP, WMF, .ICO, .CUR)

Las dimensiones del PictureBox se establecen en el diseño o mediante programa, variando las
propiedades Height y Width. También puede cambiarse su posición mediante las propiedades Top
y Left. Dispone de una propiedad, Align que permite colocarlo adosado en la parte superior. Inferior
o a uno de los lados del formulario que lo contiene.

El Control PictureBox puede ser destino de los datos de un enlace DDE. (Los datos serán,
lógicamente, gráficos. Por ello, tiene las propiedades LinkMode, LinkItem, LinkTimeout y
LinkTopic.

También puede tomar el dato del gráfico de una Base de Datos. (A través de un control Data o un
objeto Recordset o rdoResultset)

Las propiedades de un PictureBox son:

Align Appearance Autoredraw Autosize Backcolor BorderStyle


ClipControls DataField DataSource DragIcon DragMode DrawStile
DrawWidth Enabled FillColor FiilStyle Font Fontransparent
ForeColor Height HelpContextID Index Left LinkItem
LinkMode LinkTimeout LinkTopic MouseIcon MousePointer Name
Negotiate Picture ScaleHeight ScaleLeft ScaleMode ScaleTop
ScaleWidth TabIndex TabStop Tag Top Visible
WhatThisHelp Width

Un PictureBox puede disponer de los siguientes procedimientos :

Click Change DblClick DragDrop DragOver GotFocus


KeyDown KeyPress

Al igual que en el formulario, se puede escribir texto en un PictureBox, utilizando el método Print.

El control Picture puede ser contenedor de otros controles. Esto quiere decir que puede poner otros
controles dentro del picture, y esos controles tendrán un comportamiento especial en ciertos casos.
(Verá más adelante el control Option)

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 2


CONTROL IMAGE

Este control se encuentra en la caja de herramientas estándar:

Este control permite presentar todo tipo de ficheros gráficos (.BMP, WMF, .ICO, .CUR)

El control Image no puede ser destino de una comunicación DDE. Puede tomar la imagen de una
base de datos, bien a través de un control Data o a través de un objeto Recordset.

El control Image utiliza menos recursos del sistema y repinta con más rapidez que un control
PictureBox, pero sólo admite una parte de las propiedades, los eventos y los métodos de
PictureBox. Use la propiedad Stretch para determinar si el gráfico se escala para que se ajuste al
control o viceversa. Poniendo esta propiedad a True el gráfico se adaptará a las dimensiones del
control Image. Si se pone a False, el control Image tomará las medidas del gráfico que contenga. Si
el gráfico es un bit-map (Fichero .BMP), con la propiedad Stretch a True podemos variar el tamaño
del bit-map, variando las propiedades Width y Height del control Image, propiedades que se
pueden cambiar en tiempo de ejecución. Si esta propiedad está a False, el tamaño del bit-map no
cambiará, presentándose solamente una porción del bit-map, caso que el control Image sea menor
que el tamaño del bit-map, o sobrará espacio en el control, en caso contrario.

Un Image es transparente, es decir, deja ver el fondo del formulario en las partes no ocupadas por
su gráfico. Por lo tanto, no tendrían sentido en este control propiedades como Backcolor, FillColor,
o FillStyle.

Las propiedades de un Image son:

Appearance BorderStyle Datafield DataSource DragIcon DragMode


Enabled Height Index Left MouseIcon MousePointer
Name Picture Stretch Tag Top Visible
WhatThisHelp Width

Un Image puede disponer de los siguientes procedimientos :

Click DblClick DragDrop DragOver GotFocus MouseDown


MouseMove MouseUp

PROPIEDADES DE LOS CONTROLES PictureBox e Image

Align (PictureBox solamente)

Permite colocar el control en el borde superior (Align Top), en el inferior (Align


Bottom), en el izquierdo (Align Left) o en el derecho (Align Right) del formulario que
lo contiene. Para no alinearlo con ningún borde basta con poner la propiedad Align a 0-
None.

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 3


Cuando se adosa a uno de los bordes, el tamaño del control se ajusta automáticamente
a la anchura o altura del formulario.

Sintaxis
NombrePictureBox.Align [= número]

número Un entero que especifica cómo se presenta el control. Puede tomar los
siguientes valores :

0-None (Predeterminado cuando el control se coloca en un formulario no MDI).


Con este valor, el control mantiene el tamaño y la posición asignada en
tiempo de diseño.
1-Top (Predeterminado cuando el control se coloca en formularios MDI) El control
se coloca en la parte superior del formulario y su anchura es igual a la
anchura del formulario.
2-Bottom El control se coloca en la parte inferior del formulario y su anchura es igual
a la anchura del formulario.
3-Left El control se coloca en la parte izquierda del formulario y su altura es igual
a la altura del formulario.
4-Right El control se coloca en la parte derecha del formulario y su altura es igual a
la altura del formulario.

Se puede usar propiedad Align para crear rápidamente una barra de herramientas o
una barra de estado en la parte superior o inferior de un formulario. Cuando un usuario
cambie el tamaño del formulario, un control con la propiedad Align establecida a 1 ó 2
modificará su tamaño de forma automática para ajustarse a la anchura del formulario.

De la misma forma se puede crear barras de herramientas a los lados izquierdo o


derecho de un formulario. Si en un formulario hay dos barras de herramientas, una en
la parte superior (o inferior) y otra en un lateral, la de la parte superior o inferior es la
que se extiende hasta la esquina, teniendo preferencia sobre las colocadas
verticalmente a la izquierda o a la derecha.

Al ser el PictureBox un contenedor, puede poner un PictureBox en la parte superior


de un Formulario, y colocar en este PictureBox varios controles Image, a los que se
les puede poner un icono. De esta forma realizamos una barra de herramientas.

Negotiate (PictureBox solamente)

Esta propiedad le permite mostrar o no mostrar el PictureBox dentro de un formulario


donde tiene una barra de herramientas. No está disponible en tiempo de ejecución.
Esta propiedad no es muy usual, por lo que omitimos una mayor explicación. Recurra a
la ayuda para obtener mas detalles

Appearance (PictureBox e Image) 3D o Flat, como en otros controles

Autoredraw (PictureBox solamente)

Permite que el Formulario o PictureBox (El control Image no tiene esta propiedad),
mantenga siempre la imagen o el texto presente. Si Autoredraw está a False, el control
no presentará las imágenes o texto que no se hayan dibujado realmente (caso por
ejemplo de un formulario minimizado) o que se hayan borrado por haber sido puestas
tras otro control.

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 4


Autosize (PictureBox solamente)

Si esta propiedad es True se cambia automáticamente el tamaño del PictureBox para


acomodarse al tamaño de la imagen. Si es False, si la imagen es mayor que el
PictureBox la recortará, y si es menor, presentará una zona sin imagen.

BackColor (PictureBox solamente)

Color de fondo. Igual que otros controles

BorderStyle (PictureBox e Image)

Tipo de borde. Ninguno o fijo. Igual que otros controles.

ClipControls (PictureBox solamente)

Devuelve o establece un valor que determina si los métodos gráficos en eventos Paint
vuelven a dibujar el objeto entero o solamente las áreas últimamente expuestas. Si esta
propiedad es True, un método gráfico repintará todo el Picture. Si es False, solamente
repintará la zona de la imagen que ha variado.

DataField (PictureBox e Image)


DataSource (PictureBox e Image)

Verá con mas detalles estas propiedades cuando estudie los Objetos enlazados a
Datos. Le van a permitir presentar una imagen desde una base de datos. Le permitirá
también introducirla de una forma muy sencilla en la base de datos.

DragIcon
DragMode (PictureBox e Image) Igual que otros controles

DrawMode (PictureBox solamente)


DrawStyle (PictureBox solamente)
DrawWidth (PictureBox solamente)

Formas de responder a los métodos gráficos. Lo verá en el capítulo correspondiente


Enabled (PictureBox e Image)

Habilitado. Igual que otros controles.

FillColor, FillStyle, Font, Fontransparent, ForeColor (PictureBox solamente)

Igual que otros controles.

Height, Width , Left, Top (PictureBox e Image)

Definen el tamaño y la posición del control. En el control Image el tamaño puede


depender del gráfico que se introduzca y del valor de la propiedad Stretch.

HelpContextID (PictureBox solamente) Igual que otros controles

Index (PictureBox e Image) Igual que otros controles

LinkItem, LinkMode, LinkTimeout, LinkTopic (PictureBox solamente)

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 5


Propiedades que afectan al comportamiento de este control como DESTINO de una
conversación DDE. Se estudiará con mas detalles al estudiar el Intercambio Dinámico
de Datos.

MouseIcon, MousePointer (PictureBox e Image)

MouseIcon Establece un icono de mouse personalizado.

(Una vez que comenzamos a estudiar las propiedades gráficas, se comenta cómo se puede cambiar
el icono de la propiedad MouseIcon de todos los controles)

Sintaxis
objeto.MouseIcon = LoadPicture(ruta) ó
objeto.MouseIcon = imagen

donde :
objeto Nombre del objeto PictureBox o Image
ruta Expresión de cadena que especifica la ruta y el nombre del archivo que
contiene el icono personalizado. Así podemos cargar un icono de los existentes en el
disco. Ej. Image1.MouseIcon = LoadPicture("C:\vb\icons\computer\disk05.ico")

imagen Propiedad Picture de un objeto Form, de un control PictureBox o de un


control Image, o nombre de una variable tipo Picture. De esta forma podemos cargar
como un icono el gráfico que tengamos en otro objeto o en una variable tipo Picture.
Ej. Image1.MouseIcon = Picture1.picture

La propiedad MouseIcon proporciona un icono de mouse personalizado que se utiliza


cuando el valor de la propiedad MousePointer es 99.

MousePointer. Establece el tipo de puntero de mouse que aparece cuando se pasa el


puntero del ratón por encima de un objeto en tiempo de ejecución.

Sintaxis objeto.MousePointer [= valor]

objeto Nombre del objeto PictureBox o Image


valor Número entero que especifica el tipo de puntero de mouse que aparece,
según se describe mas adelante.

Las opciones para valor son:

0 (Predeterminado) Forma que determine el objeto.


1 Flecha.
2 Cruz (puntero en forma de cruz).
3 Forma de I.
4 Icono (pequeño cuadrado dentro de otro cuadrado).
5 Tamaño (flecha de cuatro puntas: norte, sur, este y oeste).
6 Tamaño NE SO (flecha doble apuntando al nordeste y al sudoeste).
7 Tamaño N S (flecha doble apuntando al norte y al sur).
8 Tamaño NO SE (flecha doble apuntando al noroeste y al sudeste).
9 Tamaño O E (flecha doble apuntando al oeste y al este).
10 Flecha hacia arriba.
11 Reloj de arena (espera).
12 No soltar.
13 Flecha y reloj de arena.

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 6


14 Flecha e interrogación.
15 Tamaño de todo (personalizable en Microsoft Windows NT 3.51)
99 Icono personalizado especificado en la propiedad MouseIcon explicada
anteriormente.

Name (PictureBox e Image) Nombre del control

Picture (PictureBox e Image)

Devuelve o establece un gráfico mostrado en un control.


Ya se ha estudiado mas atrás como cambiar la propiedad Picture.

ScaleHeight, ScaleWidth, ScaleLeft, ScaleTop, ScaleMode


Propiedades del PictureBox solamente.

¡Todas las propiedades Scale ? ? ? afectan a la medida de las coordenadas, no a la escala !

ScaleHeight, ScaleWidth

Establecen el número de unidades de medida horizontal (ScaleWidth) y vertical


(ScaleHeight) del interior de un objeto al utilizar métodos gráficos o al colocar controles.

Sintaxis objeto.ScaleHeight [= valor]


objeto.ScaleWidth [= valor]

objeto Nombre del Control


valor Expresión numérica que especifica la medida horizontal o vertical.

Nota Las propiedades ScaleHeight y ScaleWidth son distintas de las propiedades


Height y Width.

ScaleLeft, ScaleTop

Devuelven o establecen las coordenadas horizontal (ScaleLeft) y vertical (ScaleTop) de


los bordes izquierdo y superior de un objeto al utilizar métodos gráficos o al situar
controles. Estas coordenadas están medidas de acuerdo con la unidad de medida
establecida en las propiedades ScaleHeight y ScaleWidth

ScaleMode

Devuelve o establece un valor que indica la unidad de medida de las coordenadas de


un objeto al utilizar métodos gráficos, o al situar controles.

Sintaxis objeto.ScaleMode [= valor]

Nombre del Control

objeto Nombre del Control


valor Número entero que especifica la unidad de medida, según se describe a
continuación.

0 Indica que una o más de las propiedades ScaleHeight, ScaleWidth, ScaleLeft y


ScaleTop tienen valores personalizados. Se usa entonces una unidad de medida
definida por el usuario (User)

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 7


1 (Predeterminado) Twip (1440 twips por pulgada lógica; 567 twips por centímetro
lógico).
2 Punto (72 puntos por pulgada lógica).
3 Píxel (la unidad mínima de la resolución del monitor o la impresora).
4 Carácter (horizontal = 120 twips por unidad; vertical = 240 twips por unidad).
5 Pulgada.
6 Milímetro.
7 Centímetro.

Utilizando las propiedades relacionadas ScaleHeight, ScaleWidth, ScaleLeft y


ScaleTop, puede configurar un sistema de coordenadas completo, con coordenadas
positivas y negativas. Estas cuatro propiedades de escala se relacionan con la
propiedad ScaleMode de la siguiente forma:

Al establecer un valor en cualquier otra propiedad de escala, en ScaleMode se


establece automáticamente 0.
Al establecer en ScaleMode un número mayor que 0, ScaleHeight y ScaleWidth
cambian a la nueva unidad de medida, y en ScaleLeft y ScaleTop se establece 0.
Además, los valores de CurrentX y CurrentY cambian para reflejar las nuevas
coordenadas del punto actual.

Stretch (Solo control Image)

Devuelve o establece un valor que indica si un gráfico cambia su tamaño para ajustarlo
al de un control Image.

Sintaxis objeto.Stretch [= lógico]

objeto Nombre del control Image


lógico Expresión booleana que especifica si el gráfico adapta su tamaño, según se
describe a continuación.

True El gráfico cambia su tamaño para ajustarlo al del control.


False (Predeterminado) El control cambia su tamaño para ajustarlo al del gráfico.

Si Stretch tiene el valor True, al cambiar el tamaño del control también se cambiará el
del gráfico que contenga. Cuando aumenta el tamaño del control, mantiene las nuevas
medidas aunque se le introduzca un gráfico de menor tamaño. Debe controlarse por
programa el tamaño del mismo.

TabIndex, TabStop (Solo control PictureBox)

Igual que otros controles

Tag
Top
Visible
WhatsThisHelpID
Width Comunes a ambos. Igual que resto de controles.

Otros controles que pueden manejar imágenes

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 8


IMAGE LIST

Lo verá mucho mas ampliamente en un capítulo posterior. Se incluye en este capítulo para que lo
pueda ir usando.

Este control no está normalmente en la caja de herramientas. Hay que introducirlo mediante los
Proyecto | Componentes y pertenece al grupo Microsoft Windows Common Controls
(COMCTL32.OCX) (Vea Nota 1)

Este control nos permite almacenar varias imágenes. Es, tal como indica su nombre, como un
ListBox pero que en vez de contener textos, contiene imágenes.
La utilidad de este control es para almacenar en él distintas imágenes, y servirlas desde él a otro
control, un PictureBox o un control Image, sin necesidad de tener que acceder a leerlas en el disco,
que conllevaría una importante pérdida de tiempo si el cambio de imágenes debe ser rápido.
Este control es necesario para almacenar las imágenes que se mostrarán en los iconos de la barra
de herramientas. Verá mas adelante como se realiza una barra de herramientas (La barra de
herramientas solo está disponible para la versión de 32 Bits)

Un ImageList permite tener varias imágenes dentro de él, pero este control no las presenta.
Solamente sirve de “almacén” para pasarlas rápidamente a otro control (PictureBox, p.e.) que será
el que las presenta en pantalla.

En la siguiente figura, pueden verse las propiedades de un ImageList con varias imágenes
cargadas.

Nota 1. El grupo de controles Microsoft Windows Common Controls (COMCTL32.OCX) incluye


además de este los controles TabStrip, Toolbar, StatusBar, ProgressBar, TreeView, ListView y
Slider. Se verá con más detalle en un próximo capítulo (Cap. 16)

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 9


Para introducir imágenes en el control ImageList deberemos acceder a sus propiedades, bien
mediante F4 y luego haciendo click sobre Personalizado, bien pulsando el botón derecho del ratón
sobre el icono del control. Aparecerá un cuadro donde podemos insertar imágenes

El tipo de imágenes pueden ser mapas de bits :BMP o iconos .ICO

El control ImageList tiene una colección llamada ListImages. Esta colección contiene todas las
imágenes introducidas en el ImageList y las propiedades de cada imagen. Como toda colección,
será un array donde podemos elegir uno de sus elementos designándolo por su nombre seguido de
su número (Index) encerrado entre paréntesis. Así la imagen número 3 será :

ImageList1.Listimages (3)

Si tenemos un control Picture llamado Picture1 y queremos poner en su propiedad Picture la imagen
cargada en el ImageList1, en su posición 3, usaríamos la expresión :

Set Picture1.Picture = ImageList1.ListImages (3) . Picture

Observe que tras ListImages ( ) es necesario poner la propiedad Picture, ya que Picture es una
propiedad de la colección ListImages

Como cualquier colección, ListImages tiene la propiedad Count, que nos servirá para contar el
número de imágenes que guarda.

Numerodeimágenes = ImageList1. ListImages.Count

Dado que al guardar imágenes en un ImageList, estas imágenes están guardadas en la memoria
RAM, es fácil realizar una animación. Para ello necesitamos varias imágenes que poniendo una tras
otra, dé la sensación de movimiento. Imaginemos un número indeterminado de imágenes dentro de
un ImageList, y un control Picture llamado Picture1 donde queremos presentar la animación. En el
procedimiento Timer de un Timer pondríamos

Static pepe As Integer


pepe = pepe + 1

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 10


If pepe > ImageList1.ListImages.Count Then pepe = 1
Set Picture1.Picture = ImageList1.ListImages(pepe).Picture

Una de las mayores aplicaciones del ImageList es proporcionar imágenes para otros controles.
Entre ellos el TOOLBAR

Barra de Herramientas. Control Toolbar

Este control permite realizar una barra de herramientas. La barra de herramientas es, como ya
conocerá, una barra donde existen varios iconos. Estos iconos realizan una determinada función.
Normalmente se ponen en la barra de herramientas los iconos que representan las acciones mas
frecuentes de una aplicación. Esto facilita la operación al no tener que desplegar menús para
buscar la operación a realizar.

Como el espacio que ocupan los iconos es grande, es también bastante normal que no estén
representados en la barra de herramientas todas las funciones posibles de la aplicación, sino como
decíamos, solamente las mas frecuentes. Pero ocurre que la función que para un usuario es muy
frecuente, para otro no lo es, por lo que también es habitual poder programar los iconos que
aparecen en la barra de herramientas.

Todo ello lo puede hacer el control Toolbar.

Para introducir el Toolbar es necesario que esté presente en la caja de herramientas el control
personalizado Microsoft Windows Common Controls (COMCTL32.OCX).

El control Toolbar es un contenedor de un array de iconos. Estos iconos forman botones sobre los
que se puede insertar código en sus procedimientos. A cada botón se le denomina Button y a la
colección de botones se le denomina Buttons. Cada Button es un elemento de la colección
Buttons y por lo tanto podemos referirnos a cada uno de ellos por el índice que tiene dentro de la
colección.

Los iconos de cada uno de los botones del Toolbar debe introducirse previamente en un control
ImageList. Como se recordará, un control ImageList es un almacén de imágenes, que podemos
usar en cualquier parte de la aplicación. Una de esas partes es la confección de la barra de
herramientas. Por lo tanto, es necesario introducir un control ImageList en cualquier aplicación que
use un control Toolbar. Todas las imágenes del Toolbar deben estar en un único ImageList. Y
este ImageList debe estar en el mismo formulario que el Toolbar

La barra de herramientas puede realizarse en tiempo de diseño (este sería el caso para cuando no
existiese variación ni elección de botones a lo largo de la ejecución de la aplicación)
o en tiempo de ejecución (caso que correspondería con una aplicación que tuviese una barra de
menú programable o que variase esta barra de menú dependiendo de cada operación que se esté
ejecutando en la aplicación).

Para realizar la barra de herramientas en tiempo de diseño, basta con visualizar el cuadro de
propiedades que aparece pulsando el botón derecho del ratón sobre el control Toolbar. Aparecerá
un cuadro de diálogo como este :

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 11


Puede ver que en el cuadro ImageList aparece el nombre de un ImageList. Al desplegar la lista
aparecerán todos los ImageList que existan en el formulario. El ImageList debe estar en el mismo
formulario que el Toolbar. Deberá elegirse el ImageList que contenga las imágenes de los iconos
que queremos introducir en el Toolbar.

Este cuadro nos permite también introducir la forma que adoptará el puntero del ratón cuando entre
en el Toolbar (MousePointer), si el Toolbar aparece por defecto habilitado o deshabilitado (Enabled)
y si muestra o no un rótulo programable al pasar el ratón por encima de cada botón del Toolbar.
(ShowTips). (El uso de estos pequeños rótulos pueden hacer una aplicación muy bonita) La
propiedad AllowCustomize permite, si es True, cambiar el orden de los botones e introducir
separadores (vea evento DobleClick).

En el cuadro botones podemos introducir los datos deseados para cada uno de los botones que
compondrán la colección Buttons.

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 12


Para insertar un nuevo botón hay que hacer click sobre Insertar botón e insertará un nuevo botón
inmediatamente después del que figura en la propiedad Index (en la figura del ejemplo, lo insertaría
en segundo lugar, no en el último lugar como podría creerse). También podemos eliminar un botón
haciendo click sobre Eliminar botón.

El Caption (opcional) es la palabra que figurará debajo del icono del botón.

Un botón se identifica por su índice. ( Toolbar1.buttons(1) )

La propiedad Key es un nombre que se puede añadir a cada botón. Esta propiedad sirve para
identificar el botón que se ha pulsado, pero no para nombrar al botón.

La propiedad Value es el valor por defecto, con el que aparecerá el botón al comienzo de la
aplicación. (Unpressed, no pulsado, Pressed, pulsado).

La propiedad Style define el tipo de botón :

0 - Default Botón monostable. (Se pulsa, pero no se mantiene pulsado)


1 - Check Botón Biestable. (Se mantiene pulsado y se levanta con otro click)
2 - Button Group Solo uno de los botones del grupo puede estar pulsado. Esta
propiedad lleva implícito que los botones que forman un grupo son
biestables. Pueden hacerse varios grupos independientes
introduciendo un botón que no pertenezca a un grupo (tipos 0, 1, 3
ó 4) entre los dos grupos que se independientes que se pretenden
formar
3 - Separator El botón se convierte en un separador de anchura fija.
4 - PlaceHolder El botón se convierte en un separador de anchura variable.

ToolTipText es el texto que aparecerá al lado del botón cada vez que se ponga el cursor del ratón
sobre el botón. Para que aparezca debe estar habilitada la propiedad ShowTips.

Image es el número de la imagen en el ImageList.

El control Toolbar también puede realizarse en tiempo de ejecución. Para introducir u botón en el
Toolbar hay que crear el botón y añadirlo a la colección Buttons de Toolbar. Podemos hacerlo en
una sola instrucción :

Set NombreBotón = NombreToolbar.Buttons.add ( [Indice], [Key], [Caption], [Style], [Imagen])

NombreBotón puede ser cualquier nombre (es el nombre del objeto botón)
NombreToolbar es el nombre del Toolbar
Indice es el número de orden de ese botón dentro del Toolbar
Key es el valor de la propiedad Key del botón. Este valor debe ser único para cada botón.
Style es un número del 0 al 4 con el tipo de botón. Vea lista mas arriba
Imagen es el número de la imagen para ese botón, dentro del ImageList que las contiene.

Los botones pueden habilitarse y deshabilitarse usando la propiedad Enabled (True / False).
Recuerde que los botones se identifican por su índice :

Toolbar1.Buttons(Indice).Enabled = False

Para saber que botón se ha pulsado, puede leerse la propiedad Key :

Text1.Text = Button.Key presenta en Text1 el texto introducido en la propiedad


Key del último botón pulsado.

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 13


Con la lectura de la propiedad Key, y la sentencia Case o If ... Then podemos iniciar la parte de la
aplicación asociada a cada botón.

El control Toolbar tiene los siguientes eventos :

ButtonClick

Este evento se produce cada vez que se hace click sobre un botón del Toolbar. Pasa como
parámetro el índice del botón pulsado. Podremos saber que botón se ha pulsado mediante
sentencias condicionales :

Private Sub Toolbar1_ButtonClick(ByVal Button As Button)

If Button.Index = 1 Then . . . .
If Button.Index = 2 Then . . . .

También podríamos usar la propiedad Key como se dijo mas atrás.

Click

Este evento se produce cuando se hace click sobre cualquier botón del Toolbar, pero no pasa
parámetros. (No distingue sobre que botón se ha hecho click) Podemos utilizarlo cuando se quiera
realizar una operación común para todos los botones (Que suene un Beep, por ejemplo)

DobleClick

Este evento solamente se produce cuando se hace doble click en la parte del Toolbar donde no hay
botones, y la propiedad AllowCustomize esté a True. Si se hace doble click sobre un botón se
produce solamente el evento click (dos veces). Haciendo doble click en una zona libre de botones,
con la propiedad AllowCustomize = True nos permite cambiar el orden de los botones e introducir
separadores.

Change

Se produce solamente cuando se ha realizado algún cambio del orden por el procedimiento
anterior.

DragDrop, DragOver

Igual que cualquier control.

MouseMove, MouseUp, MouseDown

Igual que el resto de los controles Pasa como parámetro el índice del botón, la tecla de mayúsculas,
y las posiciones x e y del ratón.

Private Sub Toolbar_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)

Este control solamente funciona en la versión de VB de 32 Bits. Pero para 16 bits puede hacerse
una cosa parecida (y mas sencilla) utilizando un control Picture como contenedor de tantos
controles Image como necesitemos. Dado que el control Picture dispone de propiedad Align y
puede servir como contenedor de otros controles, puede realizarse una barra de herramientas
similar a esta, y posiblemente de forma mas sencilla.

¡ El control Toolbar NO sirve de contenedor de otros controles, a excepción de sus


botones ! ! !

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 14


LA BARRA DE ESTADO

Este control es muy parecido a la barra de herramientas, y suele usarse, colocándolo en la parte
inferior de la ventana, para indicar el proceso que está en curso en la aplicación. La barra de
estado, control StatusBar se introduce en la caja de herramientas al mismo tiempo que el control
Toolbar, mediante el control personalizado múltiple Microsoft Windows Common Controls
(COMCTL32.OCX).

La barra de estado puede albergar hasta 16 paneles, que pueden contener texto o gráficos.
También pueden contener información del Hardware, tal como el estado de la tecla Bloqueo de
Mayúsculas, Bloqueo del teclado numérico, tecla Insert activada, tecla Scroll Lock activada, o
mostrar la fecha y la hora

La barra de estado puede configurarse como de un solo panel o de múltiples paneles. (Propiedad
Style. 0=múltiples paneles, 1= panel único)

Las dimensiones de cada panel pueden configurarse como fijas o ajustadas al tamaño del texto o
imagen que presentan.

Las propiedades pueden establecerse en tiempo de diseño, mediante el siguiente cuadro.

En este control las imágenes no es necesario introducirlas previamente en un ImageList. Pueden


introducirse directamente sobre el cuadro de diálogo que sale pulsando el botón derecho del ratón -
propiedades - en la ventana correspondiente a paneles. Acepta imágenes tipo Bit-map o .ICO. Los
paneles pueden combinar una gráfico y un texto.

La barra de estado puede realizarse en tiempo de diseño o en tiempo de ejecución. Para realizarla
en tiempo de ejecución basta con visualizar la ventana de propiedades, muy similar a la del control
Toolbar.

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 15


Para añadir un panel en tiempo de ejecución basta con añadirlo a la colección Panels del control
StatusBar mediante la sentencia :

Set PanelNuevo = Nombrebarraestado.Panels.Add.( [índice],[key],[Text],[estilo],[gráfico]

Donde PanelNuevo es el nombre con el que se va a conocer ese panel que acabamos de crear.
PanelNuevo debe declararse como variable objeto Panel donde sea necesario según el ámbito que
le queramos dar. De esta forma, una vez creado, nos podremos referir a ese panel simplemente
citándolo por su nombre (En este caso, PanelNuevo)

Los términos [índice],[key],[Text],[estilo],[gráfico] que entran a formar parte en la sintaxis de


creación del panel se explican a continuación.

Indice - Necesario. Es el índice que define al panel dentro del StatusBar.


Key - Opcional. Es la propiedad Key de ese panel (El contenido de esta propiedad lo podemos
leer desde cada panel
Variable = statusbar1.Panels(Panel.Index).Key
Text - El texto que queremos figure en el panel (Solo si la propiedad Estilo está en sbrText
Estilo - Propiedad estilo del panel.
0 - sbrText El panel mostrará el Texto de la propiedad Text de ese panel
1 - sbrCaps El panel muestra el estado de la tecla Bloqueo Mayúsculas
2 - sbrNum El panel muestra el estado de la tecla Bloq. Números
3 - sbrIns El panel muestra el estado de la tecla Insert
4 - sbrScrl El panel muestra el estado de la tecla Scroll / Lock
5 - sbrTime El panel muestra la hora
6 - sbrDate El panel muestra la fecha
Gráfico - Es el gráfico que va a tener el panel. Este gráfico puede obtenerse desde un ImageList,
ImageList1.ListImages(n).Picture - o directamente desde el disco duro, mediante el
método LoadPicture - LoadPicture("C:\vb\icons\comm\net09a.ico") -

Si no se pone alguna de las propiedades opcionales intermedias, deben mantenerse las comas
separadoras.

Como ejemplo, podemos añadir varios paneles de la siguiente forma :

Dim PanelNuevo As Panel ‘Donde deba declararse a efectos del ámbito


Dim pepe As Integer

Set PanelNuevo = statusbar1.Panels.Add(pepe, "Contenido del Key " & Str(pepe), "Texto " &
Str(pepe), , LoadPicture("C:\vb\icons\comm\net09a.ico"))

Estos son los controles gráficos mas importantes. Verá a lo largo del curso que existen otros, y más
que podrá encontrar entre diferentes suministradores de controles, ya que VB ha dejado una puerta
abierta para realizar controles a medida. Existen varias empresas de software dedicadas a la
fabricación de controles personalizados, y en el aspecto de controles gráficos, podrá encontrar una
amplia gama de fabricantes y controles. Puede obtener muchos controles en el CD-ROM que
acompaña a varias revistas especializadas en programación VB, y a través de Internet.

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 16


Visual Basic - Guía del Estudiante - Ademdum 1 al Capitulo 4
CREAR CONTROLES EN TIEMPO DE EJECUCIÓN

Los ademdums se fueron introduciendo una vez que la Guía del Estudiante estuvo “casi” terminada.
Los temas tratados en los ademdums no constituyen en sí mismos materia suficiente para un
nuevo capítulo, ni se acoplan lógicamente a ninguno de los capítulos escritos. Por lo tanto, se ha
decidido alojarlos en capítulos que no eran demasiado “gruesos”, aunque el contenido de los
ademdums no encaje ni por su contenido, ni por los conocimientos anteriores. No se preocupe que
algunos ademdums no los entienda. Posiblemente estemos usando un lenguaje que no se ha visto
todavía en los capítulos estudiados. Los podrá repasar cuando lo considere oportuno, una vez vaya
avanzando en el curso.

Desde mis comienzos en la actividad educativa de esta asignatura, los alumnos siempre me
preguntaron por la posibilidad de crear controles en tiempo de ejecución. Supongo que exista
alguna razón que yo desconozco para ello. Y digo esto porque no he tenido la necesidad de ello en
ninguno de mis proyectos, y no han sido precisamente pocos.

Quiero decir con esto que la creación de controles en tiempo de ejecución es algo muy llamativo,
pero de escaso sentido práctico. Sean los alumnos los que busquen utilidad a ello, y yo me limito a
mi obligación de enseñárselo.

En anteriores versiones de VB era un proceso un poco tedioso. Había que crear una matriz de
controles y añadir en tiempo de ejecución tantos controles nuevos a esa matriz como necesitemos.
Era complicado. Había que meter un control y ponerle Index = 0. Se le pone la propiedad Visible =
False y ya tenemos una matriz de controles. Una matriz de un solo control, pero al tener la
propiedad Index = 0 ya era una matriz. Ya en ejecución, se utilizada el método Load para crear los
controles que necesitamos. Los nuevos elementos de la matriz tendrán todas las propiedades del
elemento inicial, es decir, las del elemnto que tienen indice 0. Al ser una matriz, todos los controles
comparten el código de sus procedimientos.

Para crear por ejejmplo, varios botones de comando, introduciremos primero uno con Index = 0
cmdBotonInicial(0) y cuando queramos crear un botón nuevo, invocamos el método Load.
Recuerde que el nuevo botón tendrá las mismas propiedades que el objeto inicial, por lo tanto sus
mismas propiedades Left y Top. Resultado: el nuevo botón queda completamente solapado con el
inicial, por lo que habrá que cambiarle de posición y coocarlo en las coordenadas deseadas.

Una de las propiedades que no se pasan al nuevo control es la propiedad Visible. Esta siempre
comienza a False. Por lo tanto también hay que ponerla a True para que veamos el nuevo control.
Este podría ser un código para crear un botón de comando

Load cmdBotonInicial(1)
cmdBotonInicial(1).Visible = True
cmdBotonInicial(1).Left = cmdBotonInicial(0).Left + 1000

Es un poco complicado. Se suele hacer esto para que aparezca un control justamente donde
hacemos clic con el ratón sobre el formulario. Dejo al alumno la posibilidad de jugar con este
método.

Veamos un método más sencillo.

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 17


Add (Método de la colección Controls)
Agrega un control a la colección Controls y devuelve una referencia al mismo.

Sintaxis

Set NombredelControl = NombredelFormulario.Controls.Add (progID, name, container)

Donde:
NombredelControl Es la referencia del nuevo control devuelta por el método Add. Debe ser
una variable tipo Control declarada previamente. Le recomiendo que esta
variable tipo objeto tenga el mismo nombre que le va a dar al control en su
parámetro Name. Le ahorrará muchas confusiones.

NombredelFormulario Es el formulario donde se va a meter el nuevo control. (Puede ser Me)

ProgID Es una cadena que identifica al control. Se obtiene del Examinador de


Objetos de Visual Basic. Consiste en una cadena que indica la biblioteca
donde se encuentra, seguido del nombre que puede ver en el citado
analizador de Objetos, separados ambos por un punto.

Name Es el nombre que va a tener el control. Le repito lo de más atrás. Ponga


aquí la misma cadena que en NombredelControl.
Container Es el nombre del contenedor de ese control si es que se quiere meter
dentro de un contenedor que a su vez está dentro del formulario. Un
contenedor de controles puede ser un PictureBox o un Frame. Aquí se
pondría el nombre del ese contenedor que debe existir en el formulario.

Vamos a ver como se puede declarar una variable tipo Control. Puede hacerlo según estos tres
ejemplos, en el primero se declara que NuevoBoton es un control, (declaración suficientemente
válida ya que posteriormente al crearlo, le diremos que ese control es precisamente un
CommandButton) , en la segunda ya lo declaramos como objeto CommandButton, y la tercera es la
declaración de un Objeto TextBox:

Dim NuevoBoton As Control


Dim NuevoBoton As CommandButton
Dim NuevoTextBox As TextBox

Esta declaración es suficiente si no va a poner código en los procedimientos de ese control. El


problema es que con esa declaración no se puede introducir código. Para ello debe declararse de
otra forma:

Private WithEvents NuevoBoton As CommandButton

Mediante esta declaración (Que debe ponerse en la sección de declaraciones del formulario), no
solamente estamos declarando que NuevoBoton es un CommandButton, sino que tendrá los
mismos eventos (WithEvents) que un CommandButton.

El código para crear estos dos controles es el siguiente:


(En el ejemplo se ha puesto en el procedimiento click de un botón de comando)

Set NuevoBoton = Me.Controls.Add("VB.CommandButton", "NuevoBoton1", Picture1)


Set NuevoTextBox = Me.Controls.Add("VB.TextBox", "NuevoTextBox", Picture1)

NuevoBoton.Visible = True
NuevoBoton.Left = 100

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 18


NuevoBoton.Top = 120
NuevoBoton.Caption = “Soy un Botón”

NuevoTextBox.Visible = True
NuevoTextBox.Left = 2000
NuevoTextBox.Top = 100

Ahora vamos a introducir el código en el procedimiento Click del botón de comando. Para ello
vamos a Herramientas | Agregar Procedimiento y tecleamos el nombre del procedimiento:
NuevoBoton_Click. Continuamos escribiendo el código deseado en ese nuevo procedimiento que
acabamos de crear.
MsgBox "Esto Funciona"

Ejecutamos el programa y vemos que efectivamente, una vez creado el botón, al hacer click sobre
él sale el Mensaje Box. Volvamos a ver el código. Cuando introducimos un procedimiento nuevo
creado por nosotros, ese procedimiento aparece en el desplegable de la derecha de la ventana de
código. En el desplegable de la parte izquierda aparecen solamente los nombres de los controles
existentes en el formulario. Pero ¡Oh sorpresa!, el procedimiento NuevoBoton_Click no está en el
desplegable de la parte derecha. Está en la parte izquierda, y como si fuese un botón que
realmente existe en tiempo de diseño. Ya hemos introducido código en el botón recién creado.

Para el TextBox no ha hecho falta declararlo con la segunda declaración, ya que no va a contener
código. Podemos cambiarle las propiedades, estre ellas su propiedad Text:

NuevoTextBox.Text = "Hola Mi Amor, yo soy tu Lobo"

Texto que aparecerá en el TextBox como si se tratase de un TextBox introducido durante el diseño.
Lógicamente, si ejecutamos la linea anterior antes de crear el TextBox dará un error.

Hay formas más complicadas de crear controles, pero creo que con esta le basta. E insisto que
nunca me he visto en la necesidad de crear controles (lo cual no demuestra nada, lo reconozco)

Quitar controles
Para quitar controles agregados dinámicamente, se utiliza el método Remove. Solamente se
pueden quitar los controles agregados con el método Add (a diferencia de los controles agregados
con la instrucción Load, que se quitan mediante Unload ).

El siguiente ejemplo quita el control NuevoTextBox agregado dinámicamente:

Me.Controls.Remove "NuevoTextBox"

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 19


Visual Basic - Guía del Estudiante - Ademdun 2 al Capitulo 4
EL EXAMINADOR DE OBJETOS

El Examinador de objetos es una herramienta que tienen Visual Basic para ver los objetos de las
colecciones, las propiedades, métodos y eventos de los controles, los métodos del proyecto, las
constantes . Lo entenderemos mejor abriéndolo. Para abrirlo, basta con pulsar F2

Este es el analizador de objetos. Puede ver que tienen varias partes. Comencemos por arriba.
El desplegable donde pone Todas sirve para elegir una parte de todo lo que nos puede mostrar. En
este caso está mostrando todo lo que tienen el proyecto. Si observa la figura de la página siguiente
verá que está desplegado, mostrando todas las referencias y controles que tienen en ese momento.
Puede ver que tienen el MSCommDlg, porque a ese proyecto le habíamos introducido el
CommonDialog. Si seleccionamos ese control, nos aparecen en la ventana Classes todas las
colecciones que tiene el CommonDialog, entre ellas el propio control, que si lo seleccionamos, en la
ventana de la derecha, (Miembros) aparecerán todas la propiedades, los métodos, y los eventos
(Claro que un CommonDialog no tienen eventos, pero sí aparecerán si mostramos cualquier otro
control)

Si le añadimos ahora una referencia (El acceso a una base de datos mediante DAO, por ejemplo)
aparecerá esa referencia en la lista desplegable.

Los controles básicos aparecen en la referencia VB. Aparecen concretamente los controles que
figuran en la barra de herramientas al abrir un nuevo proyecto. Si añadimos más componentes
(Haciendo clic en la barra de menú Proyecto | Componentes) veremos que aparecen nuevos
controles en el desplegable.

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 20


En la casilla Miembros aparecen los métodos, procedimientos y eventos de la clase seleccionada. Al
hacer click sobre cualquiera de estas propiedades, métodos y eventos, en la parte inferior aparece la
explicación del elemento elegido.

Parece que es un poco complicado. Nada más lejos de la realidad. Verá que es una herramienta
que le va a ser muy útil, y que la va a comprender una vez se decida a usarla, mucho antes que el
tiempo que necesitaría para leérselo en este libro. Adelante.

LSB Visual Basic - Guía del Estudiante Capítulo 4 Página 21


Visual Basic - Guía del Estudiante Cap. 5
PORTAPAPELES
INTERCAMBO DINAMICO DE DATOS
EL DRAG AND DROP (Drag & Drop) Arrastrar y Soltar
EL OLEDRAGDROP Drag & Drop con otras aplicaciones
MENÚS - MENUS EMERGENTES

EL PORTAPAPELES. EL OBJETO CLIPBOARD

El objeto Clipboard Proporciona acceso al Portapapeles del sistema.

El portapapeles es una herramienta de windows que permite transportar texto o imágenes de una
parte a otra dentro de la misma aplicación, o entre dos aplicaciones distintas. ¿Quién no ha cortado
y pegado en Windows? Pues al hacerlo está introduciendo texto en el portapaleles y copiándolo en
otra parte.

El objeto Clipboard se usa para manipular el texto y los gráficos del Portapapeles. Este objeto
puede usarse para permitir que el usuario corte, copie y pegue texto y gráficos en la aplicación.
El objeto Clipboard puede contener varias unidades de datos siempre y cuando cada una tenga un
formato diferente. Por ejemplo, se puede usar el método SetData para poner un mapa de bits en el
Clipboard con el formato CF_BITMAP y después usar el método SetText con el formato CF_TEXT
para poner texto en el Clipboard. Después se puede usar el método GetText para recuperar el
texto o el método GetData para recuperar el gráfico. Los datos del Clipboard se pierden cuando se
colocan otros datos con el mismo formato en el Clipboard desde el código o mediante un comando
de menú.

SetText

Pone una cadena de texto en el objeto Clipboard usando el formato del objeto Clipboard
especificado. No acepta argumentos con nombre.

Sintaxis Clipboard.SetText datos, formato

datos Requerido. Cadena de datos que se va a colocar en el Portapapeles.

formato Opcional. Una constante o valor que especifica uno de los formatos del
Portapapeles reconocidos por Visual Basic, como se describe a continuación :

Los valores de formato son:

Constante Valor Descripción

vbCFLink &HBF00 Información de conversación DDE


vbCFRTF &HBF01 Formato de texto enriquecido
vbCFText 1 (Predeterminado) Texto

Estas constantes se enumeran en la biblioteca de objetos de Visual Basic (VB) del


Examinador de objetos.

SetData

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 1


Pone una imagen en el objeto Clipboard usando el formato gráfico especificado. No acepta
argumentos con nombre.

Sintaxis Clipboard.SetData datos, formato

datos Requerido. El gráfico que se va colocar en el objeto Clipboard.

formato Opcional. Una constante o valor que especifica uno de los formatos del
objeto Clipboard reconocidos por Visual Basic, como se describe mas
adelante. Si formato se omite, SetData determina el formato gráfico
automáticamente.

Los valores de formato son:

Constante Valor Descripción

vbCFBitmap 2 Mapa de bits (archivos .BMP)


vbCFMetafile 3 Metarchivo (archivos .WMF)
vbCFDIB 8 Mapa de bits independiente del dispositivo (DIB)
vbCFPalette 9 Paleta de colores

Estas constantes se enumeran en la biblioteca de objetos de Visual Basic (VB) del


Examinador de objetos.
El gráfico que se va colocar en el objeto Clipboard se define mediante la función
LoadPicture o la propiedad Picture de los objetos Form, Image o PictureBox.

GetData
Devuelve un gráfico del objeto Clipboard. No acepta argumentos con nombre.

Sintaxis Clipboard.GetData (formato)

formato
Opcional. Una constante o valor que especifica el formato gráfico de Clipboard, como se
describe mas adelante. La constante o valor debe ir entre paréntesis. Si formato es 0 o se
omite, GetData usa automáticamente el formato apropiado.

Los valores de formato son:

Constante Valor Descripción

vbCFBitmap 2 Mapa de bits (archivos .BMP)


vbCFMetafile 3 Metarchivo (archivos .WMF)
vbCFDIB 8 Mapa de bits independiente del dispositivo (DIB)
vbCFPalette 9 Paleta de colores

Si en el objeto Clipboard no hay ningún gráfico que coincida con el formato esperado, no se
devuelve nada. Si en el objeto Clipboard sólo hay una paleta de colores, se crea un DIB de
tamaño mínimo (1 x 1).

GetText

Devuelve una cadena de texto del objeto Clipboard. No acepta argumentos con nombre.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 2


Sintaxis Clipboard.GetText (formato)

formato
Opcional. Un valor o constante que especifica el formato del objeto Clipboard, como se
describe mas adelante. La constante o valor debe ir entre paréntesis.

Los valores de formato son:

Constante Valor Descripción

vbCFLink &HBF00 Información de conversación DDE


vbCFText 1 (Predeterminado) Texto

Si en el objeto Clipboard no hay ninguna cadena de texto que coincida con el formato
esperado, se devuelve una cadena vacía ("").

Paste

Copia datos desde el Portapapeles del sistema en un control contenedor OLE.

Sintaxis objeto.Paste

Objeto es el nombre del Panel Contenedor OLE donde se quiere depositar el contenido del
Portapapeles.

Comentario

Para usar este método, defina la propiedad OLETypeAllowed y después verifique el valor
de la propiedad PasteOK. No se puede pegar con éxito a menos que PasteOK devuelva
True.
Si se ha ejecutado el método Paste, la propiedad OLEType es vbOLELinked (0) o
vbOLEEmbedded (1). Si no se ha ejecutado el método Paste, la propiedad OLEType es
vbOLENone (3).
Este método puede usarse para implementar un comando Edición Pegar en un menú.
Si el valor de la propiedad PasteOK es True y Visual Basic no puede pegar el objeto, el
control contenedor OLE elimina cualquier objeto existente en el control.

PasteOK

Devuelve un valor booleano que determina si el contenido del Portapapeles del sistema se
puede pegar en el control contenedor OLE.

Sintaxis VariableBooleana = objeto.PasteOK

Objeto es el nombre del contenedor OLE donde se quiere pegar el contenido del
portapapeles.

Cuando el valor de esta propiedad es True, el contenido del Portapapeles del sistema se
puede pegar en el control contenedor OLE.
La propiedad OLETypeAllowed se usa para especificar el tipo del objeto (vinculado o
incrustado) que se quiere pegar en el control contenedor OLE. Una vez que un objeto se
ha pegado en el control contenedor OLE, se puede verificar el valor de la propiedad
OLEType para determinar el tipo de objeto que ha sido creado.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 3


Esta propiedad puede usarse si se quiere que la aplicación implemente un comando Pegar
en un menú Edición. Si PasteOK es False, el comando del menú se deshabilita; si no,
puede habilitarse. Los comandos de menú se habilitan y se deshabilitan estableciendo su
propiedad Enabled a True o False, respectivamente.

Los objetos se pegan en el control contenedor OLE con el método Paste.


Para ofrecer mayor flexibilidad al usuario, presente un cuadro de diálogo Pegado especial
cuando el usuario elija el comando Edición Pegar
. (Establezca OLETypeAllowed = 2 y después use el método PasteSpecialDlg). Cuando se
presenta este cuadro de diálogo, el objeto del Portapapeles del sistema se pega
basándose en las selecciones del usuario en el cuadro de diálogo.

GetFormat

Devuelve un entero que indica si un elemento del objeto Clipboard coincide con un formato
especificado. No acepta argumentos con nombre.

Sintaxis VariableLong = Clipboard.GetFormat (formato)

formato
Requerido. Un valor o constante que especifica el formato del objeto Clipboard, como se
describe mas adelante. La constante o valor debe ir entre paréntesis.

Los valores de formato son:

Constante Valor Descripción

vbCFLink HBF00 Información de conversación DDE


vbCFText 1 Texto
vbCFBitmap 2 Mapa de bits (archivos .BMP)
vbCFMetafile 3 Metarchivo (archivos .WMF)
vbCFDIB 8 Mapa de bits independiente del dispositivo (DIB)
vbCFPalette 9 Paleta de colores

El método GetFormat devuelve True si algún elemento del objeto Clipboard coincide con el
formato especificado. Si no, devuelve False.
Para los formatos vbCFDIB y vbCFBitmap, la paleta de colores que se encuentre en el
Clipboard se usa para presentar el gráfico.

Clear

Borra el contenido del Portapapeles del sistema.

Sintaxis Clipboard.Clear

Con Clear se borra todo el contenido del portapapeles, texto y gráficos.

Copy
Copia el objeto de un control contenedor OLE al Portapapeles del sistema.

Sintaxis objeto.Copy

Objeto es el nombre del contenedor OLE cuyo contenido queremos copiar

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 4


Cuando se copia un objeto en el Portapapeles del sistema, todos los datos y la información de
vinculación asociados con el objeto se copian en el Portapapeles del sistema. En el Portapapeles
del sistema se pueden copiar objetos vinculados y objetos incrustados.
Este método puede usarse para implementar un comando Edición | Copiar en un menú.

EJERCICIO

Se propone el siguiente ejercicio, donde pueden verse todas las posibilidades del Portapapeles.

Cree un formulario de la siguiente forma :

El gráfico que tiene el Picture de la izquierda puede ser cualquiera.

El código de este formulario es el siguiente:

Option Explicit

Private Sub Check1_Click()


End Sub

Private Sub Command1_Click()


Clipboard.SetData Picture1.Image
End Sub

Private Sub Command2_Click()


Dim ClpFmt As Integer
Dim Msg As String
On Error Resume Next ' Configura el controlador de errores.
If Clipboard.GetFormat(vbCFText) Then ClpFmt = ClpFmt + 1
If Clipboard.GetFormat(vbCFBitmap) Then ClpFmt = ClpFmt + 2
If Clipboard.GetFormat(vbCFDIB) Then ClpFmt = ClpFmt + 4
If Clipboard.GetFormat(vbCFMetafile) Then ClpFmt = ClpFmt + 8
Select Case ClpFmt

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 5


Case 1
Msg = "El Portapapeles sólo contiene texto."
Case 2
Msg = " El Portapapeles sólo contiene un archivo de mapa de bits."
Case 3
Msg = " El Portapapeles contiene texto y un archivo de mapa de bits."
Case 5
Msg = " El Portapapeles contiene texto y un archivo DIB."
Case 8
Msg = " El Portapapeles contiene solamente un archivo MetaFile."
Case 9
Msg = " El Portapapeles contiene texto y un archivo MetaFile."
Case Else
Msg = "No hay nada en el Portapapeles."
End Select
Label1.Caption = Msg ' Muestra el mensaje.
End Sub

Private Sub Command3_Click()


Clipboard.Clear
End Sub

Private Sub Command4_Click()


Clipboard.SetText Label2.Caption
End Sub

Private Sub Command5_Click()


Label3.Caption = Clipboard.GetText
End Sub

Private Sub Command6_Click()


Picture2.Picture = Clipboard.GetData()
End Sub

Private Sub Command7_Click()


Picture2.Picture = LoadPicture
End Sub

Private Sub Command8_Click()


Text1.Text = Trim(Text1.Text)
If UCase(Right(Text1.Text, 3)) = "BMP" Then
Check1.Value = 1
Else
Check1.Value = 0
End If
If Check1.Value = 1 Then
Clipboard.SetData LoadPicture(Text1.Text), 8
Else
Clipboard.SetData LoadPicture(Text1.Text)
End If
End Sub

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 6


LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 7
INTERCAMBO DINAMICO DE DATOS (Dinamic Data Exchange) DDE

El intercambio dinámico de datos es una utilidad de Windows que utiliza Visual Basic, y nos
permite crear aplicaciones que tomen datos una de otras.

Para pasar datos de una aplicación a otra se necesitan al menos, dos aplicaciones (lógico), una
que se deje leer, y la otra (u otras), que quieran leer la información en aquella.

Puede darse el caso que una aplicación esté recibiendo datos de otra aplicación, y a su vez envíe
datos a una tercera.

A la aplicación que envía la información se le llama aplicación servidor, y a la que la recibe,


aplicación cliente.

La aplicación servidor debe estar funcionando antes de que la aplicación cliente le pida la
información. Si no es así, se generará un error.

Los datos a traspasar de una aplicación a otra pueden ser:

· Textos, de un Label o un TextBox.


· Imágenes, de un PictureBox.

El origen de un intercambio DDE siempre es un formulario. Dentro de este formulario origen


estará el Label, TextBox o PictureBox que contiene la información a enviar.

Para indicar que un formulario es origen de información para un intercambio DDE debemos
decírselo en sus propiedades LinkMode y LinkTopic.

El destino de un texto ha de ser necesariamente un Label, un TextBox, y el destino de un gráfico


debe ser un PictureBox.

Cuando queremos que uno de estos controles sea el destino de un intercambio DDE debemos
indicarlo en sus propiedades LinkMode, LinkTopic, LinkItem, e indicarle el tiempo de espera para
un intercambio en la propiedad LinkTimeout.

Propiedad LinkMode

Tiene distinta forma si se trata de un control (Label, TextBox y PictureBox) ó un formulario.

Para un formulario tiene dos valores posibles :

0 = None No puede existir comunicación DDE con ese formulario


1= Source El formulario permite que exista una comunicación DLL entre uno de
sus controles y otra aplicación.

Si se establece el valor de esta propiedad a 0 en tiempo de diseño, no podrá cambiarse en tiempo


de ejecución. Si se establece a 1 en tiempo de diseño, se podrá cambiar a 0 y volver a ponerla a 1
en tiempo de ejecución.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 8


Para un control, la propiedad LinkMode le permite que inicie una conversación DDE con una
aplicación servidor, (origen), y cómo iniciarla. Tiene 4 valores posibles :

0=None. No existe comunicación DDE con ese control

1=Automático Los datos se traspasarán desde la aplicación servidor a este control de


la aplicación cliente cada vez que cambie el dato en la aplicación
servidor (origen)

2=Manual Los datos se traspasarán cuando lo pida la aplicación cliente (destino),


mediante la orden LinkRequest.

3=Notify Cuando existe un cambio en los datos de la aplicación origen, ésta


notifica a la aplicación destino que el dato ha cambiado, pero no le envía el
dato nuevo. En el control de la aplicación destino donde debe llevarse la
información, se genera el evento LinkNotify, en cuyo procedimiento
podremos escribir el código necesario dependiendo de nuestra aplicación.
Para traer la información, debe ejecutarse la orden LinkRequest. (Véase
mas adelante)

En tiempo de ejecución, para un control, esta propiedad es de lectura y escritura, es decir, se


puede usar para saber que valor tiene esta propiedad en un determinado control, o para forzar esa
propiedad a un determinado valor.

La sintaxis de esta propiedad es :

objeto.LinkMode [= número]

donde número es un entero que especifica el tipo de conexión. (0, 1, 2 ó 3 según se ha visto)
y objeto es el nombre del control.

Propiedad LinkTopic

Esta propiedad es de lectura y escritura, tanto para los controles como para los formularios.

Cuando un control destino quiere establecer una comunicación DDE “llama” a la aplicación origen,
y dentro de ella, al formulario que contiene el control cuya información debe ser traspasada.
(Nótese que la aplicación origen puede tener varios formularios). Al ese formulario podría llamarle
por su nombre, (por su Name), pero no lo hace así. Le llama por un nombre que le debemos poner
al formulario en su propiedad LinkTopic. A este nombre se le denomina Tema.

La propiedad LinkTopic, para un formulario de origen, devuelve o establece el tema al que el


formulario “responde” en una conversación DDE.

Sintaxis NombredelFormulario.LinkTopic [= tema]

Para un control destino, La propiedad LinkTopic contiene el nombre de la aplicación y el tema,


ambos separados mediante el carácter | (carácter 124)

Sintaxis NombredelControl.LinkTopic [= aplicacionorigen|tema]

El nombre de la aplicación origen será el nombre del de proyecto de Visual Basic sin la extensión
.VBP (si la aplicación se está ejecutando en el entorno de desarrollo de Visual Basic), o el nombre
de la aplicación de Visual Basic sin la extensión .EXE (si se ejecuta como un archivo ejecutable
independiente).

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 9


El tema será el mismo al que “responde” el formulario donde se encuentra el control que contiene
la información a traspasar.

(DDE es una utilidad de Windows. Windows establece que el estándar de un vinculo DDE es
Aplicación | Tema | elemento. Véase para mas detalles el manual de Windows, enlaces DDE)

Propiedad LinkItem

La propiedad LinkItem solamente la tiene el control destino de la información. No la tiene el


formulario origen. En esta propiedad deberá expresarse el nombre del control origen de la
información.

Esta propiedad es de lectura y escritura, es decir, tanto sirve para saber el nombre del control
origen de los datos, como para establecerlo en tiempo de ejecución.

Sintaxis objeto.LinkItem = cadena

donde cadena es el nombre del control origen que tiene los datos y objeto es el nombre del control
al que le estamos poniendo la propiedad LinkItem.

Propiedad LinkTimeout

Devuelve o establece la cantidad de tiempo que un control espera una respuesta a un mensaje
DDE.

Sintaxis objeto.LinkTimeout = número

donde número es una expresión numérica que especifica el tiempo de espera en décimas de
segundo.
El tiempo de respuesta DDE desde aplicaciones origen varía. Use esta propiedad para ajustar el
tiempo que un control destino espera la respuesta de una aplicación origen. Si se usa LinkTimeout
de forma correcta se puede evitar la generación de un error por Visual Basic si una aplicación
origen tarda mucho en responder.

Nota La plazo mayor de tiempo que un control puede esperar es 65.535 décimas de segundo, es
decir, sobre 1 hora y 49 minutos. Al establecer LinkTimeout a 1 se indica al control que espere la
respuesta en una conversación DDE durante el mayor plazo de tiempo. El usuario puede forzar
que el control deje de esperar presionando la tecla ESC..

Evento LinkNotify

Ocurre cuando el origen ha cambiado el dato definido por el vínculo DDE si la propiedad LinkMode
del control destino está establecido a 3 (Notificar).

Private Sub objeto_LinkNotify([índice As Integer])

End Sub

En este procedimiento se puede escribir el código necesario para nuestra aplicación, a sabiendas
de que este evento se produce cuando cambia la información en origen. Posiblemente no quiera
depositarlo de inmediato en el control destino, puesto que si fuese así habría puesto la propiedad

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 10


LinkMode a 1. Cuando quiera colocar el dato en el control destino, puede utilizar el método
LinkRequest para obtener el nuevo dato de la fuente.

Método LinkRequest

Pide a la aplicación origen de una conversación DDE que actualice el contenido de un control
Label, PictureBox o TextBox.

Sintaxis objeto.LinkRequest

Siendo objeto el nombre del control destino de la aplicación.

Objeto es el nombre de un control Label, PictureBox o TextBox involucrado en una conversación


DDE como destino. LinkRequest provoca que la aplicación origen envíe los datos actuales al
objeto, actualizando la propiedad Caption si objeto es un control Label, la propiedad Picture si
objeto es un control PictureBox o la propiedad Text si objeto es un control TextBox.
Si la propiedad LinkMode del objeto está definida como 1 (Automático), la aplicación origen
actualiza objeto automáticamente y LinkRequest no es necesario. Si la propiedad LinkMode del
objeto está definida como 2 (Manual) , la aplicación origen actualiza objeto sólo cuando se usa
LinkRequest.
Si la propiedad LinkMode del objeto está definida como 3 (Notify), el origen notifica al destino que
los datos han cambiado invocando el método LinkNotify. El destino debe entonces usar el método
LinkRequest para actualizar los datos.

Método LinkSend

Transfiere el contenido de un control PictureBox a la aplicación destino de una conversación DDE.

Sintaxis objeto.LinkSend

Objeto debe ser un control PictureBox de un objeto Form que sea origen de una conversación
DDE.
Cuando otras aplicaciones establecen vínculos automáticos con un objeto Form de su aplicación,
Visual Basic las notifica cuando el contenido de un control TextBox o Label origen cambia. Sin
embargo, Visual Basic no notifica automáticamente a una aplicación destino DDE cuando el valor
de la propiedad Picture de un control PictureBox origen cambia. Como la cantidad de datos de un
gráfico pueden ser muy grande y como no tiene sentido actualizar la aplicación destino por cada
cambio de píxel de la imagen, Visual Basic requiere el uso del método LinkSend para notificar
explícitamente a las aplicaciones destino DDE cuándo cambia el contenido de un control
PictureBox.

Método LinkPoke

Transfiere el contenido de un control Label, PictureBox o TextBox a la aplicación origen de una


conversación DDE.

Sintaxis objeto.LinkPoke

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 11


Objeto es el nombre del control Label, PictureBox o TextBox involucrado en la conversación DDE
como destino. Si objeto es un control Label, LinkPoke transfiere el contenido de la propiedad
Caption al origen. Si objeto es un control PictureBox, LinkPoke transfiere el contenido de la
propiedad Picture al origen. Si objeto es un control TextBox, LinkPoke transfiere el contenido de la
propiedad Text al origen.
Normalmente, en una conversación DDE la información fluye de origen a destino. Sin embargo,
LinkPoke permite que un objeto destino suministre datos al origen. No todas las aplicaciones origen
aceptan información de esta forma; si la aplicación origen no acepta los datos, se produce un error.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 12


LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 13
EL DRAG & DROP (Arrastrar y Soltar)

El Drag & Drop es una forma visual de representar el movimiento de algo. Para ello se toma algo
de una parte de la interface gráfica, mediante la operación de colocar el puntero del ratón y pulsar
su botón izquierdo sobre ese algo que se quiere tomar. Sin dejar de pulsar el botón izquierdo del
ratón se desliza (se arrastra) el puntero del ratón hasta el punto de la interface gráfica donde lo
queremos dejar. Ese punto puede ser un control o un formulario. Una vez en el punto de destino se
suelta el botón del ratón y se “deja caer” lo que habíamos tomado en el punto de origen. El efecto
de “tomar” algo de un control le denominaremos Drag. Si durante la operación de arrastre
pasamos por encima de un control, se producirá en ese control el evento DragOver Al efecto de
dejar caer le denominaremos DragDrop.

El Drag & Drop tiene un efecto visual muy didáctico. Pero NO HACE otra cosa. Es decir, no toma
nada del control origen ni lo suelta al llegar a destino. Esa acción de tomar algo en el origen o
soltarlo al llegar al destino debemos realizarla mediante código en los eventos adecuados
(MouseDown, DragOver , DragDrop), dando los valores adecuados a las propiedades DragMode
y DragIcon, y utilizando el método Drag.

Propiedad DragMode

Es una propiedad de lectura y escritura. Devuelve o establece un valor que determina si se usa el
modo de arrastre manual o automático en una operación de arrastrar y soltar.

Sintaxis NombreControlOrigen.DragMode = número

Donde número puede tomar los valores 0 (Manual) ó 1 (Automático).


El valor predeterminado es el 0.

Cuando esta propiedad está a 0 (Manual) se debe emplear el Método Drag para iniciar una
operación Drag & Drop. Si está a 1, la operación de arrastrar y soltar se inicia automáticamente
cada vez que hacemos click sobre el botón izquierdo del ratón, teniendo el puntero del mismo
sobre el control. Los controles contenedores OLE sólo se arrastran automáticamente cuando no
tienen el enfoque.

Parece en principio mas práctico tener esta propiedad a 1. Sin embargo la realidad es distinta. Se
controla mucho mejor el Drag & Drop poniendo esta propiedad a 0 (Manual), pese a que en este
caso deberemos utilizar el método Drag para iniciar el proceso.

El poner esta propiedad en automático conlleva también el hecho de que el control no toma el foco
haciendo click sobre él, ya que no sabe si lo que quiere hacer es llevarle el foco o iniciar una
operación de Drag & Drop.

Propiedad DragIcon
Devuelve o establece el icono que se presenta como puntero del ratón durante una operación de
arrastrar y soltar.

Sintaxis NombreControlOrigen.DragIcon = icono

Donde Icono es cualquier referencia a un icono válido.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 14


Esta propiedad va a marcar el icono que aparezca durante la operación Drag & Drop
desplazándose a lo largo de la ventana. Si no se especifica esta propiedad, el desplazamiento se
expresa mediante un rectángulo del tamaño del control origen, cosa que resulta bastante
desagradable en cualquier aplicación. Debe ponerse por lo tanto un icono en esta propiedad.

El valor de esta propiedad puede establecerse en tiempo de diseño, eligiendo el icono en el cuadro
de Propiedades del control origen, o en tiempo de ejecución. En este caso, la referencia a un icono
válido puede darse igualando el valor de esta propiedad a un icono ya existente en la aplicación
(NCO.DragIcon = Form1.Icon pondría como icono el del formulario Form1, NCO.DragIcon =
Text1.DragIcon pondría el mismo icono de Text1 para esta propiedad), o cargándolo mediante la
función LoadPicture :

(NCO.DragIcon = LoadPicture (C :\Iconos\Icono1.ICO)

El archivo que se cargue debe tener la extensión .ICO y formato de icono.

Para Nota. Cuando quiera colocar un icono animado en la propiedad DragIcon (una hoja de papel
que oscila al moverse, una hoja de papel que se destruye - ejemplos tomados de W95-), debe usar
varios iconos en secuencia. Por lo tanto debe cambiar la propiedad DragIcon a lo largo del tiempo
que dura el arrastre. Puede utilizar para ello un temporizador (control Timer) o basarse en las
coordenadas del formulario por donde se mueve (para eso introducen en el evento DragOver del
Formulario). Dado que el cambio debe ser rápido, no es conveniente acceder al disco (mediante la
función LoadPicture) cada vez que tiene que cambiar la imagen del icono. Como para simular un
movimiento tan sencillo son suficientes pocas imágenes, (8 por ejemplo) puede crear otras tantas
variables tipo Picture, cargar las imágenes al comienzo de la aplicación (con la función
LoadPicture) y cuando necesite el movimiento animado del icono, cargar las 8 imágenes
secuencialmente desde esas variables, para simular el movimiento

NCO.DragIcon = Variable1
NCO.DragIcon = Variable2
......
NCO.DragIcon = Variable8

Esto le ocupará mas memoria. Es el precio a pagar por la rapidez y la buena presentación de una
aplicación.

Método Drag
Inicia, termina o cancela una operación de arrastre de cualquier objeto excepto los controles Line,
Menu, Shape o Timer.

Sintaxis NombreControlOrigen.Drag TipoAcción

NombreControlOrigen es el nombre del control donde se inició la operación Drag & Drop.

TipoAcción es un valor o una constante que especifica la acción a realizar, según se describe a
continuación :

Constante Valor Descripción

vbCancel 0 Cancela la operación de arrastre.


vbBeginDrag 1 Inicia el arrastre del objeto.
vbEndDrag 2 Termina el arrastre y suelta el objeto.

Si se omite TipoAcción, la acción predeterminada es iniciar el arrastre del objeto.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 15


El uso del método Drag para controlar una operación de arrastrar y soltar sólo se requiere cuando
la propiedad DragMode del control origen tiene el valor Manual (0). Sin embargo, Drag puede
usarse con objetos cuya propiedad DragMode tenga el valor 1 (o vbAutomatic).

En versiones anteriores de Visual Basic, Drag era un método asíncrono y las instrucciones
siguientes se ejecutaban incluso aunque la acción de arrastre no hubiera terminado. En Visual
Basic versión 4.0, Drag es un método síncrono y las instrucciones siguientes no se ejecutan hasta
que la acción de arrastre no haya terminado.

Usando el método Drag puede controlar exactamente cuando quiere que se produzca el inicio del
Drag & Drop y el final. El autor de esta Guía del Estudiante vuelve a recomendar que ponga la
propiedad DragMode = 0 (Manual). Entre otras razones por la siguiente :

Cuando tenemos la propiedad DragMode de un TextBox a 1 (automático) ese TextBox no podrá


coger el foco, (al menos de forma fácil) y si lo consigue no puede seleccionar el texto que tiene
actualmente, ya que VB no puede saber si lo que está ocurriendo es que queremos seleccionar el
texto o si deseamos iniciar la operación D & D.

Como decíamos al principio, el Drag & Drop solamente es una manifestación visual de algo que se
está produciendo, pero ese algo deberemos programarlo. Por ejemplo, es muy típico llevar un dato
de una casilla a otra (de un TextBox a otro p.e.) mediante una operación D & D.

El dato debemos llevarlo a una variable que nos permita, al final de la operación, introducir ese
dato en el TextBox final. (No olvide declarar la variable en el lugar correspondiente para que sea
válida en ambos controles). La acción de llevar el dato a la variable debemos hacerla en el
procedimiento mas adecuado. Puede ser por ejemplo, el procedimiento MouseDown del control
origen, ya que cualquier operación de D & D comienza haciendo click en el control origen. Si tiene
la propiedad DragMode de ese control en Manual, en el momento de hacer Click, ese control toma
el foco y, caso de un TextBox, puede arrastrar con el ratón para cambiar el texto, cosa que no
podría hacer si pone DragMode=1.

Evento DragOver
Cuando una operación de arrastrar y soltar está en progreso y el cursor del ratón pasa por encima
de un control o un formulario, se produce el evento DragOver de ese control o formulario.

Dependiendo si se trata de un Formulario convencional, un Formulario MDI o un control, el


procedimiento DragOver captura distintos parámetros :

Private Sub Form_DragOver(origen As Control, x As Single, y As Single, estado As Integer)


Private Sub MDIForm_DragOver(origen As Control, x As Single, y As Single, estado As Integer)
Private Sub Control_DragOver([índice As Integer,]origen As Control, x As Single, y As Single,
estado As Integer)

Donde :

origen = Control que se está arrastrando. O dicho de forma mas ortodoxa, control en el que se
inició la operación de Drag & Drop. Dentro de este procedimiento puede hacer referencia a sus
propiedades y métodos con este argumento. Por ejemplo, Source.Visible = False. Caso de que el
Control Origen fuese parte de un array de controles, el Index de ese control se tiene en índice

x, y Número que especifica la posición horizontal (x) y vertical (y) actual del puntero del mouse
dentro del control o formulario destino. Estas coordenadas se expresan siempre en términos del

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 16


sistema de coordenadas del destino tal y como se establece en las propiedades ScaleHeight,
ScaleWidth, ScaleLeft y ScaleTop.

estado Entero que nos indica el estado de transición del control que se está arrastrando en
relación al formulario o control destino:

0 = Entra. Este valor se produce en el instante en el que entra el cursor del ratón a
este control o Formulario. Se genera también en el control origen en el instante que se
pulsa el botón del ratón, iniciándose de esta forma el D & D.
1 = Deja Este valor se produce cuando el cursor sale del control o Formulario.
2 = Sobre Este valor se produce cuando el cursor se está moviendo sobre el control o
el Formulario destino.

Mediante el parámetro origen (completado con índice si el origen se trata de un array) podemos
conocer el control desde el que se inició la operación de Drag & Drop. Debemos tener siempre
presente que el procedimiento DragOver se realiza cada vez que pasamos por encima de un
control o formulario durante una operación de Drag & Drop, independientemente que ese control o
formulario sea o no sea origen ni destino de esa operación. Puede emplearse el procedimiento
DragOver para comprobar si ese valor que transportamos puede depositarse sobre el control o
formulario por el que estamos pasando, si el valor que llevamos está dentro de los márgenes que
admite la aplicación, etc. Es muy llamativo por ejemplo, cambiar el color del control que va a recibir
el valor traspasado si este valor se sale de los márgenes aceptables. O cambiar la propiedad
DragIcon del control origen cuando ese dato no se puede depositar en ese control. Es típico poner
la señal de trafico de Prohibido cuando el dato transportado no se puede soltar sobre el control
sobre el que estamos pasando el cursor del ratón. (Como el control origen se pasa como
parámetro al procedimiento DragOver con el nombre Origen basta con poner Origen.Dragicon =
..... ) Recuerde en este caso que al abandonar ese control debe restaurar el icono original. Para
ello es útil cargar varias variables con los distintos iconos que se van a usar y luego igualar la
propiedad DragIcon del control origen a una u otra variable, dependiendo de los valores u otros
factores de la aplicación.

En el siguiente ejemplo, se declaran 6 variables tipo Picture que van a almacenar seis iconos
distintos :

En General - Declaraciones
Dim pepe as string
Dim icono1 As Picture, Icono2 As Picture, Icono3 As Picture
Dim Icono4 As Picture, Icono5 As Picture, Icono6 As Picture

El Form1.Load se cargan los valores de estas variables con seis iconos existentes en el disco. El
icono asignado al control origen (Text1) es Icono4.
Set icono1 = LoadPicture("C:\vb\icons\dragdrop\drag1pg.ico")
Set Icono2 = LoadPicture("C:\vb\icons\dragdrop\drag2pg.ico")
Set Icono3 = LoadPicture("C:\vb\icons\dragdrop\drag3pg.ico")
Set Icono4 = LoadPicture("C:\vb\icons\dragdrop\drop1pg.ico")
Set Icono5 = LoadPicture("C:\vb\icons\dragdrop\dragfldr.ico")
Set Icono6 = LoadPicture("C:\vb\icons\dragdrop\dropfldr.ico")
Text1.DragIcon = Icono4

En el control destino se cambia el icono si el valor de la variable transportada (pepe) es mayor de


999 :
En el procedimiento DragOver
If Val(pepe) > 999 Then Source.DragIcon = icono1
‘Al salir de Text1 se recupera el icono original
If State = 1 Then Source.DragIcon = Icono4

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 17


Evento DragDrop
Ocurre cuando se completa una operación de arrastrar y soltar como resultado de arrastrar un
control sobre un formulario o control y liberar el botón del mouse o utilizar el método Drag con su
argumento acción establecido a 2 (Drop).

Dependiendo de si soltamos sobre un Formulario convencional, Formulario MDI o Control, este


evento captura los siguientes parámetros :

Private Sub Form_DragDrop(origen As Control, x As Single, y As Single)


Private Sub MDIForm_DragDrop(origen As Control, x As Single, y As Single)
Private Sub Control_DragDrop([índice As Integer,]origen As Control, x As Single, y As Single)

Estos parámetros son idénticos a los del Procedimiento DragOver ya comentados

Utilice un procedimiento de evento DragDrop para controlar qué ocurre tras completarse una
operación de arrastrar. Por ejemplo, puede mover el contenido del control origen a un nuevo lugar
o copiar un archivo de un lugar a otro, depositar un valor sobre un control etc.

Recuerde que la operación Drag & Drop no hace otra cosa que lo que se puede ver en la interface
gráfica. Debe poner en este Procedimiento (DragDrop) el código necesario para que se realice la
operación deseada.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 18


LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 19
EL OLE Drag & Drop
El Drag & Drop visto hasta ahora permite llevar datos desde un control a otro siempre dentro de la
misma aplicación, incluyendo una interface gráfica muy didáctica para presentar ese movimiento de
información. El DDE permite llevar información desde una aplicacióna otra, pero de forma rígida,
es decir, desde un control a otro control, sin intervención del usuario, o al menos, sin una
intervención realizada de forma gráfica con el ratón.

Cuando veíamos las propiedades de los controles relacionadas con el Drag & Drop, veíamos otras
que hablaban de Drag y Drop, que eran OLEDragMode y OLEDropMode, y en el Formulario
veíamos solamente esta última: OLEDropMode. Entre los procedimientos observábamos algo
parecido: OLECompleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLESetData y
OLEStartDrag. También existe el Método OLEDrag.

Mediante estas propiedades, procedimientos y método, podemos hacer que desde una aplicación
(Word por ejemplo) pase información a una aplicación hecha por nosotros, utilizando la misma
interfase gráfica para “ver” el movimiento de los datos. Lo mismo ocurre en sentido contrario.
Desde una aplicación nuestra podemos llevar texto o imágenes a Word. A ese mecanismo se le
denomina OLE Drag & Drop. Parece como si el OLE Drag & Drop reuniera las dos ventajas de DDE
y de Drag & Drop. Esa fue la idea con la que Microsoft creo esta herramienta.

Mediante el OLE Drag & Drop ya podemos enlazar nuestras aplicaciones a las aplicaciones
compradas. Pero piense que lo que va a conseguir con el OLE Drag & Drop ya lo tiene
prácticamente igual con el portapapeles. Por lo tanto, no se haga demasiadas ilusiones. Y además
recuerde que el mecanismo de arrastrar y soltar no es tan fácil como copiar y pegar, al menos para
personas poco hábiles.

El Objeto DataObjet
El objeto DataObjet es un contenedor que utiliza OLE para transportar datos. Recuerde, cuando
hacíamos Drag & Drop normal, en el Drag teníamos que meter lo que queríamos transportar (Texto
o imagen) en una variable y en el Drop poníamos el contenido de esa variable en el control final.
Esto puede hacerse cuando se trata de una misma aplicación, en la que el valor de la variable se
mantiene mientras estuviésemos dentro del ámbito donde se ha declarado. ¿Cómo haríamos esto
para pasar un texto a Word? Debe haber una “variable” que mantenga su contenido entre dos
aplicaciones. Esa “variable” debe ser un objeto superior a las dos aplicaciones que van a
intercambiar datos. Es concretamente el DataObjet

El objeto DataObject es un contenedor de datos donde se pueden transportar datos desde un


componente de origen a un componente de destino.

El DataObject tiene sus propiedades y métodos.

Métodos del DataObject

Método SetData
Inserta datos en un objeto DataObject con el formato de datos especificado.

Sintaxis objeto.SetData [datos], [formato]

objeto es un objeto tipo DataObjet. Este objeto no es necesario declararlo, ya que aparece en
todos los procedimientos donde es posible introducir o sacar datos del DataObject.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 20


Por ejemplo, en el método OLEStartDrag se pasa como parámetro un objeto DataObject llamado
Data.

Private Sub Text1_OLEStartDrag(Data As DataObject, AllowedEffects As Long)


Data.SetData Text1.Text, vbCFText
End Sub

Data es un objeto tipo DataObject donde se ha metido el texto que contienen el Text1. Ese objeto
llamado Data lo ha pasado el procedimiento (Data As DataObject) por lo que podemos meterle los
datos sin necesidad de crearlo previamente. Este objeto es único para Windows, por lo que a partir
de la ejecución de ese procedimiento OLEStartDrag el texto introducido en Data está disponible
para cualquier aplicación Windows que sepa recogerlo.

datos es el dato a introducir en el DataObject. En el ejemplo anterior, era el texto contenido en


Text1

formato es un valor o constante que especifica el tipo de datos introducidos. Este argumento es
opcional. Vea valores posibles en el cuadro más abajo.

Método GetData
Devuelve datos de un objeto DataObject en forma de Variant.

Sintaxis objeto.GetData (formato)

objeto es el objeto tipo DataObject

formato es un valor o constante, que determina el formato de los datos que se van a obtener. Los
valores para formato se pueden ver en el cuadro más abajo.

Un ejemplo de GetData. En el procedimiento OLEDragDrop de un RichTextBox con la propiedad


OLEDropMode existe este código para poner el texto que llevaba el DataObject en el RichTextBox.
Observe que también se pasa en este procedimiento, un parámetro llamado Data del tipo
DataObject.

Private Sub RTB1_OLEDragDrop(Data As RichTextLib.DataObject, Effect As Long, Button As


Integer, Shift As Integer, x As Single, y As Single)

RTB1.SelText = Data.GetData(vbCFText)
End Sub

Loa valores o constantes para formato en ambos métodos son:

Constante Valor Descripción


vbCFText 1 Texto (archivos .txt)
vbCFBitmap 2 Mapa de bits (Archivos .bmp)
vbCFMetafile 3 Metaarchivo (archivos .wmf)
vbCFEMetafile 14 Metarchivo mejorado (archivos .emf)
vbCFDIB 8 Mapa de bits independiente del dispositivo (DIB)
vbCFPalette 9 Paleta de colores
vbCFFiles 15 Lista de archivos
vbCFRTF -16639 Formato de texto enriquecido (archivos .rtf)

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 21


Método Clear
Elimina el contenido del objeto DataObject.

Sintaxis objeto.Clear

Puede ejecutar este método antes de introducir nuevos datos en el DataObject para asegurarse
que ha borrado los datos existentes

Private Sub Text1_OLEStartDrag(Data As DataObject, AllowedEffects As Long)


Data.Clear
Data.SetData Text1.Text
End Sub

Este método sólo está disponible para los orígenes de operaciones de arrastre de componentes. Si
se invoca Clear desde un destino de la operación de colocación de componentes, se producirá un
error.

Método GetFormat
Devuelve un valor booleano que indica si un elemento del objeto DataObject coincide con un
formato especificado.

Sintaxis objeto.GetFormat formato

Ejemplo Puede asegurarse que el formato contenido en el DataObject es el deseado antes de


proceder a colocarlo en un control en la operación de Drop:

Private Sub RTB1_OLEDragDrop(Data As RichTextLib.DataObject, Effect As Long, Button As


Integer, Shift As Integer, x As Single, y As Single)
If Data.GetFormat(vbCFText) = True Then
RTB1.SelText = Data.GetData(vbCFText)
End If
End Sub

Propiedades del DataObject


Deberíamos decir mejor, propiedad, ya que solamente tiene una:

Propiedad Files
Devuelve una colección DataObjectFiles, que a su vez contiene una lista con todos los nombres
de archivo utilizados por un objeto DataObject (por ejemplo los nombres de los archivos que un
usuario arrastra hacia o desde el Explorador de archivos de Windows).

Sintaxis NombredelObjetoDataObject.Files(índice)

La colección Files sólo se puebla con nombres de archivo cuando el objeto DataObject contiene
datos de tipo vbCFFiles. La colección Files puede rellenarse para permitir a las aplicaciones de
Visual Basic actuar como origen de operaciones de arrastre de una lista de archivos.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 22


Colección DataObjectFiles
Es la colección de cadenas con los nombres de ficheros de la propiedad Files del objeto
DataObject.

Sintaxis NombredelObjetoDataObject.DataObjectFiles

La colección DataObjectFiles es una colección de cadenas que representan un conjunto de


archivos seleccionados mediante el método GetData o en una aplicación, como el Explorador de
Windows.
Aunque la colección DataObjectFiles tiene sus propios métodos y propiedades, debe usar la
propiedad Files del objeto DataObject para ver y manipular el contenido de la colección
DataObjectFiles.

Aunque se ha pretendido realizar un ejemplo de esta propiedad, el autor cede ese honor al alumno
interesado en el tema. No he podido obtener los elementos de la colección DataObjectFiles.

Volvamos sobre las propiedades y métodos de los controles involucrados en un


OLE Drag & Drop

Propiedad OleDragMode

Esta propiedad establece la forma en la que comienza a realizarse la operación de Drag. Si está en
Automático basta con seleccionar el texto o la imagen a pasar a otra aplicación y una vez
seleccionado, al volver a marcarlo con el ratón, se inicia el Drag. En ese instante se ejecuta el
procedimiento OLEStartDrag donde deberemos colocar el código para que VB haga lo que
nosotros queramos. Ya se verá al estudiar este procedimiento.
A diferencia del Drag & Drop estudiado anteriormente, donde recomendábamos poner la propiedad
similar a manual, en este caso es mucho más práctico ponerlo en automático y además no es
molesto, ya que el Drag no se inicia si no se ha seleccionado previamente parte del texto o la
imagen a enviar a la otra aplicación.
La propiedad DragMode de ese control debe estar ahora a Manual, ya que si está en automático se
genera antes el Drag & Drop ordinario y no se producirá el OLE Drag & Drop.

Si se pone esta propiedad a Manual es necesario iniciar el drag mediante el método OLEDrag, que
ejecuta el procedimiento OLEStartDrag, y colocar en este el código correspondiente. No es
práctico, pero cada aplicación y cada programador es una caso distinto.

Propiedad OLEDropMode

Esta propiedad va a determinar la forma en la que el componente destino toma los datos
transportados medainte OLE Drag & Drop. Acepta tres valores:

0 vbOLEDropNone El componente no acepta operaciones de Drop. Cuando pasa el


cursor del ratón sobre él durante una operación de OLE Drag &
Drop, muestra el icono de No Colocar
1 vbOLEDropManual Manual. El componente de destino desencadena los eventos
OLE de colocar, (Evento OLEDragDrop) lo que permite al
programador controlar la operación en el código.
2 vbOLEDropAutomatic Automático. El componente de destino acepta automáticamente
las operaciones OLE de colocar si el objeto DataObject
contiene datos en un formato que reconoce. En este caso, en el

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 23


destino no se producen los eventos del mouse ni eventos OLE
de arrastrar y colocar.

Es normal poner esta propiedad a manual, para poder controlar lo que ocurre con la información
tanto en destino como en origen. Estando en Automático, la información en el origen se mueve al
destino, es decir, desaparece del origen al tiempo que se pone en el destino. Esto puede que no
sea lo deseado por el programador. Si pone esta propiedad en Manual, puede controlar lo que hace
la información tanto en destino como en origen.

Eventos relacionados con el OLE Drag & Drop.

Una cosa que podemos advertir en todos los eventos relacionados con el OLE Drag & Drop es la
ausencia del parámetro Source que teníamos en los eventos DragDrop y DragOver del Drag&Drop
convencional. Parece normal, ya que no tenemos porque saber el nombre del control origen si éste
es de una aplicación externa (Word por ejemplo). Ese parámetro Source lo empleábamos para
saber si un control podía recibir o no la información, dependiendo del origen de la misma. En el OLE
Drag & Drop solamente podemos basarnos para eso en el tipo de información que transporta el
DataObject, tipo que podemos determinar mediante el método GetFormat.

Evento OLEStartDrag
Se produce cuando se ejecuta el método OLEDrag de un componente o cuando un componente
inicia una operación OLE de arrastrar y colocar, y su propiedad OLEDragMode está establecida a
Automatic.

Sintaxis
Private Sub objeto_OLEStartDrag(datos As DataObject, efectosPermitidos As Long)

Vemos que pasa como parámetro el objeto datos que es del tipo DataObject. Por lo tanto podemos
realizar sobre este objeto el método SetData visto anteriormente, para introducir en él los datos
deseados. Veamos un ejemplo:

Private Sub Text1_OLEStartDrag(Data As DataObject, AllowedEffects As Long)


Data.Clear
Data.SetData Text1.Text
AllowedEffects = 1
End Sub

El parámetro EfectosPermitidos va a determinar lo que ocurre con el dato en el control origen.


Acepta 3 valores:

0 vbDropEffectNone No se inicia el OLE Drag & Drop


1 vbDropEffectCopy Los datos se copian en el destino y no se modifican en el
control origen.
2 vbDropEffectMove Los datos se colocan en el destino y desaparecen del control
origen. Ocurre el efecto de mover los datos.

Evento OLEDragOver
Se produce cuando el puntero del ratón pasa por encima de un control durante una operación de
OLE Drag & Drop.

Sintaxis

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 24


Private Sub nombredelcontrol_OLEDragOver(datos As DataObject, efecto As Long, botón As
Integer, mayúsculas As Integer, x As Single, y As Single, estado As Integer)

Este evento solamente ocurre cuando la propiedad OLEDropMode está en manual

nombredelcontrol Nombre del control sobre el que pasa el puntero del ratón, en el que se
produce el evento OLEDragOver.

datos Objeto tipo DataObject que transporta los datos


efecto Este parámetro es similar al AllowedEffects del evento OLEStartDrag y
tiene los mismos valores.
boton Indica el botón que se está pulsando: 1 = izdo. 2 = Dcho. 4 = Central.
Si está pulsado más de uno, será la suma de los valores de cada uno.
mayusculas Indica el estado de pulsación de las teclas MAYUSCULAS, CTRL y ALT
1 = MAY, 2 = CTRL, 4 = ALT. Si hay más de una tecla pulsada, será
la suma de los valores de cada una.
x, y Posición del puntero del ratón dentro del control destino, medidas en las
unidades de medida del formulario.
estado Valor que indica uno de los tres estados siguientes:

0 vbEnter El ratón está entrando al control


1 vbLeave El ratón está saliendo del control
2 vbOver El ratón está dentro del control

Evento OLEDragDrop
Se produce cuando se termina la operación de OLEDrag&Drop sobre el control. Para que se pueda
terminar la operación de OLEDrag&Drop el componente destino tienen que permitirlo.

Nota Este evento sólo se produce cuando OLEDropMode está establecido a 1 (Manual).

Sintaxis

Private Sub objeto_OLEDragDrop(datos As DataObject, efecto As Long, botón As Integer,


mayúsculas As Integer, x As Single, y As Single)

En este evento podemos escribir el código necesario para que el dato se coloque de la forma
deseada (por ejemplo, puede analizar el tipo de dato y proceder de acuerdo al contenido del
DataObject).

Los parámetros pasados por este evento son iguales al del evento anterior.

Evento OLECompleteDrag
Se produce en el origen cuando se ha completado la operación de arrastre (cuando se levanta el
botón del ratón), e informa al componente de origen de que se ha completado o cancelado dicha
operación.

Sintaxis Private Sub objeto_OLECompleteDrag([efecto As Long])

Efecto es idéntico a los eventos anteriores.

En el ejemplo siguiente, el control origen (Text1) se pone rojo cuando se termina el


OLEDrag&Drop:

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 25


Private Sub Text1_OLECompleteDrag(Effect As Long)
Text1.BackColor = 255
End Sub

Evento OLEGiveFeedback
Este evento se produce en el control Origen. Se produce después de cada evento OLEDragOver.
OLEGiveFeedback permite al componente de origen proporcionar al usuario una indicación visual,
como cambiar el cursor del mouse para indicar lo que ocurrirá si coloca el objeto o señalar
visualmente la selección (en el componente de origen) para indicar lo que va a ocurrir.

Sintaxis

Private Sub objeto_OLEGiveFeedback(efecto As Long, cursoresPredeterminados As Boolean)

efecto igual a los eventos anteriores.

CursoresPredeterminados Valor booleano que determina si Visual Basic utiliza el cursor


predeterminado del mouse que indica el componente o si utiliza un cursor definido por el usuario.
True (predeterminado) = utiliza el cursor predeterminado.
False = no utiliza el cursor predeterminado. Debe haber establecido un cursor de mouse con la
propiedad MousePointer del objeto Screen.

En este capítulo hemos visto tres formas de transvasar información, bien de una aplicación a otra,
bien dentro de la misma aplicación.
Es posible que le haya llamado la atención estas herramientas. Y posiblemente piense en un
enorme número de posibilidades de aplicación. La realidad le va a demostrar que se aplican muy
pocas veces. Exceptuando el OLEDrag&Drop, que le permite exportar texto a / desde Word, y eso
le vienen muy bien al usuario porque le ahorra tiempo de teclear, los demás no se usan con la
profusión que se debería, vistas a priori las ventajas que tienen.

Como siempre en programación, lo bueno es lo que acepta y le gusta al usuario. Y el realizar un


arrastre con el ratón es una operación que no todos terminan con éxito. Quizás sea esa la razón de
no usarlo tan profusamente.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 26


LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 27
EL EDITOR DE MENUS

El Menú o Barra de Menú es la segunda línea de cualquier ventana Windows, donde pueden verse
distintos nombres. La Barra de Menú es un componente de un Formulario.

La Barra de Menú puede tener tantas palabras como se desee, y sobre cada palabra, puede
desplegarse un Menú desplegable con mas palabras. Sobre cada una de estas puede a su vez
desplegarse otro conjunto de palabras, etc. con lo que se puede conseguir una cantidad de
palabras tan grande como necesitemos.

Para cada palabra se produce el evento click. Cada palabra de la Barra de Menú lleva anexo un
único procedimiento, que se ejecutará al hacer click sobre la palabra. Pero en las palabras que
sirven para desplegar un menú no tiene sentido que se ponga ningún código en su procedimiento,
ya que están ahí justamente para desplegar otras palabras. Será en las palabras finales donde se
colocará el código correspondiente.

En las figuras anteriores pueden verse tres formas distintas de ver el mismo Menú. En la primera
figura el Menú está sin desplegar. En la segunda figura puede verse un árbol de Menú largo,
desplegado en su totalidad. En la tercera puede verse el Menú desplegable de la palabra Archivo
de la Barra de Menú. Puede apreciarse en este menú desplegable una línea que separa las
palabras Guardar Como y SALIR. Esta línea separadora es muy práctica para separar dos temas
distintos dentro de un Menú desplegable. Tan distintos como las operaciones de Abrir y Guardar
respecto a la última orden del menú desplegable que es SALIR de la aplicación.

Para crear un menú debe usarse el Editor de Menú, que se encuentra en la Barra de Menú de VB
en Herramientas | Editor de menús. Le aparecerá el siguiente cuadro. (En principio vacío)

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 28


Cada palabra del menú tiene su Caption (La palabra que aparece en el menú), su Name
(Nombre), y puede tener Index (si existen varias palabras con el mismo Name). Para introducir
estas propiedades basta con teclearlas directamente en cada una de las casillas al efecto del
cuadro del editor de menús. Para colocar el cursor de escritura en una u otra casilla, puede
hacerse bien con el cursor del ratón, bien con el tabulador. Para pasar a la siguiente línea de
edición (crear una nueva palabra), basta con pulsar ENTER.

Existen otras propiedades aparte del Caption y Name que se introducen directamente en las
casillas al efecto.

HelpContextID Igual que esta propiedad en el resto de los controles, permite introducir un número
de contexto para la ayuda de Windows.

Enabled. Habilitado. Si se quita la marca de esa casilla, esa palabra aparecerá por defecto
deshabilitada. Esta propiedad puede leerse y cambiarse en tiempo de ejecución, por lo que esta
propiedad puede usarse para deshabilitar ciertas funciones de la aplicación, dependiendo de la
evolución de la propia aplicación. La presentación en el menú cuando está deshabilitada es con
color pálido.

Visible. Como su nombre indica, que sea visible o no lo sea. Puede cambiarse en tiempo
de ejecución.

WindowList Indica si esa palabra es la que va a mostrar todos los formularios abiertos en una
aplicación de documentos múltiples (MDI). Al hacer click sobre esta palabra, se desplegará un
submenú con todos los Caption de los Formularios hijo abiertos en ese momento. Solamente
puede existir una palabra en un menú con esta propiedad activada. Esta propiedad no puede
variarse en tiempo de ejecución.

Para cambiar una de estas propiedades en tiempo de ejecución, basta con citar por su nombre a
esa palabra (por su Name, no por su Caption), e igualar a True o False su valor :

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 29


nmuDocumentos.Visible = False

El nombre usado para nombrar a una de las palabras del menú puede ser cualquiera. Sin embargo
es prudente usar un nombre que nos pueda identificar, por una parte, que ese nombre corresponde
a una de las palabras del menú, y por otra, a que palabra se refiere. La solución puede ser
cualquiera. El autor de estos apuntes propone poner las letras mnu (o menu - recomiendo no usar
acentos e los Names de VB), seguido del Caption de esa palabra.

Otras propiedades

Shortcut Atajo. Esta propiedad admite varias combinaciones de teclas para acceder al
procedimiento click de esa palabra sin necesidad de usar el ratón. Las combinaciones de teclas
posibles se muestran haciendo click en la flecha hacia abajo que tiene esa casilla. Se desplegará
una lista con todas ellas. Para elegir una de estas combinaciones, basta con hacer click sobre la
línea que la contiene. Esta combinación de teclas aparecerá en el menú, al lado de la palabra
(Véase figura siguiente, SALIR Ctrl + X)

NegotiatePosition. Establece un valor que determina si los controles Menu de nivel superior
se muestran en la barra de menús mientras un objeto vinculado o incrustado de un formulario está
activo y mostrando sus menús. No está disponible en tiempo de ejecución. Puede tener los valores
0 (Predeterminado) Ninguno. El menú no se muestra en la barra de menús cuando el objeto está
activo.
1 Izquierda. El menú se muestra a la izquierda de la barra de menús cuando el objeto está activo.
2 Medio. El menú se muestra en medio de la barra de menús cuando el objeto está activo.
3 Derecha. El menú se muestra a la derecha de la barra de menús cuando el objeto está activo.

El menú editado con los datos de la figura anterior tendrá esta forma en tiempo de ejecución :

Observe que tiene cuatro palabras en la línea superior, y que “colgando” de la primera aparece un
menú desplegable. Para conseguir un menú desplegable fíjese en la figura del Editor, en la parte
de abajo donde están todos los Caption de las palabras del menú. Observará que algunas de ellas
(&Edicion, Documentos, Ayuda - Hay otra que no se vé, &Archivo) están completamente a la
izquierda de la ventana, y las demás están separadas de la parte izquierda por unos guiones. Las
palabras que están completamente a la izquierda son las que figurarán en la barra de menú de
forma permanente. Las que están separadas (tabuladas) corresponden a las que aparecerán en
los menús desplegables. Como es lógico, un menú desplegable debe colgar de una palabra de las
de la barra de menú. La palabra de la que cuelga el submenú es la palabra sin tabular
inmediatamente anterior.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 30


Para tabular las palabras, hay que hacer click en el botón en forma de flecha a la derecha que está
sobre la ventana de edición:

Situandonos sobre una de las líneas ya editadas, y haciendo click sobre el botón con flecha hacia
la izquierda, quitamos la tabulación.

Los botones con flecha hacia arriba o abajo nos permiten variar el orden de las líneas ya editadas.

Podemos hacer varios niveles de submenús a base de introducir varias tabulaciones. Al comienzo
de este capítulo puede ver un ejemplo de ello.

Quedan un par de cosas. Una de ellas es el carácter & que está delante de los Caption de Archivo
y Edición. Este carácter nos permite acceder al procedimiento click de esa palabra pulsando la
tecla Alt + la tecla correspondiente a la letra que está detrás del carácter &. Justamente la letra
que está subrayada en la palabra del menú.

El carácter & no tiene porqué ir precisamente al comienzo de la palabra. Puede ir en el medio de la


palabra. De esta forma se subrayará una letra intermedia.

Otra cosa. Puede verse en el menú desplegado de la figura anterior una línea entre Guardar Como
y SALIR. Esta línea, que solamente tiene efectos estéticos, se logra introduciendo como Caption
un guión ( - ). El editor de menús solamente le permite el guión en una palabra de menú
desplegable (Tabulada). No se olvide de poner el Name incluso para este guión.

NOTA MUY IMPORTANTE

Siempre se recomienda poner la orden de SALIR en la primera palabra de la barra de Menú. Bien
que esa primera palabra sea Salir o que esté en el menú desplegable de la primera palabra de la
Barra de Menú, en este último caso, separada mediante una línea separadora. (Vea The Windows
Interface Guidelines for Software Design, pág.124)

POPUP MENÚS

Un PopUpMenú o Menú Emergente es un menú que despliega en cualquier punto de un Formulario


(MDI o normal) con varias opciones. Es normal en los procesadores de texto que se obtenga un
menú emergente pulsando el botón derecho del ratón, donde aparecen las tres palabras mágicas
de Copiar, Cortar y Pegar.

Para crear un menú emergente o PopUpMenu es necesario tener en el menú de ese formulario
una palabra de la que se despliegue un submenú con las mismas palabras que queremos que
aparezcan en el PopUpMenu.

Por ejemplo, en el menú que hemos editado como ejemplo anteriormente, existía una palabra
Edición, de la que se desplegaba el Submenú Copiar, Cortar y Pegar. Si analizamos la edición
realizada, las palabras tenían el siguiente Caption y Name :

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 31


Caption Name Tabulada

Edición mnuEdicion NO
Copiar mnuCopiar SI
Cortar mnuCortar SI
Pegar mnuPegar SI

Recuerde que las palabras del menú que estaban tabuladas son las que aparecían en el menú
desplegable. Esas mismas serán las que aparezcan en el PopUpMenu.

Para ello utilizaremos el Método PopupMenu. Este método pesenta un menú emergente en un
objeto MDIForm o Form en la posición actual del mouse o en las coordenadas especificadas.

La sintaxis de este método es la siguiente :

NombreFormulario.PopupMenu nombremenú, indics, x, y, negrita

Donde NombreFormulario es el nombre del formulario donde presentamos el PopUpMenu. Puede


omitirse.

Nombremenú. Este parámetro es requerido. Es el Name de la palabra del menú de donde cuelga
el menú desplegable. La palabra del menú a que se refiere Nombremenú debe tener al menos un
submenú.

Indics. Parámetro opcional. Un valor o constante que especifica la posición y el comportamiento del
menú emergente, como se describe a continuación :

Constante (posición) Valor Descripción

vbPopupMenuLeftAlign 0 (Predeterminado) El lado izquierdo del menú se


sitúa en x.
vbPopupMenuCenterAlign 4 El menú emergente se centra en x.
vbPopupMenuRightAlign 8 El lado derecho del menú se sitúa en x.

Constante (comportamiento) Valor Descripción

vbPopupMenuLeftButton 0 (Predeterminado) Los elementos del


menú emergente sólo reaccionan a los
clic del mouse cuando se use el botón
primario del mouse.
vbPopupMenuRightButton 2 Los elementos del menú emergente
reaccionan a los clic del mouse cuando se
usen los botones primario o secundario.

Para combinar la los valores de indics de posición y comportamiento basta con sumar los valores.

Nota El parámetro indics no tiene efecto en las aplicaciones que se ejecuten bajo Microsoft
Windows versión 3.0 o anteriores.

X, y Parámetro(s) opcionales que especifican las coordenadas x e y donde va a aparecer el menú


emergente. Si no se especifican, aparecerá donde esté el puntero del mouse. Las unidades de
medida de las coordenadas x e y se definen mediante la propiedad ScaleMode.

negrita. Parámetro opcional que especifica el nombre de un control menú del menú emergente
para presentar su título en negrita. Si se omite, ningún control del menú aparece en negrita.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 32


Nota. Este argumento funciona solamente en las aplicaciones que se ejecuten bajo Windows 95.
La aplicación ignora este argumento cuando se ejecute bajo versiones de 16 bits de Windows o
Windows NT 3.51 y anteriores.

La forma mas habitual de presentar un menú emergente es mediante el botón derecho del ratón.
Concretamente en el editor Word que estoy utilizando para escribir estos apuntes ocurre cuando se
levanta el botón derecho del ratón. Es decir, en el evento MouseUp, con la condición de que
Button=2. Imaginemos que queremos presentar en un menú emergente las palabras Cortar, Copiar
y Pegar del ejemplo anterior, que colgaban en el menú de la palabra Edición. (Vea mas atrás).
Queremos también que la palabra Copiar salga resaltada en negrita. Iríamos al procedimiento
MouseUp del Formulario y escribiríamos :

Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)


If Button = 2 Then
PopupMenu mnuEdicion, , , , mnuCopiar
End If
End Sub

Observe que se ha omitido el nombre del Formulario (Opcional), el parámetro indics, y las
coordenadas x e y (el menú emergente aparecerá donde esté situado el cursor del ratón). Observe
también que las comas separadoras de los parámetros hay que colocarlas.

Cuando se presenta un menú emergente, el código que sigue a la llamada al método PopupMenu
no se ejecuta hasta que el usuario elige un comando del menú (en cuyo caso se ejecuta antes el
código del procedimiento de evento Click) o cancela el menú. Además, sólo puede presentarse un
menú emergente al mismo tiempo; por lo tanto, las llamadas a este método se ignoran si el menú
emergente está presentado actualmente o si un menú desplegable está abierto.

Si queremos presentar un menú emergente es necesario tener ese menú en el menú del
formulario. El problema puede ser que no queramos que esté en la barra de menú. No es
problema. Ponga la propiedad Visible del elemento del menú desde el que se va a desplegar el
submenú a False. No se verá ya en la barra de menú ni esa palabra ni el submenú que de ella se
despliega. Eso sí, las palabras del submenú deben tener la propiedad Visible = True. Si les pone
esa propiedad a False, no se verán en el menú emergente. Puede aprovechar esta circunstancia
para hacer menús emergentes con mas o menos elementos, según las necesidades de su
aplicación. También puede poner la propiedad Enabled a False si así lo precisa. No puede activar
la propiedad WindowList en un elemento que forma parte de un menú emergente.

Ejercicio propuesto: un editor de texto, con un menú que diga Copiar | Cortar | Pegar donde pueda
utilizar el portapapeles. Ahora es posible que le cueste un poco de trabajo. Pero este ejercicio lo va
a repetir con casi todas las aplicaciones que realice en su vida profesional.

LSB Visual Basic - Guia del Estudiante Capitulo 5 Página 33


Visual Basic - Guía del Estudiante Cap. 6
FICHEROS EN VISUAL BASIC

Existen tres tipos de ficheros donde podremos almacenar y leer datos:

- Secuenciales
- Aleatorios (Random)
- Binarios

Cada uno de ellos tiene sus aplicaciones y particularidades.

FICHEROS SECUENCIALES

Este tipo de ficheros nos permite guardar información de cualquier longitud. En este tipo de
ficheros, la información se guarda colocando un carácter tras otro. La forma de leerlos es,
igualmente, carácter tras carácter. (Byte tras byte). Son los mas sencillos de manejar, y los
utilizados para guardar texto en ASCII. Permiten guardar datos en un fichero con un determinado
nombre, "machacando" la información de otro posible fichero que ya estuviese en el disco con el
mismo nombre, o añadir la información nueva a continuación de la ya existente.

Para abrir un fichero secuencial para guardar información, debemos ejecutar la siguiente
instrucción:

Open Nombrefichero For Output As # Numerocanal

De esta forma, si ya existía un fichero llamado Nombrefichero, sobreescribiremos dicho fichero


perdiendo la información que contuviese. Es la forma típica de hacerlo cuando modificamos un
texto. Para añadir la nueva información tras la ya existente, deberemos abrirlo con la siguiente
instrucción:

Open Nombrefichero For Append As # Numerocanal

Numerocanal debe ser un número comprendido entre 1 y 255. Representa el número del canal por
donde introduciremos los datos. Normalmente se llama también número de archivo. No puede
haber mas de un archivo abierto con un número de canal determinado.

Para cerrar un fichero secuencial, basta con ejecutar la instrucción:

Close # Numerocanal

Si no se especifica Numerocanal (la instrucción Close a secas) se cerrarán todos los ficheros
abiertos actualmente.

Para introducir la información, pueden emplearse dos métodos: Print y Write Nos centraremos
de momento solamente en Print.

Print
Introduce la información de forma secuencial, byte tras byte tal como se comentó.
Sirve para guardar textos. Por ejemplo si deseamos guardar en ese fichero el
contenido de una caja de texto llamada Text1, basta con ejecutar la siguiente
instrucción:

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 1


Print #NumerodeCanal, Text1.Text

El texto queda en el fichero en caracteres ASCII, que se pueden leer con el Bloc de
Notas.

Cuando los datos se han introducido con la instrucción Print, la forma de acceder a ese texto es
muy sencilla:

Se abre el archivo con la instrucción Open

Open Nombrefichero For Input As # Numerodecanal

Se utiliza la instrucción Input o Line Input para sacar los datos del fichero.

La instrucción Input tiene en este caso la siguiente sintaxis:

VariableString = Input (Numero de caracteres, # Numero de canal)

Por ejemplo, VariableString = Input (1, #1) extrae un carácter del fichero abierto como #1. El
número máximo de caracteres a extraer de un golpe mediante la instrucción Input está limitado a
65.534.

Verá un poco mas adelante la propiedad LOF de los ficheros secuenciales. LOF devuelve un valor
igual a la longitud total del fichero. Si ejecutamos la instrucción :

Para no emplear una palabra tan larga como Numerodecanal, utilizaremos de ahora en adelante el
número 1 como número de canal. Recuerde que ese número puede ser un número comprendido
entre el 1 y el 255

VariableString = Input (LOF(1), #1) LOF(1)=longitud del fichero #1

leeremos el fichero de una única vez. Este procedimiento puede ahorrarle cierto tiempo a la hora de
la lectura. (Por lo dicho anteriormente, este procedimiento de leer todo el fichero de un golpe
solamente se podrá hacer si la longitud del fichero (LOF(1)) es inferior a 65.534 bytes. Tenga esto
presente cuando vaya a leer un fichero que no sabe que longitud tiene. Para curarse en salud, le
recomiendo que lea los ficheros secuenciales carácter a carácter. Input(1,#X) pues tarda poco
mas que leyéndolo de un golpe. Claro que para leer un fichero carácter a carácter debe poner un
bucle en el que se van leyendo los caracteres hasta que llaga al final del fichero..

La forma de hacer este bucle es la siguiente:

Dim A As String A es la variable donde meteremos el carácter que extraemos del fichero.
Dim MiVariable as String MiVariable es una variable tipo string donde vamos a meter todo el
contenido del fichero

Do Until EOF(1) El programa ejecutará este bucle hasta que se cumpla que EOF(1) sea
True. EOF(NumerodeCanal) es una propiedad de los ficheros cuando
están abiertos, que es True cuando la posición del puntero de lectura
apunta al carácter Fin De Fichero (End Of File) que es el carácter siguiente
al último carácter de texto de ese fichero.

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 2


A = Input (1, #1) Estrae un carácter del fichero abierto por el canal número 1. Al leer este
carácter, el puntero de lectura avanza automáticamente tantos caracteres
como haya leído, colocándose sobre el primer carácter no leído.

MiVariable = MiVariable & A Con esta línea vamos anexando el carácter leído a la variable
MiVariable. En vez de utilizar una variable, podríamos poner ese
texto sobre un TextoBox o un RichTextBox (RTB) (Lo verá
proximamente). Si lo ponemos en un RTB esta línea sería:
RTB.SelText = A

Loop Vuelve al comienzo del bucle.

Close #1 Cierra el fichero

Sólo se utilizará la instrucción Input con archivos abiertos en modo Input o Binary. (Los Binary Se
verán a continuación) A diferencia de la instrucción Input #, (la veremos a continuación, pues es la
instrucción que deberá utilizar para leer archivos escritos con la instrucción Write ), Input devuelve
todos los caracteres que lee, incluyendo puntos y coma, retornos de carro, avances de línea,
comillas y espacios iniciales.

Existe una instrucción, Input$ , que asume que el dato a leer es un String. (Cadena de caracteres).
Puede ahorrar un poco de memoria usando esta instrucción en lugar de Input.

Nota Se proporciona otra función (InputB) para su uso con datos de byte incluidos en archivos de
texto. En lugar de especificar el número de caracteres a devolver, número especifica el número de
bytes.

INSTRUCCION LINE INPUT

La instrucción Line Input se utiliza para extraer una línea completa. Tiene la siguiente
sintaxis:

Line Input # Número de canal, VariableString

Mediante esta instrucción se extrae una línea completa (los caracteres delimitados entre dos
retornos de carro), y se le asigna esa cadena a VariableString

Una línea es un trozo de texto delimitado por los caracteres 13 (Retorno de carro) y 10 (Avance de
línea) La instrucción Line Input # lee un carácter cada vez en un archivo hasta que encuentra un
retorno de carro (Chr(13)) o una secuencia retorno de carro - avance de línea (Chr(13) + Chr(10)).
Las secuencias de retorno de carro - avance de línea no se tienen en cuenta y no se añaden a la
cadena de caracteres extraída mediante esta instrucción. Cuando lea un archivo mediante Line
Input # y lo quiere presentar en un TextBox o en el Printer, deberá introducirlos para evitar que le
salga todo el texto en una única línea.

Con lo que se ha explicado, ya puede realizar un pequeño edito de textos. Este sencillo editor tiene
un TextBox llamado TBTexto, donde podemos escribir el texto que queramos (con la propiedad
MultiLine = True y ScrollBars = Vertical), tres botones llamados BAbrir (1), (2 a y b) y (3), para abrir
el fichero y poner su contenido en TBTexto, y dos BGuardar para guardar, uno abriendo el fichero
For Append y el otro abriéndolo For Output. En este último, al guardar el texto borramos el
contenido que del fichero, si ya existiera. En el primero, lo anexamos al final del mismo . Para
conocer el nombre del fichero, ponemos un CommonDialog llamado CD1, con un filtro CD1.Filter =
“Ficheros de Texto |*.txt”

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 3


Para abrir el fichero, y depositar su contenido en TBTexto pondremos este código en BAbrir :

Private Sub BAbrir1_Click()


Dim VarTexto As String
CD1.Filter = "Ficheros de Texto |*.txt"
CD1.ShowOpen
Open CD1.filename For Input As #1
VarTexto = Input(LOF(1), #1) 'leemos todo el fichero de un golpe
Close #1
TBTexto = VarTexto
End Sub

Cuando el fichero es mayor de 64 kilobytes, el leerlo de un golpe puede dar problemas. Mejor
dicho, no funciona. Deberemos leerlo en ese caso, carácter a carácter o línea a línea.

Para leer carácter a carácter :

Private Sub BAbrir_Click()


Dim VarTexto As String
CD1.Filter = "Ficheros de Texto |*.txt"
CD1.ShowOpen
Open CD1.filename For Input As #1
Do Until EOF(1) ‘Hacemos un bucle de lectura hasta que encontremos EOF(1)
‘ Vea mas adelante la Propiedad EOF en Propiedades de los ficheros Secuenciales
VarTexto = Input(1, #1) 'leemos el fichero carácter a carácter
TBTexto = TBTexto & VarTexto 'vamos añadiendo los caracteres leídos a TBTexto
Loop
Close #1
End Sub

(NOTA.- Lo expuesto funciona perfectamente, pero el hecho de meter en un TextBox carácter a


carácter eterniza la aplicación. - Meter un texto en un TextBox o en un Label es una operación que
tarda cierto tiempo. Si esa operación hay que hacerla una vez por carácter, puede tardar mucho
tiempo. Para evitar esto, cuando vaya a leer un fichero carácter a carácter, métalo primero en una
variable y luego realice un volcado único de esa variable al TextBox o Label)

Y podemos hacerlo también leyendo línea a línea con Line Input

Dim VarTexto As String


CD1.Filter = "Ficheros de Texto |*.txt"
CD1.ShowOpen
Open CD1.filename For Input As #1
Do Until EOF(1)
Line Input #1, VarTexto 'leemos el fichero Línea a Línea
TBTexto = TBTexto & VarTexto & vbCrLf 'vamos añadiendo las líneas leídas a TBTexto
'(Hay que introducir un retorno + avance de línea con cada línea (vbCrLf), ya que VarTexto no
‘contiene los retornos ni avances de línea.
Loop
Close #1

Los Botones de Guardar tienen el código :

Private Sub BGuardar_Click()


Dim VarTexto As String
LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 4
CD1.Filter = "Ficheros de Texto |*.txt"
CD1.ShowSave
Open CD1.filename For Output As #1
Print #1, TBTexto.Text
Close #1
End Sub

O para el caso de abrir con For Append

Private Sub BGuardar2_Click()


Dim VarTexto As String
CD1.Filter = "Ficheros de Texto |*.txt"
CD1.ShowSave
Open CD1.filename For Append As #1
Print #1, TBTexto.Text
Close #1
End Sub

Ya hemos visto como se guardan y se leen datos de texto en un fichero secuencial.

INSTRUCCIÓN WRITE

La otra forma de introducir datos en un fichero secuencial es Write. Mediante esta instrucción, no
se puede introducir texto, sino datos, aunque esos datos sean de texto. Mediante la instrucción
Write puede crear una pequeña base de datos. Eso sí, una base de datos de escasa calidad. Pero
no es momento de cuestionar la calidad de esta base de datos, sino de explicarla.

Write
Puede introducir varias informaciones, que posteriormente se podrán leer de forma
separada con la instrucción Input #. Esta forma de introducir datos en un fichero
secuencial permite realizar un fichero con distintos datos que se pueden leer en el
propio fichero, puesto que se guardan en ASCII, y leerlos mediante el programa de
una forma muy sencilla. Hacemos, en realidad, una pequeña base de datos. (Verá
a lo largo de su vida profesional que lo de pequeña no es cierto, pues es la forma
mas sencilla de guardar datos cuando la cantidad de estos datos no es muy
grande)

Lo que estamos haciendo en realidad al escribir datos mediante la instrucción Write es escribir
estos datos en un fichero secuencial, utilizando una coma como separador entre los distintos datos.
Un fichero secuencial con datos introducidos mediante la instrucción Write tendrá esta forma :

“Luis Suárez”,” VisualBasic - Guía del estudiante”,”Editorial XX”,”3200”,”51”


“Miguel de Cervantes”,”El Qijote”,”Editorial YY”,”5000”,”27”

Observe que el contenido de este fichero se diferencia algo de una simple sucesión de caracteres.
Tiene varias partes separadas por una coma. Cada una de ellas es un dato.

Imaginemos una aplicación, con la que introducimos datos de libros. La aplicación es un único
formulario donde podemos introducir la información mediante varios TextBox. Existe un Botón de
comando con el siguiente código:

Private Sub Command1_Click()


TITULO = LIBRETBTITULO.Text
AUTOR = LIBRETBAUTOR.Text
LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 5
EDITORIAL = LIBRETBEDITORIAL.Text
PRECIO = LIBRETBPREC.Text
EXISTENCIAS = LIBRETBEX.Text

‘Donde LIBRETBTITULO, LIBRETBAUTOR, Etc. son los nombres de los TextBox


‘Ha leído los datos de los TextBox. Ya están el las variables TITULO, AUTOR, Etc.
‘Ahora los metemos en el fichero con la instrucción Write. El nombre del fichero será el
‘que hayamos puesto en el TextBox LIBRETBFICHERO, y lo guardará en el directorio
‘C :\cursoVB

Open TBNombreFichero.Text For Append As #1


Write #1, TITULO, AUTOR, EDITORIAL, PRECIO, EXISTENCIAS
Close #1
End Sub

Si introduce los datos del ejemplo anterior, se creará un fichero que tiene esta apariencia:

“Luis Suárez”,” VisualBasic - Guía del estudiante”,”Editorial XX”,”3200”,”51”

Si realizamos otra introducción de datos, con la segunda línea del ejemplo anterior, los datos
existentes en ese fichero no se borrarán, dado que lo hemos abierto con Append. Quedará de la
siguiente forma:

“Luis Suárez”,” VisualBasic - Guía del estudiante”,”Editorial XX”,”3200”,”51”


“Miguel de Cervantes”,”El Qijote”,”Editorial YY”,”5000”,”27”

¿Que pasaría si leemos este fichero con la instrucción Input o Line Input # vista anteriormente ?
Pues simplemente que lo leeríamos tal como está, con sus comas y comillas dobles. No sería la
forma mas adecuada, ya que lo que queremos es obtener sucesivos datos de autores, títulos,
editoriales, precios y existencias.

Para sacar estos datos debemos leerlos con la instrucción Input #. Esta instrucción saca los datos
que hemos metido, es decir, elimina las comillas y la coma que servían de separadores.

En nuestro ejemplo, podríamos hacerlo de esta forma, aprovechando los mismos TextBox:

Private Sub Command2_Click()


' Limpiamos los TextBox
LIBRETBTITULO.Text = "" : LIBRETBAUTOR.Text = "" : LIBRETBEDITORIAL.Text = ""
LIBRETBPREC.Text = "" : LIBRETBEX.Text = ""

'Abrimos el fichero

Open TBNombreFichero.Text For Input As #1


Do Until EOF(1)

' Introducimos una parada para poder leer datos


DETENERSE = True
Input #1, TIT, AUT, NED, PRE, EXS

LIBRETBTITULO.Text = TIT
LIBRETBAUTOR.Text = AUT
LIBRETBEDITORIAL.Text = NED
LIBRETBPREC.Text = PRE
LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 6
LIBRETBEX.Text = EXS
' Refrescamos los TextBox
Refresh

' Esto produce una pequeña parada


Do While DETENERSE = True
A=A+1
If A = 100000 Then DETENERSE = False: A = 0
Loop
' terminó la parada y vuelve a leer datos

Loop
Close #1

End Sub

Observe que los nombre de las variables en el proceso de lectura tienen distintos nombres a los
utilizados durante la escritura. Como en el fichero no se guarda ninguna referencia al respecto, lo
único que importa es que el número de variables para la lectura sea igual al número de variables
que se utilizó para la escritura, y que el orden de las variables sea correcto. Si por ejemplo, el
número de variables usadas en la introducción de datos fuese distinto al número de variables usado
en la lectura, Visual Basic nos daría un error.

Observe también que se ha introducido un temporizador. Sirve para ver los sucesivos títulos que
tenemos en nuestra base de datos tan sui generis. Se ha pretendido presentar unos datos de esta
pequeña base de datos sin complicarnos mucho la vida. Mas adelante veremos como presentarlos
de una forma correcta. Este tipo de ficheros no es el mas adecuado para construir bases de datos,
es complicado manejar ficheros de mas de unas pocas líneas, por lo que para tener muchos datos,
este tipo de ficheros no es recomendable. No es aconsejable ni para muchos datos ni para pocos
datos. Pero es obligación del autor explicarlo … y de advertirlo.

En esta pequeña aplicación mostrábamos las informaciones sucesivamente según las íbamos
leyendo del fichero. Interrumpíamos momentáneamente la lectura para presentar cada información
durante un instante, ya que como tenemos cinco datos distintos en cada registro y cinco TextBox
para presentarlos, deberemos presentar una información tras otra. Esto no parece en principio una
solución práctica para una base de datos, donde lo que interesa es disponer de todos los datos
para usarlos cuando sea necesario. Esto nos lleva a crear una matriz para albergar todos los datos
de la base, ya que los ficheros secuenciales se leen y se les tiene que extraer toda la información
de un golpe, ya que no permiten ir a leer hacia atrás. Por lo tanto, si deseamos disponer de todos
los datos, deberemos guardarlos en la memoria, en una matriz. Imagínese que estamos tratando
datos de varios miles de libros en el ejemplo anterior. Si la información de cada campo es
medianamente extensa, no tendríamos memoria RAM suficiente en el ordenador para albergarlos.
Esto nos lleva a pensar en otro tipo de archivo que veremos a continuación, los Random
(aleatorios), que permiten leer solamente los registros que nos interesan.

Pero volvamos a nuestra aplicación de librería, donde hemos hecho una variación, los campos
PRECIO y EXISTENCIAS los vamos a tratar ahora como números (Integer). También se ha
introducido otro campo tipo texto, para introducir la edición. El fichero creado tras introducir varios
libros quedó de la siguiente forma :

"EL RODABALLO","GUNTER GRASS","PLANETA",”1995”,2000,12


" VisualBasic - Guía del Estudiante ","LUIS SUAREZ","CEU",”PRIMERA”,1000,21
"EL NOMBRE DE LA ROSA","UMBERTO ECO","AGUILAR",”28”,1000,21
"ENCICLOPEDIA DEL VB","CEBALLOS","RAMA",”CUARTA”,1200,23
LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 7
"LA GRANJA ANIMAL","ORWELL","DESTINO",”45”,12000,78
"LA PASION TURCA","ANTONIO GALA","PLANETA",”SEGUNDA”,2500,25
"LA METAMORFOSIS","KAFKA","PLAZA&JANES", “4ª”,3400,101
"VB4 PARA WINDOWS95","GARY CORNELL","MCGRAWHILL",”1ª”,6500,25

Observe que los dos últimos campos (correspondientes a PRECIO y EXISTENCIAS) no están entre
comillas, pues no se trata de texto, sino de números.

(Observe también la gran ventaja de tener una base de datos con datos completamente legibles)

Se han introducido alguna variaciones en el programa. Entre ellas, se crea una matriz de variables
de 5 x n (n=número de registros). También se le añaden unos botones para poder recorre toda la
base de datos.

La interfaz gráfica quedó de la siguiente forma :

El programa necesita que le introduzcamos el nombre del fichero que alberga la base de datos. Por
sencillez no se ha usado ningún CommonDialog y se introduce directamente el nombre de este
fichero en un TextBox llamado TBNombreFichero

El fichero anterior podemos leerlo tal y como indicábamos antes :

Open TBNombreFichero.Text For Input As #1


Do Until EOF(1)
Input #1, TITULO, AUTOR, EDITORIAL, EDICION, PRECIO, EXISTENCIAS

Donde las variables TITULO, AUTOR, EDITORIAL y EDICION serán del tipo String y PRECIO y
EXISTENCIAS serán de tipo numérico. Podemos saberlo, ya que en una línea cualquiera del
fichero anterior :

" VisualBasic - Guía del Estudiante ","LUIS SUAREZ","CEU",”PRIMERA”,1000,21

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 8


los cuatro primeros parámetros van entre comillas dobles, ya que son datos tipo texto, y los dos
últimos van sin comillas, como corresponde a datos numéricos.

Pero existe otra forma mejor (al menos un poco mas complicada) para leer estos datos, y evitar el
problema que teníamos antes de tener que hacer un temporizador para poder ver, aunque solo sea
un momento, los datos. Podemos meter los datos a una matriz que tenga tantas columnas como
datos (campos) (en el ejemplo 6, cuatro String y dos numéricos), y tantas filas como apuntes
(registros) tengamos.

Para ello, antes de nada debemos definir un tipo de variable, mediante la instrucción Type. Parece
que no nos basta con los tipos de variable que trae VB (Long, String, Integer ...) y es cierto. La
variable que necesitamos no es de ningún tipo de esos. Está compuesta por varias secciones, y
cada una de ellas puede ser de un tipo distinto. Este tipo de definiciones debe hacerse en un
módulo (Véase instrucción Type en la ayuda de VB), por lo que se ha creado un módulo llamado
LIBREMD2.BAS, con el siguiente código :

Type REGISTROLIBRO
AUTOR As String
TITULO As String
EDITORIAL As String
EDICION As String
PRECIO As Integer
EXISTENCIAS As Integer
End Type

Esto es lo que se llama DEFINIR una variable. Es como hacerse un traje a medida. Y dese cuenta
de que es un tipo de variable (REGISTROLIBRO) formado por varias partes (AUTOR, TITULO,
Etc.) Observe que DEFINIR una variable NO es lo mismo que DECLARAR

En el apartado de Declaraciones del General del formulario declaramos las variables, entre ellas
una variable, REGISTROLIBROS, de la cual decimos que va a ser una matriz mediante los
paréntesis que la acompañan, y además declaramos que va a se similar a REGISTROLIBRO ya
definida en el módulo.

Dim NR As Integer
Dim REGISTROLIBROS() As REGISTROLIBRO
Dim NRP As Integer

Observe que al usar paréntesis al declarar la variable REGISTROLIBROS le estamos diciendo a


VB que esa variable será un Array, y además que es una variable del tipo REGISTROLIBRO, tipo
de variable que ya conoce, puesto que se la hemos definido en un módulo.

En el ejemplo preparado podemos escribir y leer datos. Veamos de nuevo como se escriben
El código del procedimiento click del botón BIntroducir1 es :

Private Sub BIntroducir1_Click()


TITULO = LIBRETBTITULO.Text ‘TextBox para introducir el título
AUTOR = LIBRETBAUTOR.Text ‘ autor
EDITORIAL = LIBRETBEDITORIAL.Text ‘ editorial
EDICION = LIBRETBEDICION.Text ‘ edición
PRECIO = Val(LIBRETBPREC.Text) ‘ precio
EXISTENCIAS = Val(LIBRETBEX.Text) ‘ existencias

‘(Observe que para introducir el precio y las existencias se transformó el contenido del TextBox a
LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 9
‘un valor numérico mediante la instrucción Val.)

Open "C:\cursoVB\" + LIBRETBFICHERO.Text For Append As #1


Write #1, TITULO, AUTOR, EDITORIAL, EDICION, PRECIO, EXISTENCIAS
Close #1
End Sub

Tras reiteradas entradas, el fichero de la BD quedó como se vio anteriormente.

Al leer los datos, lo primero es que no conocemos el número de registros existentes. Como cada
registro va en una línea del fichero, si contamos el número de retornos de carro (Chr(13))
obtendremos el número de registros. Esta operación es la primera que se realiza en el
procedimiento click del botón LEER :

Private Sub Command2_Click()

LIBRETBTITULO.Text = "" ‘Pone todos los TextBox en blanco


LIBRETBAUTOR.Text = ""
LIBRETBEDITORIAL.Text = ""
LIBRETBEDICION.Text = ""
LIBRETBPREC.Text = ""
LIBRETBEX.Text = ""
NR = 0 ‘ NR=número de registros

‘ Abre el fichero, lo lee entero y cuenta el número de retornos de carro. Existirán tantos apuntes
(registros) como retornos de carro existan, ya que cada registro ocupa una línea.

Open TBNombreFichero.Text For Input As #1


Do Until EOF(1)
A = Input(1, #1)
If A = Chr(13) Then NR = NR + 1
Loop
Close #1

‘ Presenta en LNumFich el número de registros

LNumFich.Caption = Str(NR) + " Registros)"

'Redimensionamos la matriz de REGISTROLIBROS a NR elementos..


ReDim REGISTROLIBROS(1 To NR)

‘Volvemos a abrir el fichero


Open TBNombreFichero.Text For Input As #1

‘Leemos los registros del 1 al NR, y cada campo del fichero lo vamos asignando a los elementos
‘que componen la matriz.

For I = 1 To NR
Input #1, REGISTROLIBROS(I).TITULO
Input #1, REGISTROLIBROS(I).AUTOR
Input #1, REGISTROLIBROS(I).EDITORIAL
Input #1, REGISTROLIBROS(I).EDICION
Input #1, REGISTROLIBROS(I).PRECIO
Input #1, REGISTROLIBROS(I).EXISTENCIAS
LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 10
Next I
Close #1

NOTA.- Estas líneas podríamos heberlas puesto en una línea única :


Input#1,REGISTROLIBROS(I).TITULO,REGISTROLIBROS(I).AUTOR,_
REGISTROLIBROS(I).EDITORIAL,REGISTROLIBROS(I).EDICION,_
REGISTROLIBROS(I).PRECIO, REGISTROLIBROS(I).EXISTENCIAS

‘NRP = Número del Registro Presentado. Lo hacemos igual a 1 para presentar, de momento, el
‘número 1

NRP = 1

LIBRETBTITULO.Text = REGISTROLIBROS(NRP).TITULO
LIBRETBAUTOR.Text = REGISTROLIBROS(NRP).AUTOR
LIBRETBEDITORIAL.Text = REGISTROLIBROS(NRP).EDITORIAL
LIBRETBEDICION.Text = REGISTROLIBROS(NRP).EDICION
LIBRETBPREC.Text = REGISTROLIBROS(NRP).PRECIO
LIBRETBEX.Text = REGISTROLIBROS(NRP).EXISTENCIAS

End Sub

Copiamos este código de presentación de datos y lo llevamos a las flechas de incrementar o


disminuir el número del registro a presentar.

Private Sub BMas1_Click()


NRP = NRP + 1
If NRP > NR Then ‘protegemos que salga error de NRP fuera de intervalo
MsgBox "No existen mas registros en esta dirección"
NRP = NR
Else
LIBRETBTITULO.Text = REGISTROLIBROS(NRP).TITULO
LIBRETBAUTOR.Text = REGISTROLIBROS(NRP).AUTOR
LIBRETBEDITORIAL.Text = REGISTROLIBROS(NRP).EDITORIAL
LIBRETBEDICION.Text = REGISTROLIBROS(NRP).EDICION
LIBRETBPREC.Text = REGISTROLIBROS(NRP).PRECIO
LIBRETBEX.Text = REGISTROLIBROS(NRP).EXISTENCIAS
End If
End Sub

Esta es la de incrementar. La de disminuir es igual, pero restando 1 a NRP

Las flechas dobles llevan al registro 1 y al último. Tienen este código

Private Sub BMas2_Click()


NRP = NR
LIBRETBTITULO.Text = REGISTROLIBROS(NRP).TITULO
LIBRETBAUTOR.Text = REGISTROLIBROS(NRP).AUTOR
LIBRETBEDITORIAL.Text = REGISTROLIBROS(NRP).EDITORIAL
LIBRETBEDICION.Text = REGISTROLIBROS(NRP).EDICION
LIBRETBPREC.Text = REGISTROLIBROS(NRP).PRECIO
LIBRETBEX.Text = REGISTROLIBROS(NRP).EXISTENCIAS
End Sub
LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 11
Observe que es muy sencillo trabajar con ficheros secuenciales para bases de datos. El
inconveniente es la cantidad de memoria necesaria para la matriz de datos. También tienen un gran
inconveniente: solamente se pueden leer de hacia adelante. Un fichero secuencial hay que leerlo de
una sola vez. Esto que no es ningún inconveniente para un fichero de texto, o incluso para un
fichero de datos que leemos una única vez, es un problema cuando leemos un dato situado en un
punto de ese fichero, y luego tenemos que leer un dato colocado en una posición anterior. En este
caso, deberemos terminar de leerlo, y volver a comenzar por el principio. Este es un gran
inconveniente para hacer bases de datos con ficheros secuenciales.

No solamente hemos visto una forma de crear una base de datos, sino que hemos visto como
movernos a lo largo de los registros. Verá esto con mucho mas detalle cuando demos bases de
datos. Este tipo de bases de datos son la Tipo Texto que verá mas adelante.

Propiedades de los ficheros Secuenciales:

EOF
Indica el fin del fichero (End Of File). EOF será False hasta que encuentre el final del
fichero secuencial. Habrá observado instrucciones tales como:

Do until EOF(1) (Hazlo hasta que encuentres el EOF del canal 1)


Do While Not EOF(1) (Hazlo mientras EOF del canal 1 sea False)

Estas expresiones se usan en un bucle, para ir extrayendo con la instrucción Input o Line
Input los caracteres de un fichero hasta que se encuentre la marca de final de fichero
(EOF)

LOC
Devuelve la posición de lectura/escritura actual en un archivo abierto.

La sintaxis de esta propiedad es: LOC (Numero de canal)


la información devuelta para un archivo secuencial es la posición de byte actual en el
archivo, dividida por 128.

LOF
Devuelve la longitud de un fichero (Lenght Of File) abierto mediante Open.

Sintaxis LOF(numeroarchivo)

Ejemplo Long = LOF (1)

Observaciones Para obtener la longitud de un archivo que no está abierto utilice la función
FileLen. (Véala mas abajo)

SEEK
Devuelve la posición actual de lectura/escritura de un archivo abierto con la instrucción
Open.

Sintaxis Seek(númeroArchivo)

Seek devuelve un valor entre 1 y 2,147,483,647 (equivalente a 2^31-1) inclusive. Para archivos
abiertos en modo Output, Append o Input, Seek devuelve la posición de byte en la que se va a
ejecutar la siguiente operación. El primer byte de un archivo está en la posición 1, el segundo en la
posición 2 y así sucesivamente.
LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 12
FICHEROS ALEATORIOS (RANDOM)

Un fichero aleatorio es un conjunto de registros, todos ellos de la misma longitud, que nos permite
guardar varias colecciones de datos.

Tal como habíamos visto en los ficheros secuenciales, el almacenar una serie de colecciones de
datos en un fichero secuencial era muy fácil, pero bastante difícil de almacenarlas en la memoria
cuando el número de estas colecciones superaba una cierta cantidad.

Los ficheros aleatorios permiten almacenar información en registros que pueden ser fácilmente
leídos, pudiendo leer los registros uno a uno, sin necesidad de leerlos todos. En los archivos
secuenciales, la información de varios datos podíamos introducirla mediante la instrucción Write, y
conseguíamos un registro de la forma: (Recuérdese el ejemplo de los datos de un libro)

"Título","Autor","Editorial","Edición","Precio","Existencias"

Si deseábamos guardar la información de muchos libros, no había mucho problema para guardarla,
pero sí para almacenarla en memoria para poder usarla luego. Teníamos que leer todo el fichero, y
extraer de él la colección de informaciones y guardarlas en una matriz. Cambiar una información
dentro del fichero secuencial también implica una complicación adicional, ya que debemos rehacer
el fichero completo, pues un fichero secuencial no permite “remendar” el trozo que queremos
cambiar.

Los ficheros aleatorios nos permiten guardar una información similar a la anterior, referida a
cualquier número de libros, y para leerla no es necesario leer todo el fichero, sino simplemente
acceder a los registros que nos interesen. También permite realizar el cambio de un registro de una
forma sencilla, sin alterar los demás.

Todo esto tiene un precio: En los archivos secuenciales, podíamos introducir informaciones de
cualquier longitud. En los archivos aleatorios cada dato tiene una longitud asignada, longitud que no
se puede sobrepasar, y si la información que debemos almacenar tiene menos que la longitud
preestablecida, perderemos esa capacidad sobrante.

Para abrir un fichero aleatorio debemos emplear la expresión:

Open Nombrefichero For Random As # Numerocanal Len = LongitudRegistro

Nombrefichero es el nombre que queremos dar al fichero


Numerocanal es el número del canal (número de fichero) que puede ser de 1 a 255
LogitudRegistro es la longitud total del registro.

Un fichero aleatorio (Random), una vez abierto, puede utilizarse para leer o escribir datos.

Para escribir datos en un fichero aleatorio, primero debemos definir el registro, es decir, en el caso
de los libros visto anteriormente, un registro va almacenar los datos del titulo, autor, editorial, etc.
Para "saber" como se colocan estos datos dentro del registro será necesario definirlo.

En realidad lo que vamos a hacer es definir una variable de las denominadas “Definidas por el
usuario” Con esto lo que hacemos es crear un nuevo tipo de variable, en el ejemplo, la variable tipo
Registro. Se debbe hacer en la sección de declaraciones de un módulo o de un formulario, y
siempre antes de declarar una variable como variable de ese tipo. (La definición de la variable
debe hacerse en la sección de declaraciones del módulo o formulario con ámbito suficiente para
que sea válida en todas las partes de la aplicación donde se necesite esa variable)

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 13


Podemos hacerlo con la instrucción Type:

Type Registro
Titulo As String * 30 Asignamos 30 caracteres para el título
Autor As String * 30 Otros 30 para el autor
Editorial As String * 15 Asignamos 15 caracteres para editorial
Edición As String * 6 Asignamos 6 caracteres para Edición
Precio As String * 4 Asignamos 4 caracteres para el precio
Existencias As String * 3 Tres caracteres para existencias.
End Type

Observe la diferencia de esta definición con la que hacíamos en los ficheros secuenciales. En
aquellos no poníamos la longitud de cada sección. Aquí es necesario, ya que la longitud de un
registro (y también de cada campo) es fija.

Ya una vez definido como es Registro, podemos decir que una variable es del tipo definido para
Registro, es decir :

Dim MiVariable as Registro

Entonces MiVariable ya puede almacenar los datos de Titulo, Autor, Editorial, Edición, Precio y
Existencias, colocando un dato tras otro, sin ninguna separación, en el mismo orden que lo
habíamos definido para Registro. No es necesario utilizar separaciones ya que el programa sabe
que longitud tiene cada dato y el orden de colocación. Lo sabe porque se lo hemos dicho al definir
Registro. Si los datos a introducir son :

Titulo : Guía del Estudiante


Autor : Luis Suárez Bernaldo
Editorial : Ediciones XX
Edición : 2ª
Precio : 3500
Existencias : 25

el registro correspondiente a este libro tendrá una forma mas o menos así :

Guía del Estudiante///////////Luís Suárez Bernaldo//////////Ediciones XX///2ª////350025/

donde se ha sustituido el carácter nulo por una barra ( / ) con el fin de hacerlo visible en el texto. Si
se molesta en contar los caracteres que tiene el registro observará que son 88, que es la suma de
30 + 30 + 15 + 6 + 4 + 3 que son los caracteres asignados a cada uno de las partes que forman el
registro (Título, Autor, etc.) Para hablar con propiedad, a esas partes que componen el registro lea
vamos a llamar CAMPOS. Un Registro está formado por varios Campos, y cada Campo
contiene una información.

Imagínese que introducimos otro libro. El primer campo de ese nuevo registro se colocará en el
fichero inmediatamente después del último campo existente, sin ningún tipo de separación. No
hace falta esa separación, pues VB conoce donde finaliza un registro y comienza otro, ya que la
longitud total del registro se le ha introducido en la instrucción para abrir el fichero, que repetimos
aquí por comodidad :

Open Nombrefichero For Random As # Numerocanal Len = LongitudRegistro

(Si se omite el dato LongitudRegistro VB colocará la longitud por defecto, 128 caracteres)
LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 14
LongitudRegistro deberá ser igual o mayor que la suma de caracteres de cada uno de los campos
declarados en la instrucción Type, que también reproducimos :

Type Registro
Titulo As String * 30 Asignamos 30 caracteres para el título
Autor As String * 30 Otros 30 para el autor
Editorial As String * 15 Asignamos 15 caracteres para editorial
Edición As String * 6 Asignamos 6 caracteres para Edición
Precio As String * 4 Asignamos 4 caracteres para el precio
Existencias As String * 3 Tres caracteres para existencias.
End Type

¿Deberá ser igual o mayor, o estrictamente igual ? La respuesta es igual o mayor. Pero si
declaramos en la instrucción Open que el registro es mayor que la suma de los caracteres de todos
los campos que lo componen, estaremos perdiendo espacio de disco duro, tanto como la diferencia
entre lo declarado en la instrucción Open menos la suma de los caracteres de cada uno de los
campos. Y esa cifra, multiplicada por el número de registros existentes. Por lo tanto debe
declararse en la instrucción Open exactamente la suma de los caracteres de todos los campos. En
el ejemplo anterior era bastante fácil, ya que todos los campos eran del tipo String (cadena de
caracteres) y cada carácter ocupa un byte. La cosa se complica si uno o varios de los campos son
de tipo numérico, porque nos obligará a recordar cuantos bytes ocupa un integer, un Long, etc. Si
hubiésemos declarado en la instrucción Type Precio as Long, Existencias as Integer deberíamos
tener en cuenta que un Long (número entero entre -2.147.483.648 y 2.147.483.647, inclusive)
ocupa 4 bytes y un integer (número entero entre -32.768 y 32.767) ocupa 2 bytes. Se reproduce a
continuación la longitud en Bytes de cada uno de los tipos de datos. No se moleste en aprendérsela
de memoria, pues en la Ayuda de Visual Basic puede encontrarla como Resumen de tipos de
datos. Pero fíjese en algo tan curioso como que un dato tipo Boolean que solamente puede tomar
2 valores (Sí / No) ocupa 2 bytes frente a un dato tipo Byte, que puede tomar 256 valores y ocupa
solamente un Byte.

Tipo de Dato Ocupa


Byte 1 byte
Boolean 2 bytes
Integer 2 bytes
Long(entero largo) 4 bytes
Single(coma flotante Simple precisión) 4 bytes
Double(coma flotante Doble Precisión) 8 bytes
Currency 8 bytes
Date 8 bytes
Object 4 bytes
String (longitud variable) 10 bytes + longitud de cadena
String (longitud fija) longitud declarada de la cadena
Variant (con números) 16 bytes
Variant (con caracteres) 22 bytes + longitud de cadena

Ya le estoy viendo tomando buena nota de cuanto ocupa cada variable. Y echando números para
saber la longitud exacta de la variable y no perder ningún byte del disco duro desaprovechándolo
sin información. ¿No habrá algo que nos lo facilite ? Sí, lógicamente. La instrucción LEN

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 15


LEN nos da la longitud de un texto (Var=Len (“Hola que tal”), o de una variable Var=Len(Variable)
Podemos usarla para conocer la longitud total de la variable MiVariable

LongitudRegistro = Len (MiVariable)

Pero si quiere reducir mas la cosa, abra el fichero de esta forma :

Open Nombrefichero For Random As # Numerocanal Len = Len (MiVariable)

Ni que decir tiene que si se abre ese fichero en varias partes del programa con distintas
instrucciones Open el valor de LongitudRegistro debe ser igual en todas ellas.

La declaración del registro mediante la instrucción Type debe hacerse en la sección de


declaraciones de un Módulo. Esta instrucción Type en realidad lo que está haciendo es definir un
nuevo tipo de variable, (una variable definida por el usuario) que servirá de “muestra” para que en
otra parte del programa le digamos, mediante una instrucción Dim, que tal variable es del tipo
definido anteriormente mediante la instrucción Type. Por lo tanto, debemos declarar una variable en
la parte que corresponda del programa, dependiendo del ámbito que se le quiera dar a esa variable,
diciendo que será del tipo de la declarada mediante la instrucción Type.

Usando la declaración de Registro del ejemplo anterior, vamos a retomar el ejemplo de la


biblioteca. Declararemos (posiblemente en la sección de declaraciones del formulario) una variable
que llamaremos p.e. REGLIBROS de la siguiente forma :

Dim REGLIBROS as Registro

A partir de este momento, el programa sabe que REGLIBROS es una variable que tiene 6 campos
(Titulo, Autor, Editorial, Edición, Precio y Existencias) y que cada campo tiene los caracteres
especificados en la instrucción Type.

Ahora nos cabe una pregunta ¿Cuantos registros tiene un fichero Random? La respuesta es
sencilla. Basta conocer la longitud del fichero mediante la instrucción LOF si el fichero ya está
abierto, o con la instrucción FILELEN si no lo está, y dividir el dato obtenido con cualquiera de las
dos instrucciones anteriores por el valor LongitudRegistro.

Escribir datos en un fichero Random. Instrucción Put

Una vez abierto el fichero Random podemos leer y escribir datos en él. Para escribir datos
utilizaremos la instrucción Put. La sintaxis de Put es la siguiente:

Put # Numerocanal , NumeroRegistro, Variable

Puede omitirse NumeroRegistro. En este caso, el número de registro que se escribirá será el
siguiente al último registro escrito.

NumeroRegistro es el número del registro que queremos escribir, y Variable es el contenido de


ese registro. Siguiendo con nuestro ejemplo de biblioteca, Variable tiene en este caso el nombre
REGLIBROS, que no es un String ni un Integer, sino una variable definida por el usuario ya que la
declaramos con Dim REGLIBROS as Registro. Por lo tanto, la variable REGLIBROS contendrá
los mismos campos que habíamos declarado para Registro en la instrucción Type. Recuerde :

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 16


Type Registro
Titulo As String * 30 Asignamos 30 caracteres para el título
Autor As String * 30 Otros 30 para el autor
Editorial As String * 15 Asignamos 15 caracteres para editorial
Edición As String * 6 Asignamos 6 caracteres para Edición
Precio As String * 4 Asignamos 4 caracteres para el precio
Existencias As String * 3 Tres caracteres para existencias.
End Type

Luego REGLIBROS tendrá 6 campos (Titulo, Autor, Editorial, Edición, Precio y Existencias), cada
uno de una longitud determinada, la definida en la instrucción Type.

Antes de introducir REGLIBROS en el fichero habrá que decir que valor tiene. Pero cada campo
que lo compone tendrá un valor. Podríamos hacer una aplicación en la que, a través de varios
TextBox, le introdujésemos los valores de los campos, y el número de registro en el cual queremos
escribir. El nombre de cada uno de los TextBox para cada uno de los datos es el siguiente :

Campo Título : TBTITULO Campo Autor : TBAUTOR Campo Editorial : TBEDITORIAL


Campo Edición :TBEDICION Campo Precio : TBPRECIO Campo Existencias : TBEXISTENCIAS

La aplicación deberá introducir en cada campo el valor (string) existente en cada uno de esos
TextBox. El valor de la variable REGLIBROS lo compondremos de la siguiente forma :

REGLIBROS.Titulo = TBTITULO.Text
REGLIBROS.Autor = TBAUTOR.Text
REGLIBROS.Editorial = TBEDITORIAL.Text
REGLIBROS.Edicion = TBEDICION.Text
REGLIBROS.Precio = TBPRECIO.Text
REGLIBROS.Existencias = TBEXISTENCIAS.Text

(Si se hubiese omitido alguna de estas igualdades, el campo correspondiente contendría el valor
nulo)

De esta forma, REGLIBROS ya tiene un valor que se puede escribir en el fichero mediante la
instrucción Put.

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 17


El formulario de esa aplicación tendrá esta forma :

Observe que ya se le han introducido otros controles (TextBox para introducir el nombre del fichero,
otro para el número de registro, botones para leer, escribir, abrir el fichero (EXAMINAR), un par de
botones para subir o bajar el número de registro y un botón para salir de la aplicación. El TextBox
para introducir el nombre del fichero se llama TBNOMBREFICHERO y en el que debemos
introducir el número de registro a leer o escribir TBLEERESCR.

El Botón EXAMINAR cierra cualquier fichero que pudiese estar abierto, abre el fichero indicado en
TBNOMBREFICHERO, calcula el número de registros y escribe este número en el Label con
nombre LNUMFICH. El código de su procedimiento Click es el siguiente :

Private Sub BEXAMINAR_Click()


Close ‘Cierra cualquier fichero abierto
Open TBNOMBREFICHERO For Random As #1 Len = 88 ‘Abre el fichero deseado
LONGITUDFICH = LOF(1) ‘Obtiene su longitud
NUMREGS = LONGITUDFICH / 88 ‘Calcula el Nº. de registros
LNUMFICH.Caption = NUMREGS ‘Pone ese Nº. en el Label
End Sub

Veamos como se escribe un registro. Analicemos el código del procedimiento click del botón
ESCRIBIR

Private Sub BESCRIBIR_Click()


REGISTROLIBRO.Titulo = TBTITULO.Text ‘Se asignan los valores de cada
REGISTROLIBRO.Autor = TBAUTOR.Text ‘uno de los campos de la variable
REGISTROLIBRO.Editorial = TBEDITORIAL.Text ‘REGISTROLIBROS
REGISTROLIBRO.Edición = TBEDICION.Text
REGISTROLIBRO.Precio = TBPRECIO.Text
REGISTROLIBRO.Existencias = TBEXISTENCIAS.Text
Put #1, Val(TBLEERESCR), REGISTROLIBRO ‘Se escribe el registro
End Sub

Observe que el Nº. de registro es el valor que figure en el TextBox TBLEERESCR

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 18


Leer datos en un fichero Random. Instrucción Get

Para leer los datos de un fichero Random utilizaremos la instrucción Get. Su sintaxis es la
siguiente :

Get # Numerocanal , NumeroRegistro, Variable

Puede omitirse NumeroRegistro. En este caso, el número de registro que se leerá será el siguiente
al último registro leído.

La Instrucción Get leerá un registro completo. Ese registro contendrá varios campos, y
seguramente nos interesará conocer el valor de cada campo dentro de ese registro. Variable es
una variable que contendrá todos los campos. En nuestra aplicación de biblioteca, Variable tiene
por nombre REGISTROLIBRO (El mismo que tenía para la instrucción Put de escribir. Es pura
comodidad del programador. Puede tener cualquier otro nombre)

Para obtener el contenido de cada campo, realizaremos un proceso similar al empleado para la
escritura, pero al revés. En nuestra aplicación, pretendemos poner el contenido de cada campo en
los mismos TextBox que se utilizaron para escribirlos. Veamos el contenido del procedimiento click
del botón LEER

Private Sub BLEER_Click()


Get #1, Val(TBLEERESCR), REGISTROLIBRO ‘Lee el registro completo
TBTITULO.Text = REGISTROLIBRO.Titulo ‘Obtiene el valor del campo Titulo
TBAUTOR.Text = REGISTROLIBRO.Autor ‘Autor, Editorial, Edición, Precio
TBEDITORIAL.Text = REGISTROLIBRO.Editorial ‘y Existencias y los pone en los
TBEDICION.Text = REGISTROLIBRO.Edición ‘TextBox correspondientes a cada
TBPRECIO.Text = REGISTROLIBRO.Precio ‘dato
TBEXISTENCIAS.Text = REGISTROLIBRO.Existencias
End Sub

Funciones e instrucciones aplicables a los ficheros Random.

Funciones Seek y Loc.

En los ficheros Random tienen especial importancia las funciones Seek y Loc.

Mediante la Función Loc podemos conocer la el último registro manipulado, bien por lectura,
escritura. Si abrimos el fichero y no se ha hecho ninguna lectura o escritura de registros, el número
devuelto por la función Loc es 0.

La sintaxis de la función Loc es :

Variable = Loc (Numerocanal)

Variable tomará un valor igual al número del registro escrito o leído por última vez.

Mediante la Función Seek podemos conocer el próximo registro que será manipulado en una
operación de lectura o escritura. Si abrimos el fichero y no se ha hecho aún ninguna operación de
lectura o escritura, Seek devuelve el valor 1.

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 19


La sintaxis de la función Seek es :

Variable = Seek (Numerocanal)

ATENCION
¡¡¡ Seek puede ser una función (lee un Dato) o una instrucción (fuerza un dato) ! ! !

Instrucción Seek

La instrucción Seek establece el próximo registro a leer o escribir en un fichero Random.

Sintaxis

Seek (Numerocanal), posición

posición es el número de registro que se va a leer o escribir en la siguiente operación. No acepta el


0 como número de registro, el mas bajo debe ser el 1. Si se intenta forzar a la posición 0 dará un
error.

Funciones de los ficheros Random:

EOF
Devuelve un valor que indica si se ha llegado al final de un archivo.

Sintaxis EOF(Numerocanal)

En archivos Random, EOF devuelve False hasta que se haya ejecutado una instrucción Get y no
haya podido leer el registro completo, en cuyo caso devolverá True.
La función EOF no suele emplearse en ficheros Random, ya que en estos nos movemos a base de
registros, y es muy fácil controlar cuantos registros existen en el fichero y en que registro nos
encontramos o nos vamos a mover, mediante las funciones LOF, LOC y SEEK

LOF ( Lenght Of File )

Devuelve la longitud de un fichero .

Sintaxis Variable = LOF(Numerocanal)

Mediante la función LOF podemos conocer el número de registros existentes en un fichero


Random, dividiendo el valor devuelto por LOF por la longitud del registro declarada en la instrucción
Open (LEN = longitud)

Nº. Registros = LOF / longitud

Recuerde Para obtener la longitud de un archivo que no está abierto utilíce la función
FileLen.

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 20


FICHEROS BINARIOS

Un fichero binario es una sucesión de bytes, uno tras otro, que puede almacenar cualquier tipo de
información. Cuando se explicaban los ficheros secuenciales, decíamos que eran los mas
adecuados para introducir información de un texto, con los Random podíamos realizar una base de
datos de forma sencilla, a base de controlar los registros y sus campos. Con un fichero binario
podemos almacenar cualquier información. (texto y cualquier tipo de datos) .

Para abrir un fichero secuencial se abre utilizando la instrucción :

Open Nombrefichero For Binary As # Numerocanal

Como siempre en VB, Numerocanal puede ser un número comprendido entre 1 y 255, que define
ea fichero. No pueden existir al mismo tiempo 2 ficheros abiertos con el mismo Numero de canal.

Nombrefichero es el nombre completo del fichero, con su Path.

Una vez abierto un fichero se binario, podemos leer o escribir datos en él.

Para escribir uno o varios caracteres en un fichero binario, usaremos la instrucción Put.

Put # Numerocanal, Posición, Variable

Donde Posición es el Byte donde comenzará la escritura, y Variable es el nombre de la variable que
contiene el dato a escribir. Este dato puede ser un byte o varios bytes.

Para escribir varios bytes podemos hacerlo de dos formas :

- Si se puede conocer de antemano el número de bytes a escribir, puede declararse Variable como
un string de ese número de caracteres mediante la instrucción Dim, por ejemplo :

Dim Variable As String * numero de bytes

y en este caso siempre escribirá el número de bytes declarado. ¡ Cuidado ! Si los datos a introducir
sobrepasan el número de bytes declarados para Variable, los datos sobrantes no se escribirán en el
fichero. Si los datos a escribir en el fichero fuesen menos que los declarados para Variable, la
diferencia se rellenará con el byte nulo ( 0 ).

- Si no se conoce de antemano el número de bytes a escribir, podemos declarar la variable sin


especificar el número de bytes que tiene, y de esta forma se escribirán todos los bytes que
componen la variable :

Dim Variable As String

Pero en este caso debemos volver a decir ¡ Cuidado !, si no conocemos el número de bytes que
vamos a escribir, puede que “machaquemos” parte de la información que ya tenemos en el fichero,
pues la instrucción Put va a colocar los bytes que componen Variable en la posición especificada
por Posición y siguientes, hasta que quepa toda la cadena de bytes que le queremos introducir. Si
la posición en la que introducimos esos bytes es una posición intermedia, y no controlamos bien el
número de bytes a introducir y las informaciones que ya existen en el fichero en las posiciones
colindantes con las que vamos a introducir los datos, es muy probable que perdamos esa
información al introducir la nueva.

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 21


Si se omite el dato Posición, se tomará como byte de inicio de la escritura el siguiente al último
usado por la instrucción Put. Si quiere omitir este dato, debe conservar las comas que lo separan :

Put # Numerocanal, , Variable

¿Qué pasará si el dato Posición indica una posición mayor que la que tiene realmente el fichero ?
Simplemente que rellenará las posiciones intermedias que se formarán con un byte (puede verlo
con el Block de Notas ÿÿÿ)

Un fichero binario es, como se decía al principio, una sucesión de bytes, que no tiene ningún tipo de
separación entre bytes. Cada dato (byte o conjunto de bytes) que introduzcamos en un fichero
binario se escribirá en el fichero tal y como se introducen. Machacando información ya existente si
no se controla bien donde se mete. Por lo tanto, aunque parece que los ficheros binarios pueden
ser mucho mas versátiles que los secuenciales y los Random, exigen mucho mas control que los
anteriores. Limite el uso de este tipo de ficheros a las aplicaciones en que sea realmente
imprescindible.

Para leer datos de un fichero binario, utilizaremos la instrucción Get.

Get # Numerocanal, Posición, Variable

Donde Posición es el número del primer byte leído, que como en el caso de Put, si se omite,
tomará como valor el byte siguiente al usado en la última instrucción Get. Variable es el nombre de
una variable que contendrá los datos leídos.
Pueden leerse uno o varios Bytes, pero ahora surge un pequeño problema. ¿Como le decimos
cuantos bytes debe leer ? Sencillamente los especificados al declarar la variable . Imaginemos que
la declaración de la variable fue :

Dim Variable As String * 10

Con Variable declarada de esta forma, leerá 10 bytes a partir del byte Posición. (Incluido)

De esta forma, siempre leeremos un número determinado de caracteres (10 en el caso del
ejemplo). Esta es una limitación para el uso de Get. Esta función viene muy bien en aquellas
aplicaciones en las que tenemos que extraer un número fijo de bytes (En la práctica, en la mayor
parte de las aplicaciones se extrae de uno en uno)

Pero pueden existir aplicaciones en las que sea necesario leer una vez un número de caracteres, y
otra vez otro. Ese problema lo tenemos resuelto con la instrucción Input.

Podemos leer caracteres de un fichero secuencial mediante la instrucción Input :

Variable = Input (Numero de bytes, # Numerocanal)

Mediante la instrucción Input podemos leer el número de caracteres que queramos, pero no
podemos controlar el byte de comienzo. Por lo tanto deberemos ayudarnos de la instrucción Seek
para posicionar el puntero de lectura encima del primer byte que queramos leer :

Seek (Numerocanal), Número del primer Byte a leer

Por ejemplo, si queremos leer 35 bytes de un archivo binario, abierto con el número de canal 1,
comenzando por el byte 48 (el 48 será el primer byte leído), ejecutaremos las dos siguientes
instrucciones :

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 22


Seek (1), 48
Variable = Input (35, #1)

Variable contendrá ahora los 35 bytes deseados.

Al igual que se hizo para los ficheros secuenciales y Random, vamos a ver con un ejemplo práctico
como se manejan los ficheros binarios.

El formulario del ejemplo tiene esta forma :

Con el botón ABRIR se abre el fichero deseado. Si no existe en el disco, lo crea, ya que la
instrucción
Open Nombrefichero For Binary As # Numerocanal

intenta abrir un fichero existente llamado Nombrefichero, y si este no existe, lo crea. Si existe el
fichero, presenta todo su contenido en el TextBox inferior, para poder tener una referencia de que
lugar ocupan los distintos caracteres (un fichero binario puede guardar cualquier byte, por lo que si
abre un fichero generado con cualquier programa puede ser que muchos de los bytes no contengan
información de un carácter, por lo que le recomendamos haga esta práctica con un fichero creado
por la misma práctica)

El botón CERRAR cierra el fichero. SALIR sale de la aplicación. El TextBox superior (variable) sirve
para introducir la variable a escribir en el fichero, o para presentar la variable leída en caso de
lectura . El TextBox posición sirve para indicar la posición del primer byte. Posición por defecto
presenta la posición que se extrae mediante la función Seek cada vez que se hace una lectura o
escritura en el fichero. Longitud de la variable permite introducir esa longitud, para leer mediante la
instrucción Input.

El botón ESCRIBIR escribe el dato Variable en el fichero, LEER (GET) lee un único byte, y LEER
(INPUT) lee una cadena de caracteres, de longitud la especificada en el TextBox Longitud de la
variable.

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 23


Se enumera a continuación el código de cada uno, dejando para las explicaciones del profesor en
clase, o el estudio del alumno, la interpretación de cada una de susu partes.

FORMULARIO. DECLARACIONES
Option Explicit ‘Obliga a declarar todas las variables
Dim LONGVAR As Integer ‘Se declara la variable LONGVAR
Dim COMIENZA As Long ‘Se declara la variable COMIENZA
Dim TESTO As String ‘Se declara la variable TESTO
Dim pospordef As Long ‘Se declara la variable pospordef

BOTON ABRIR
Private Sub BABRIR_Click()
CD1.ShowOpen ‘CD1 es un CommonDialog para buscar el fichero
Open CD1.filename For Binary As #1 ‘Abre el fichero indicado en CD1
TESTO = Input(LOF(1), #1) ‘Lee de un golpe el fichero y lo mete en la variable TESTO
TBFICHERO.Text = TESTO ‘Presenta el fichero en el TextBox TBFICHERO
End Sub

BOTON CERRAR
Private Sub BCERRAR_Click()
Close ‘La instrucción Close cierra todos los ficheros abiertos
End Sub

BOTON ESCRIBIR
Private Sub BESCRIBIR_Click()
TBVAR2.BackColor = RGB(255, 0, 0) ‘Pone el TB long. De la variable en rojo
Dim escribe As String ‘Declara la variable escribe como string, sin limitación
escribe = TBVAR1.Text ‘Pasa el contenido de TBVAR a la variable escribe
Put #1, Val(TBVAR3), escribe ‘Instrucción Put. Val(TBVAR3) es la posición del 1er byte
pospordef = Seek(1) ‘Analiza donde quedó el puntero del fichero
Lvar5 = Str(pospordef) ‘y pone este valor en la etiqueta Lvar5
End Sub

BOTON LEER (GET)


Private Sub BLEER_Click()
TBVAR2.BackColor = RGB(255, 0, 0) ‘Pone en rojo el TB TBVAR2 (long. de la variable)
TBVAR2.Text = "1" ‘e indica que la longitud leída es 1
If Seek(1) >= LOF(1) Then ‘Si está al final del archivo
Seek #1, 1 ‘pone el puntero en la posición 1
End If ‘
Dim TEXTO As String * 1 ‘Declara la variable TEXTO de un byte
If TBVAR3.Text <> "" Then ‘Si se le ha indicado donde tiene que comenzar
COMIENZA = Val(TBVAR3.Text) ‘le dice que comience en la posición indicada en TBVAR3
ElseIf Lvar5.Caption <> "" Then ‘si no, si existe posición por defecto
COMIENZA = Val(Lvar5.Caption) ‘le indica que comience en la posición por defecto
Else ‘ si no
COMIENZA = Seek(1) ‘pone el puntero en la posición 1 (byte 1)
End If
Get #1, COMIENZA, TEXTO ‘lee un byte
TBVAR1.Text = TEXTO ‘y lo presenta en TBVAR1
pospordef = Seek(1) ‘busca la nueva posición por defecto
Lvar5 = Str(pospordef) ‘y pone ese valor en Lvar5
End Sub

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 24


BOTON LEER (INPUT)
Private Sub BLLERINPUT_Click()
TBVAR2.BackColor = RGB(255, 255, 255) ‘Pone TBVAR2 en blanco
LONGVAR = Val(TBVAR2.Text) ‘pasa el valor para long. de variable a LONGVAR
If TBVAR3.Text <> "" Then ‘si ese valor existe (TBVAR3 es distinto de nada)
COMIENZA = Val(TBVAR3.Text) ‘la variable COMIENZA toma ese valor
Seek (1), COMIENZA ‘coloca el puntero en ese valor
End If ‘
Dim TEXTO As String ‘Declara la variable TEXTO sin limitación
TEXTO = Input(LONGVAR, #1) ‘Lee LONGVAR bytes del canal 1 y los pasa a TEXTO
TBVAR1.Text = TEXTO ‘y lo presenta en el TB TBVAR1
pospordef = Seek(1) ‘analiza la nueva posición por defecto
Lvar5 = Str(pospordef) ‘y la presenta en Lvar5
End Sub ‘

BOTON SALIR
Private Sub BSALIR_Click()
End ‘Sale de la aplicación.
End Sub

Private Sub TBVAR2_Change()


TBVAR2.BackColor = RGB(255, 255, 255) ‘Vuelve a color blanco si introducimos un dato en
End Sub ‘este Text Box

FIN DE LA APLICACIÓN PARA MANEJO DE FICHEROS BINARIOS

Funciones y propiedades aplicables a todos los ficheros

DIR

Devuelve el nombre de un archivo, directorio o carpeta que concuerda con el patrón o atributo de
archivo especificado o la etiqueta de volumen de una unidad de disco.

Sintaxis Dir[(nombreruta[, atributos])]

nombreruta Expresión de cadena que especifica un nombre de archivo. Puede incluir el


directorio o carpeta y la unidad de disco. Si no se encuentra nombreruta, devuelve
Null.

atributos Constante o expresión numérica, cuya suma especifica atributos de archivo. Si se


omite, devuelve todos los archivos normales que satisfacen el nombreruta.

El argumento atributos tiene estas constantes y valores:

Constante Valor Descripción

vbNormal 0 Normal.
vbHidden 2 Oculto.
vbSystem 4 Sistema
vbVolume 8 Etiqueta de volumen; si se especifica se ignoran todos los atributos
vbDirectory 16 Directorio o carpeta.

En Microsoft Windows, Dir permite el empleo de los caracteres comodín '*' (múltiples caracteres) y
LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 25
'?' (un solo carácter) para especificar varios archivos.
La primera vez que se llama a la función Dir se debe especificar el nombreruta, de lo contrario se
produce un error. Si además se especifican atributos de archivo, se debe incluir el nombreruta.
Dir devuelve el primer nombre de archivo que coincide con el nombreruta. Para obtener más
nombres de archivo que coincidan con el nombreruta, se debe volver a llamar a Dir sin argumentos.
Cuando no hay más nombres de archivo coincidentes, Dir devuelve una cadena de caracteres de
longitud cero. Cuando se devuelve una cadena de longitud cero, en las siguientes llamadas se debe
especificar nombreruta o se producirá un error. Se puede cambiar el nombreruta sin haber obtenido
todos los nombres de archivo que coinciden con el nombreruta actual. Sin embargo, no se puede
llamar a la función Dir.

FILECOPY

Copia un archivo.

Sintaxis FileCopy fuente, destino

fuente Expresión de cadena que especifica el nombre de un archivo a copiarse puede incluir el
directorio o carpeta y la unidad de disco..
destino Expresión de cadena que especifica el nombre del archivo de destino se puede incluir el
directorio o carpeta y la unidad de disco.

Si intenta utilizar la instrucción FileCopy en un archivo abierto actualmente, se produce un error.

FILEDATATIME

Devuelve una fecha que indica la fecha y hora en que un archivo fue creado o modificado por última
vez.

Sintaxis Variable = FileDateTime(nombreRuta)

El argumento con nombre nombreRuta es una expresión de cadena que especifica un nombre de
archivo. Se puede incluir el directorio o carpeta y la unidad de disco.

FILELEN

Devuelve la longitud de un archivo en bytes.

Sintaxis Variable = FileLen(nombreRuta)


El argumento con nombre nombreRuta es una expresión de cadena que especifica un nombre de
archivo se puede incluir el directorio o carpeta y la unidad de disco.

Si el archivo especificado está abierto cuando se llama la función FileLen, el valor devuelto
representa el último tamaño de ese archivo cuando se guardó la ultima vez en el disco.
Para obtener la longitud de un archivo abierto, utilice la función LOF.

GETATTR

Devuelve un número, que representa los atributos de un archivo, directorio o carpeta o una etiqueta
de volumen.

Sintaxis Variable = GetAttr(nombreRuta)

El argumento con nombre nombreRuta es una expresión de cadena que especifica un nombre de
LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 26
archivo se puede incluir el directorio o carpeta y la unidad de disco.

Valores devueltos

El valor devuelto por GetAttr es la suma de los siguientes valores de atributos:

Valor Constante Descripción

0 vbNormal Normal.
1 vbReadOnly Sólo lectura.
2 vbHidden Oculto.
4 vbSystem Archivo de sistema.
16 vbDirectory Directorio o carpeta.
32 vbArchive El archivo ha sido modificado después de efectuar la última copia de
seguridad.

SETATTR

Establece los atributos de un archivo.

Sintaxis SetAttr nombreRuta;atributos

nombreRuta Expresión de cadena que especifica un nombre de archivo se puede incluir el


directorio o carpeta y la unidad de disco.
atributos Constante o expresión numérica cuya suma especifica los atributos de
archivo.

Las constantes y valores de atributos son los mismos que para la instrucción GetAttr

Si se trata de establecer los atributos de un archivo abierto, se producirá un error en tiempo de


ejecución.

FREEFILE

Devuelve el siguiente número de archivo disponible para ser usado con la instrucción Open.

Sintaxis FreeFile[(númerodeintervalo)]

El argumento númerodeintervalo especifica el intervalo desde el que el siguiente número de archivo


libre se va a devolver. Se especifica 0 (predeterminado) para devolver un número de archivo en el
intervalo 1 a 255, inclusive. Se especifica 1 para devolver un número de archivo en el intervalo 256
a 511.

Observaciones Se usa FreeFile cuando se necesita proveer un número de archivo y se quiere


asegurar que el número de archivo no está ya en uso.

LSB Visual Basic - Guía del Estudiante Capítulo 6 Página 27


Visual Basic - Guía del Estudiante Cap. 7

METODOS GRAFICOS
MANEJO DE LA IMPRESORA. El objeto PRINTER

Los métodos gráficos se aplican sobre aquellos objetos que permiten dibujar o escribir sobre
ellos. No son muchos estos objetos. Son el Formulario, el Picture Box y el Printer.

Se denominan métodos gráficas a aquellos métodos que nos permiten dibujar o representar
gráficos ya existentes en un objeto, o que nos permiten analizarlos o borrarlos. Los métodos
gráficos de que dispone Visual Basic son :

Circle, Cls, Line, PaintPicture, Point, Print, y PSet.

METODO Line

Dibuja líneas y rectángulos en un objeto. El objeto puede ser un Formulario, un control


PictureBox o el objeto Printer.

Sintaxis 1 objeto.Line (x1, y1) - (x2, y2), color, BF

(Con esta sintaxis trazará una línea desde las coordenadas absolutas x1,y1
(origen) a las coordenadas también absolutas x2,y2. El color de la línea será el
especificado en color. Los parámetros BF se explican mas adelante.

Sintaxis 2 objeto.Line (x1,y1) - Step (x2,y2), color, BF

(Con esta sintaxis trazará una línea desde las coordenadas absolutas x1,y1
hasta las coordenadas relativas a (x1,y1), x2,y2. Es decir, al poner la palabra
Step (paso) antes de las coordenadas finales, le estamos indicando que las
coordenadas que siguen a Step son relativas. Relativas ¿respecto a quien?.
Relativas a las coordenadas de comienzo de la línea. Esta última expresión
haría lo mismo que la siguiente expresión :

objeto.Line (x1,y1) - (x1+x2, y1+y2), color, BF

Podemos darnos cuenta por la descripción anterior que la palabra Step (palabra reservada de
Visual Basic) indica que las coordenadas que le siguen son relativas a algo. Veamos la tercera
forma de colocar una línea :

Sintaxis 3 objeto.Line Step (x1,y1) - Step (x2,y2), color, BF

Con esta expresión trazará una línea entre las coordenadas relativas (x1, y1),
y las coordenadas relativas (x2,y2). En principio es fácil entender que (x2,y2)
son relativas al punto (x1,y1), pero ¿Respecto a quién son relativas las
coordenadas (x1,y1) ? Son relativas a la posición del puntero de dibujo en el
instante anterior a ejecutar esta sentencia, es decir al CurrentX, CurrentY que
existiese antes de ejecutar la sentencia.

En estas expresiones, las coordenadas estarán especificadas en las unidades de medida


determinadas por las propiedades ScaleMode o ScaleWidth / ScaleHeight del objeto.

En las expresiones anteriores objeto es el nombre del Formulario, PictureBox u objeto


Printer sobre el que queremos dibujar. Si no se especifica objeto se entiende por defecto que
el objeto sobre el que queremos dibujar es el formulario que tiene el enfoque en ese momento.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 1


Color es el número de color, que se puede poner en cualquiera de las posibles formas que
permite VB. Si no se especifica color, pondrá el color por defecto, que es el valor de la
propiedad ForeColor del objeto.

BF es un parámetro opcional. En realidad este parámetro sirve para que en vez de hacer una
línea haga un rectángulo. La expresión :

Form1.Line (x1,y1) - (x2,y2) , RGB(255,0,0), B

dibuja un rectángulo entre los puntos (x1,y1) y (x2,y2).


La expresión :

Picture1.Line (x1,y1) - (x2,y2), RGB (0,255,0), BF

dibuja un rectángulo relleno del mismo color de la línea (en este caso verde) con esquinas en
las coordenadas (x1,y1) y (x2,y2)

De lo explicado se deduce que si el parámetro opcional BF es solamente B dibuja un cuadrado


con esquinas en las coordenadas indicadas (pueden ser absolutas o relativas), y si es BF pinta
ese rectángulo y además lo rellena con el mismo color elegido en el parámetro color. No puede
usarse solamente la F pues no tiene sentido “rellenar” de color una figura abierta.

Para dibujar líneas unidas, comience la línea siguiente en el punto final de la línea anterior.

La anchura de la línea dibujadas depende de la configuración de la propiedad DrawWidth.

Cuando se ejecuta Line, las propiedades CurrentX y CurrentY toman el valor del punto final de
la línea.

METODO Circle

Dibuja una circunferencia, círculo, elipse o arco sobre un objeto.

Sintaxis objeto.Circle (x, y), Radio, Color, Inicio, Final, Aspecto

En la expresión anterior, objeto es el objeto donde se dibujará el circulo. Puede ser, como en el
caso de la línea, un Formulario, un PictureBox o el objeto Printer. Si se omite, se asume que
se refiere al Formulario que tenga el enfoque en ese momento.

(x, y) son las coordenadas del punto central del círculo, elipse o arco. Las unidades de
medida vendrán determinadas por las propiedades ScaleMode o ScaleWidth / ScaleHeight del
objeto.

Radio Este parámetro es requerido. Indica el radio del círculo, elipse o arco, en el mismo
sistema de unidades de medida.

Color Este parámetro es opcional. Es el número del color, expresado en cualquiera de las
formas aceptadas por Visual Basic. Si se omite, se utiliza el valor de la propiedad ForeColor.

Inicio, Final Valor opcional. Cuando se dibuja un arco o parte de un círculo o elipse, inicio y fin
especifican (en radianes) la posición inicial y final del arco. El rango de ambas es de - 2 pi
radianes a 2 pi radianes. El valor predeterminado de inicio es 0 radianes; el de final es de 2 pi
radianes.

Nota para los que no aprobaron Matemáticas

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 2


Un circulo completo tiene 2 x pi radianes. Es decir, 2 x 3,1416 radianes equivalen a 360 º.
Como los datos de ángulos hay que introducirlos en radianes y nosotros normalmente
pensamos en grados, emplee esta fórmula para convertir grados a radianes :

Radianes = Grados x 2 x 3,1416 / 360

Aspecto Este valor nos convertirá la circunferencia en una elipse. Recuerde que una elipse es
una circunferencia generalizada. Lógicamente, este parámetro es opcional. El valor
predeterminado es 1.0, lo que crea un círculo perfecto (no elíptico) en la pantalla. Si utilizamos
en esta propiedad el valor 2 obtendremos una elipse con el radio horizontal de doble valor que
el vertical. Si empleamos 0.5 obtendremos otra elipse, con el radio vertical doble respecto al
horizontal.

Para rellenar la circunferencia y conseguir un círculo, establezca las propiedades FillColor y


FillStyle del objeto en el que se dibuja el círculo o elipse. Sólo se puede rellenar una figura
cerrada. La figuras cerradas son círculo, elipses o porciones de tipo circular (arcos con líneas
de radio dibujadas en ambos lados).

Los valores de Inicio y Final son siempre positivos. El sentido de cuenta de los ángulos es en
sentido contrario a las agujas del reloj. Si le añadimos a Inicio o a Final un signo menos
delante, lo que hace es dibujar un radio desde el centro del circulo hasta el inicio de la
circunferencia (si le hemos puesto un - a Inicio) o hasta el final del arco (si le hemos puesto
un - a Final). Se le pueden poner a ambos y cerramos la figura. Es decir, si queremos que
además de hacer el arco, dibuje los radios, pondremos el signo menos ( -) delante de Inicio y de
Final, a sabiendas que VB siempre entenderá los valores de Inicio y Final como positivos.
NOTA. No se líe con la información que aporta VB para este tema. ¡¡¡Está mal !!!

Lo expuesto anteriormente NO FUNCIONA para valores de Inicio o Final iguales a 0. Por lo


tanto, si queremos hacer un radio en 0 radianes (línea recta desde el centro a la derecha)
deberemos poner una cantidad muy cercana a 0 (0.00000001, p. e.) para que ponga el radio.

Puede omitir un argumento opcional en medio de la sintaxis, pero debe incluir la coma del
argumento antes de poner el argumento siguiente. Si omite un argumento adicional del final, no
utilice comas tras el último argumento que especifique.

Cuando se ejecuta Circle, las propiedades CurrentX y CurrentY toman el valor del punto
central.

METODO Cls

Borra los gráficos y el texto generados en tiempo de ejecución de los controles Form, Image o
PictureBox. Observe que el objeto Printer no tiene método Cls.

Sintaxis objeto.Cls

Donde objeto representa un formulario, control Image o PictureBox. Si objeto se omite, se


asume que el objeto es el control Form que tenga el enfoque.

Cls borra el texto y los gráficos generados en tiempo de ejecución por instrucciones gráficas y
de presentación. Los mapas de bits de fondo definidos usando la propiedad Picture y los
controles dispuestos en un Form en tiempo de diseño no se ven afectados por Cls. Los gráficos
y el texto colocados en controles Form, Image o PictureBox mientras la propiedad AutoRedraw
es True no se ven afectados si AutoRedraw se establece a False antes de llamar a Cls. Es
decir, el texto y los gráficos de los controles Form, Image o PictureBox pueden mantenerse
manipulando la propiedad AutoRedraw del objeto con el que se trabaja.

Después de llamar a Cls, las propiedades CurrentX y CurrentY del objeto se restablecen a 0.
METODO PaintPicture

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 3


Presenta el contenido de un archivo gráfico (.BMP, .WMF, .EMF, .ICO o .DIB) en un objeto
Form, PictureBox o Printer. La imagen deberá estar en un Formulario o en un control Image.
NO puede usarse este método para dibujar una imagen contenida en un fichero (Vea mas
adelante la función LoadPicture)

Puede sacar mucho partido a la propiedad PaintPicture. Piense solamente que puede volcar
una imagen .BMP al objeto Printer (a la impresora). Esto puede permitirle dibujar un logotipo en
un listado, factura, etc.

Sintaxis

objeto.PaintPicture Imagen, x1, y1, anchura1, altura1, x2, y2, anchura2, altura2, Opecod

La sintaxis del método PaintPicture tiene las siguientes partes:

objeto es el objeto donde queremos colocar el gráfico. Es opcional. Si se omite, se asume que
el objeto es el formulario que tenga el enfoque.

Imagen Este parámetro es requerido. Es el origen del gráfico que se va a presentar en el


objeto. Debe ser la propiedad Picture de un objeto Form, control PictureBox o control Image.
También puede ser el contenido de una variable tipo Picture. Es decir, la imagen debe existir en
un PictureBox, en un Formulario, en un control Image o en una variable. Si es un control, el que
contiene la imagen, puede ponerse invisible (Su propiedad Visible = False) con lo que
podemos hacer un “almacenillo” de imágenes en un formulario sin que molesten a la hora de
trabajar

x1, y1 Parámetro requerido. Indican las coordenadas destino (eje x y eje y) del objeto en las
que se ponemos el origen de la imagen. Las propiedad ScaleMode, o ScaleWidth y
ScaleHeight del objeto determinan las unidades de medida que se usan. Recuerde que las
coordenadas en VB crecen desde la esquina superior izquierda. Los valores x1 e y1
determinan el punto del objeto donde se colocará la esquina superior izquierda del gráfico que
vamos a introducir.

anchura1 Opcional. Indica la anchura destino de la imagen. La propiedad ScaleMode del objeto
determina las unidades de medida que se usan. Si anchura destino es mayor o menor que la
anchura origen (anchura2), imagen se amplía o se comprime respecto al original. Si se omite,
se usa la anchura origen.

altura1 Opcional. Indica la altura destino de la imagen. La propiedad ScaleMode del objeto
determina las unidades de medida que se usan. Si altura destino es mayor o menor que la
altura origen (altura2), imagen se amplía o se comprime respecto al original. Si se omite, se usa
la altura origen.

x2, y2 Parámetro opcional. Indican las coordenadas (eje x y eje y) de la zona de recorte dentro
de la imagen origen. Esto de la zona de recorte significa que podemos cortarle a la imagen
origen un trozo, tanto en sentido vertical como en horizontal.

anchura2 Opcional. Indica la anchura de la imagen origen. Este parámetro se usa para
establecer la relación entre la anchura de la imagen final y la anchura de la imagen origen.

Si al realizar la copia de la imagen a Objeto, esta nos sale muy grande, podemos, bien rebajar
el parámetro anchura1 o aumentar anchura2, puesto que la medida real del ancho de la
imagen final estará en relación directa con el cociente anchura1/anchura2

altura2 Opcional. Lo mismo que para anchura2, pero referido a la altura en este caso.

Opecod Opcional. Valor Long o código que se usa sólo con mapas de bits. Define una
operación bit a bit (por ejemplo, operador Not o Xor) que se realiza sobre imagen al dibujarla
sobre objeto. Para obtener la lista completa de los operadores bit a bit, busque el tema BitBlt
en el archivo de Ayuda de Windows SDK (WIN31WH.HLP).

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 4


NOTA Como caso práctico, el autor de este texto suele guardar la imagen en una variable tipo
Picture. Se desconoce el ancho de esa imagen, que vendrá dado por la anchura real del
Bitmap. Puede conocerse la anchura y altura de la imagen consultando la anchura y altura de
la variable :

AnchodelaImagen = VariableImagen.Width
AlturadelaImagen = VariableImagen.Height

Muchas veces, la imagen que se introduce en la variable tipo Picture es distinta en una ocasión
u otras, por lo que desconocemos a priori que dato debemos poner a anchura1 y a anchura2.
Todo tiene solución. Con el código siguiente el ancho y alto de la imagen se mantendrá
constante independientemente de la anchura y altura que tenga el Bitmap original.

objeto.PaintPicture Imagen, x1, y1, anchura1, altura1, , , VariableImagen.Width, _


VariableImagen.Height

donde hemos omitido x2, y2 de forma intencionada, pero observe que hemos seguido
respetando su sitio con las comas como separadores. El último parámetro, Opecod se ha
omitido, pero como es el último, no hace falta dejarle las comas.

Pueden omitirse tantos argumentos finales como se desee. Si se omite uno o varios
argumentos finales, no se usan comas a partir del último argumento especificado. Si se quiere
especificar un argumento opcional, se deben especificar todos los argumentos opcionales que
aparecen antes en la sintaxis.

METODO Point

Devuelve, como entero Long, el color rojo - verde - azul (RGB) del punto especificado de un
objeto Form o control PictureBox.

Sintaxis objeto.Point(x, y)

donde
objeto Opcional. Nombre del Formulario o PictureBox donde se va a analizar el color. Si objeto
se omite se asume que el objeto es el formulario que tenga el enfoque.

x, y Parámetro requerido. Valores Single que indican las coordenadas horizontal (eje x) y
vertical (eje y) del punto según la propiedad ScaleMode del objeto Form o control PictureBox.
Deben colocarse entre paréntesis.
Estas coordenadas se refieren a las coordenadas del objeto que contiene el gráfico, con origen
(0,0) en la esquina superior izquierda del mismo.

Si el punto definido por las coordenadas x e y está fuera de objeto, el método Point devuelve el
valor -1.

METODO Pset

Asigna a un punto de un objeto un color especificado. El objeto puede ser un Formulario, un


PictureBox o el objeto Printer.

Sintaxis objeto.PSet (x, y), Color

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 5


ó objeto.PSet Step (x, y), Color

La sintaxis del método PSet tiene las partes siguientes:

objeto Opcional. Nombre del objeto (Formulario, PictureBox o Printer). Si se omite objeto, se
asume como objeto el Formulario que tenga el enfoque.

(x, y) Requeridos. Valores de simple precisión que indican las coordenadas horizontales (eje x)
y verticales (eje y) del punto a establecer.

Estas coordenadas se refieren a las coordenadas del objeto destino, con origen (0,0) en su
esquina superior izquierda.

Color Parámetro opcional. Valor entero largo que indica el color RGB especificado para el
punto. Si se omite, se utiliza el valor de la propiedad ForeColor. Puede utilizar la función RGB o
la función QBColor para especificar el color.

El tamaño del punto dibujado depende del valor de la propiedad DrawWidth. Cuando
DrawWidth es 1, PSet establece un píxel al color especificado. Cuando DrawWidth es mayor
que 1, se centra el punto en las coordenadas especificadas.

La forma en que se dibuja el punto depende de los valores de las propiedades DrawMode y
DrawStyle.

Cuando se ejecuta PSet, las propiedades CurrentX y CurrentY toman el valor del punto
especificado en los argumentos.

Vacíe un píxel con el método PSet especificando las coordenadas del píxel y utilizando el valor
de la propiedad BackColor como argumento color.

Como complemento a los Métodos gráficos, bueno será comentar las formas posibles de
introducir colores en VB y otras propiedades que tienen relación con los métodos gráficos.

METODO Print

Imprime texto sobre un Formulario, Picture Box u Objeto Printer

Sintaxis Objeto.Print Expresión

Donde

Objeto es el nombre del Formulario, PictureBox o el Printer, donde se desea escribir


Expresión Es una cadena de caracteres o variable que contiene el texto a escribir

El tamaño, tipo, color y otras propiedades de la letra serán las que tenga el objeto sobre el que
se va a escribir en ese momento. El lugar donde se inicia la escritura será el de la propiedad
CurrentX y CurrentY actuales.

Veamos un ejemplo para excribir sobre un formulario. El Formulario, desde el código que está
dentro de el se le nombra con Me.

Me.FontName = "Arial"
Me.FontSize = 12
Me.FontBold = True
Me.Print "Hola Mundo"

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 6


SavePicture (Instrucción)

Guarda un gráfico de un objeto Form, de un control PictureBox o de un control Image en un


archivo.

Sintaxis SavePicture imagen, expcadena

La sintaxis de la instrucción SavePicture tiene las siguientes partes:

imagen es el nombre del objeto que contiene los gráficos que se van a guardar en el archivo,
mas su propiedad Picture o Image y expcadena es el nombre del archivo gráfico que se va a
guardar.

Ejemplo: SavePicture Picture1.Picture, "c:\suarez\luis.bmp"

En este ejemplo, guardamos en el fichero LUIS.BPM que está en el directorio C:\SUAREZ el


gráfico que contiene el PictureBox denominado Picture1

Si un gráfico ha sido cargado en la propiedad Picture desde un archivo, en tiempo de diseño o


en tiempo de ejecución, se guarda usando el mismo formato del archivo original. Los gráficos
de la propiedad Image siempre se guardan como archivos de mapas de bits (.BMP).

LoadPicture (Función)

Carga un gráfico en un objeto Form, un control PictureBox o un control Image.

Sintaxis Objeto.LoadPicture ([expcadena])

Donde Objeto es el nombre del Formulario, PictureBox o control Image que se va a rellenar con
el gráfico, y el argumento expcadena es el nombre del archivo gráfico que se quiere cargar.

Usando LoadPicture sin argumento se borran los gráficos de los formularios y los controles
PictureBox e imagen.

Los formatos gráficos reconocidos por Visual Basic incluyen archivos de mapas de bits (.BMP),
archivos de icono (.ICO), archivos de longitud codificada (.RLE) y Metarchivo (.WMF).

Para cargar gráficos para presentarlos en un control PictureBox, Image o como fondo de un
formulario, el valor devuelto por LoadPicture debe ser asignado a la propiedad Picture del
objeto en el se quiere presentar la imagen. Por ejemplo:

Form1.Picture = LoadPicture ("FIESTA.BMP")


Imagen1.Picture = LoadPicture ("FIESTA.BMP")
Picture1.Picture = LoadPicture (FIESTA.BMP")

Para asignar un icono a un formulario, se asigna el valor devuelto por la función LoadPicture a
la propiedad Icon del objeto Form:

Form1.Icon = LoadPicture ("UNICONO.ICO")

Los iconos también pueden ser asignados a las propiedades DragIcon de todos los controles
excepto los controles Timer y Menú. Por ejemplo:

Comando1.DragIcon = LoadPicture ("UNICONO.ICO")

Para cargar gráficos en el Portapapeles del sistema se usa LoadPicture de la forma siguiente:

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 7


Clipboard.SetData LoadPicture ("FIESTA.BMP") (Vea Capítulo del Portapapeles)

Puede también meter una imagen en una variable, y luego poner en uno de los controles
citados anteriormente la imagen guardada en la variable. Este método le permite presentar una
imagen muy rápidamente, ya que no necesita acceder al disco para buscar una imagen, pero
emplea mucha memoria RAM, ya que la variable (o variables) conteniendo la(s) imágenes están
en la RAM.

Para ello hay que declarar las variables como Picture

Option Explicit
Dim MiVariable1 As Picture, MiVariable2 As Picture

Private Sub Form_Load()


Set MiVariable1 = LoadPicture("c:\pruebavb\ athena.bmp ")
Set MiVariable2 = LoadPicture("c:\list_tel\rr1.bmp")
End Sub

Private Sub Command1_Click()


Picture1.Picture = MiVariable1
End Sub

Private Sub Command2_Click()


Picture1.Picture = MiVariable2
End Sub

Mediante este programa lo que hemos hecho fue guardar dos imágenes en sendas variables,
en el momento de cargar el formulario, imágenes que se pasan posteriormente al control
Picture1 con los botones de comando Command1 y Command2

Propiedades de varios controles aplicables a los métodos gráficos

DrawMode (Propiedad)

Devuelve o establece un valor que determina el aspecto de la salida de un método gráfico o el


aspecto de un control Shape o Line.

Sintaxis objeto.DrawMode = número

Donde objeto es el nombre del Formulario, PictureBox, objeto Print, o los controles Shape o
Line, y número es un entero que especifica el aspecto, según la siguiente lista:

1 Blackness.
2 Not Merge PenInverso del valor 15 (Merge Pen).
3 Mask Not PenCombinación de los colores comunes del color de fondo y el inverso del
Pen.
4 Not Copy PenInverso del valor 13 (Copy Pen).
5 Mask Pen NotCombinación de los colores comunes al Pen y al inverso de la muestra.
6 InvertInverso del color de muestra.
7 Xor PenCombinación de los colores en el Pen y en el color de la muestra, pero no de
ambos.
8 Not Mask PenInverso del valor 9 (Mask Pen).
9 Mask PenCombinación de los colores comunes al Pen y a la presentación.
10 Not Xor PenInverso del valor 7 (Xor Pen).
11 NopNadano hay cambios. De hecho, este valor desactiva el dibujado.
12 Merge Not PenCombinación del color de muestra y el inverso del color del Pen.
13 Copy Pen (Predeterminado)Color especificado por la propiedad ForeColor.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 8


14 Merge Pen NotCombinación del color del Pen y el inverso del color de muestra.
15 Merge PenCombinación del color del Pen y el color de muestra.
16 Whiteness.

Use esta propiedad para producir efectos visuales con controles Shape o Line o al dibujar con
métodos gráficos. Visual Basic compara cada píxel de la plantilla de dibujo con el píxel
correspondiente del fondo existente y después aplica operaciones a nivel de bit. Por ejemplo, el
valor 7 (Xor Pen) usa el operador Xor para combinar un píxel del dibujo con un píxel del fondo.
El efecto exacto de un valor DrawMode depende del modo en el que el color de una línea
dibujada en tiempo de ejecución se combina con los colores de la pantalla. Los valores 1, 6, 7,
11, 13 y 16 producen los mejores resultados.

DrawStyle (Propiedad)

Devuelve o establece un valor que determina el estilo de línea de la salida de métodos gráficos.

Sintaxis objeto.DrawStyle = número

Donde objeto es el nombre del Formulario, PictureBox, objeto Print sobre el que se va a dibujar,
y número es un entero que especifica el estilo de línea, tal como se describe a continuación:

0 (Predeterminado) Continuo.
1 Rayas.
2 Puntos.
3 Raya - punto.
4 Raya - punto - punto.
5 Transparente.
6 Continuo interior.

Si DrawWidth se define con un valor mayor que 1, los valores de DrawStyle entre 1 y 4
producen una línea continua (el valor de la propiedad DrawStyle no cambia). Si DrawWidth se
define como 1, DrawStyle produce el efecto para cada valor descrito en la tabla anterior.

DrawWidth (Propiedad)

Devuelve o establece la anchura de línea de lo dibujado con los métodos gráficos.

Sintaxis objeto.DrawWidth = tamaño

Donde objeto es el nombre del Formulario, PictureBox, objeto Printer sobre el que se va a
dibujar, y tamaño es una expresión numérica comprendida entre 1 y 32.767 que representa la
anchura de la línea en pixeles. El valor predeterminado es 1, es decir, un píxel de ancho.

Puede incrementar el valor de esta propiedad para aumentar la anchura de la línea. Si el valor
de la propiedad DrawWidth es mayor que 1, los valores de 1 a 4 en la propiedad DrawStyle
producirán una línea continua (el valor de DrawStyle no se modifica). Si se establece 1 en
DrawWidth, DrawStyle producirá los resultados mostrados en la tabla de esta propiedad.

FillColor (Propiedad)

Devuelve o establece el color usado para rellenar formas. FillColor también se usa para
rellenar círculos y cuadros creados con los métodos gráficos Circle y Line.

Sintaxis objeto.FillColor = valor

Donde objeto es el nombre del Formulario, PictureBox, objeto Printer sobre el que se va a

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 9


dibujar, y valor es un valor o constante que determina el color de relleno, con cualquiera de los
criterios de VB para definir el color.
De forma predeterminada, FillColor está definido como 0 (Negro).

Excepto en el objeto Form, cuando la propiedad FillStyle se define con su valor


predeterminado, 1 (Transparente), el valor de FillColor se ignora.

FillStyle (Propiedad)

Devuelve o establece el modelo usado para rellenar controles Shape así como los círculos y los
cuadros creados con los métodos gráficos Circle y Line.

Sintaxis objeto.FillStyle = número

Donde objeto es el nombre del Formulario, PictureBox, objeto Printer sobre el que se va a
dibujar, y número es un entero que especifica el estilo de relleno, tal como se describe a
continuación:

0 Continuo.
1 (Predeterminado) Transparente.
2 Línea horizontal.
3 Línea vertical.
4 Diagonal hacia arriba.
5 Diagonal hacia abajo.
6 Cruzado.
7 Diagonal Cruzada.

Cuando la propiedad FillStyle se define con su valor predeterminado, 1 (Transparente), el valor


de FillColor se ignora, excepto en el objeto Form.

AutoRedraw (Propiedad)

Esta propiedad es aplicable a los formularios y el PictureBox. Si está a true, hace que el
Formulario o Picture guarden el gráfico aunque estén minimizados o pase por encima de ellos
otro objeto. Por regla general, esta propiedad debe ponerse a False cuando no se van a utilizar
métodos gráficos sobre ese objeto (se ahorra memoria) y a True cuando se van a utilizar
métodos gráficos

Sintaxis objeto.AutoRedraw = booleano

Donde objeto es el nombre del Formulario o PictureBox sobre el que se va a dibujar, y


booleano es una expresión booleana que especifica la forma en la que objeto es vuelto a
dibujar, tal como se describe a continuación:

True Activa el redibujado automático de un objeto Form o control PictureBox. Los gráficos
y el texto se escriben en la pantalla y en una imagen almacenada en memoria. El objeto no
recibe eventos Paint; se vuelve a dibujar cuando es necesario, usando la imagen almacenada
en memoria.

False (Predeterminado) Desactiva el redibujado automático de un objeto y escribe los gráficos


y el texto solamente en la pantalla. Visual Basic invoca el evento Paint del objeto cuando se
necesita volver a dibujar dicho objeto.

Esta propiedad es importante cuando se trabaja con los siguientes métodos gráficos: Circle,
Cls, Line, Point, Print y PSet. Al establecer AutoRedraw a True la salida de estos métodos se
vuelve a dibujar automáticamente en un objeto Form o en un control PictureBox cuando, por

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 10


ejemplo, se cambia de tamaño al objeto o se vuelve a presentar después de haber estado
oculto por otro objeto.
Se puede establecer AutoRedraw en el código en tiempo de ejecución para alternar entre
dibujar gráficos persistentes (como color de fondo o cuadrícula) y gráficos temporales. Si se
define AutoRedraw a False, la salida anterior se convierte en parte del fondo de la pantalla.
Cuando AutoRedraw se define a False, los gráficos de fondo no se eliminan si se borra el área
de dibujo con el método Cls. Al volver a establecer AutoRedraw a True y después usar Cls se
borran los gráficos de fondo.

MEDIDAS DE LOS OBJETOS QUE PERMITEN METODOS GRAFICOS

Cuando mencionamos la sintaxis de los métodos gráficos todos ellos hablan de medidas. Por
ejemplo, en el método Line:

objeto.Line Step (x1,y1) - Step (x2,y2), color, BF

los valores x1, y1, x2, y2 se refieren a valores de las coordenadas x e y del objeto donde se va
a ejecutar ese método gráfico.

La pregunta viene ahora. En que unidades de medida se miden esas coordenadas? La


respuesta en principio es sencilla: en lo establecido en la propiedad ScaleMode. Asi, podemos
trazar una línea midiéndola en Twips, en Points, Pixels, Carácter, y hasta podemos hacerlo en
mm, cm o pulgadas. Nadie es capaz de saber la medida que va a tener una línea medida en
Twips. Y encima, las medidas que va a tener de ese formulario donde va a poner pueden ser
número como 5715 x 8953.

Le sugiero una forma mucho mas práctica de poner las medidas a un objeto soporte de
métodos gráficos. Use las propiedades ScaleWidth y ScaleHeight para determinar cuanto
quiere que le mida de ancho y de alto respectivamente. No se preocupe de cuanto va a medir
ahora la unidad de medida. Si pone para un formulario o PictureBox rectangular que ScaleWidth
= 12000 y ScaleHeight = 8000 sabe que ese formulario o PictureBox mide esas cantidades que
ha puesto. Ahora ya será mucho mas fácil definir los valores de x1, y1 y x2 e y2 en la línea de
código anterior. Esta observación es especialmente útil cuando estamos trabajando con el
Printer. El Printer es la impresora. Y en este caso podrá poner unas medidas que sean acordes
con el tamaño del papel que esté usando (Por ejemplo 21000 para ScaleWidth y 29700 para
ScaleHeight si se trata de un papel de 210 x 297 mm (DIN A4) En estas condiciones, la unidad
de medida sería la centésima de mm, precisión suficiente para realizar dibujos que necesiten
alta definición (Circuitos impresos, por ejemplo). En el caso del papel de la impresora, puede
calcular los valores de las coordenadas X e Y usando un escalímetro.

Propiedades CurrentX y CurrentY

Estas propiedades, aplicables a todos los objetos que aceptan métodos gráficos, definen el
punto de inicio para los siguientes métodos gráficos o de impresión. Es decir, donde se va a
comenzar a escribir mediante el método Print o el punto de inicio del método gráfico Line, si no
se especifica el origen del mismo. La instrucción

Me.Line -(2000, 2000)

Dibuja una línea desde el punto donde se encontrase en ese momento el CurrentX y CurrentY
hasta el punto 2000,2000

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 11


Colores en Visual Basic.
(Este texto es repetición del expuesto en el capitulo del CommonDialog)

Visual Basic acepta para especificar un color, tres procedimientos: Mediante el número de
color, mediante la sentencia RGB ( rojo, verde, azul ) o mediante la función QBColor.

Por número

El número que representa el color en VB está formado por la suma de la componente roja, la
componente verde y la componente azul. Podríamos verlo muy bien en numeración
Hexadecimal:

Color = Hex XX YY ZZ

Donde ZZ es un número Hexadecimal que representa la cantidad del color rojo. El mínimo
estaría en 0 (H00) y el máximo en 255 (HFF)

YY representaría la cantidad de color verde y XX la de color azul, ambos con los mismos límites
explicados para el rojo.

Por ejemplo: el rojo puro sería: Hex(0000FF) = 255


el verde puro sería: Hex(00FF00) = 652280
el azul puro sería: Hex(FF0000) = 16711680

Una mezcla de un poco de rojo (HB1), otro poco de verde (H56) y otro poco de azul (H1F) daría
el siguiente número:

Hex(1F56B1) = 2053809

Por la sentencia RGB

Se puede expresar el color, poniendo simplemente RGB (rojo, verde, azul), donde rojo es un
número entre 0 y 255 que indica la cantidad de color rojo que se aporta al color, verde un
número comprendido entre 0 y 255 indicando la cantidad de verde, y lo mismo para azul.
Esta es la forma más sencilla de poner la propiedad color, y con la que mejor controlaremos el
mismo.

Mediante la Función QBColor

Devuelve o establece el código de color RGB correspondiente a un número de color.

Sintaxis Objeto.QBColor(color)

El argumento color es un número entero entre 0 a 15, según la siguiente lista:

Número Color Número Color

0 Negro 8 Gris
1 Azul 9 Azul claro
2 Verde 10 Verde claro
3 Aguamarina 11 Aguamarina claro
4 Rojo 12 Rojo claro
5 Fucsia 13 Fucsia claro
6 Amarillo 14 Amarillo claro
7 Blanco 15 Blanco brillante

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 12


Ejemplo. Tengamos un Label llamado Label1 y un botón de comando, en cuyo procedimiento
click le introducimos el código:

Static i As Integer
i=i+1
If i = 16 Then i = 0
Label1.caption = i
Label1.BackColor = QBColor(i)

En el Label podremos ver el color y su número de color.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 13


LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 14
La Impresora - El Objeto Printer
El objeto Printer le permite comunicarse con una impresora del sistema (inicialmente la
impresora predeterminada). Este es uno de los Objetos de VB que no tiene representación
gráfica en la pantalla, tanto en tiempo de diseño como de ejecución.

El objeto Printer gestiona el envío de información a la impresora, tanto para imprimir textos
como gráficos. Para Visual Basic el objeto Printer es como otro objeto cualquiera. Si queremos
imprimir algo en la impresora, debemos escribir el código VB necesario para escribirlo en el
objeto Printer, lo mismo que si estuviésemos escribiendo en un formulario.

Lo mismo que para escribir en un formulario, escribíamos el código

Form1.Print "ABCD"

Para escribir en el objeto Printer el código será:

Printer.Print “ABCD”

Para enviar gráficos al objeto Printer se procede de igual forma que si estuviésemos dibujando
en un formulario

Form1.Circle (200, 150), 50, , , , 0.5 Esta instrucción dibuja una elipse centrada en
el punto x=200, y=150 del formulario Form1

Printer.Circle (200, 150), 50, , , , 0.5 Esta instrucción dibuja una elipse centrada en
el punto x=200, y=150 del objeto Printer

Parece en principio algo raro hablar de las coordenadas x e y del objeto Printer. Posiblemente
porque el objeto Printer es un objeto que no podemos “ver”. Pero imaginemos que el objeto
Printer es una hoja de papel. La misma hoja que aparecerá escrita una vez que le enviemos el
texto (o los gráficos) que queremos imprimir. Esa hoja de papel tendrá unas dimensiones que
deberemos indicar al objeto Print. La forma de indicarle las dimensiones del papel varían
dependiendo del driver de impresora usado.

El driver de la impresora sabrá que el papel que tiene es un DIN A4, DIN A3, etc., que tiene
unas medidas prefijadas. Centrémonos en lo mas habitual, una impresora que tenga un papel
DIN A4 cuyas medidas son 210 x 297 mm.

El driver de impresora “sabe” que ese es el tamaño de su papel. Ahora solamente nos falta que
nuestra aplicación lo sepa también. Para ello vamos a indicarle mediante un par de sentencias
las medidas de ese papel : ScaleWidth y ScaleHeight

Si le decimos :

Printer.ScaleWidth = 2100 : Printer.ScaleHeight = 2970

le estamos diciendo a nuestro programa que el papel mide 2100 unidades de ancho y 2970
unidades de alto. (Estamos suponiendo que el papel está colocado en posición vertical). Si
tiene 2100 unidades de ancho, y el ancho real del papel es de 210 mm, nuestra unidad de
medida será de 0,1 mm. Es decir, le decimos a nuestro programa que el papel tiene 2100
décimas de milímetro de ancho, y 2970 décimas de milímetro de alto. La precisión con la que
podemos colocar un punto sobre el papel será por tanto 0,1 mm. Podríamos hacerla mayor
(0,01 mm.) si pusiésemos Printer.ScaleWidth = 21000 y Printer.ScaleHeight = 29700.

Para el trabajo ordinario de imprimir listados o dibujar gráficos tipo barras, es mas que
suficiente una precisión de 0,1 mm. Si lo que queremos es un dibujo mas exacto (Dibujar

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 15


fotolitos de circuitos impresos, p.e. ) esta precisión de 0,1 mm. no nos bastaría, debiendo llegar
a una precisión del orden de 0,01 mm. Pero todo ello está condicionado por el número de p.p.i.
(puntos por pulgada) que nuestra impresora es capaz de dar.

Nota.- Una impresora tiene unos márgenes sobre los que no puede escribir. Por lo tanto,
cuando decíamos que el papel tiene 210 mm. de ancho, en realidad ya estamos cometiendo un
pequeño error, ya que la impresora no puede escribir en todo el ancho, pues los 2 - 3 mm de
cada lado no lo imprime. Deberemos entonces poner las propiedades ScaleWidth y ScaleHeight
del Printer de acuerdo con la superficie real de escritura de nuestra impresora. Le adelanto que
no le va a ser fácil enterarse de qué márgenes deja sin imprimir. Le recomiendo que imprima
una línea desde Printer.CurrentX=0 a Printer.CurrentX= (un número superior a
Printer.Scalewidth). Mida con un escalímetro el ancho real de la impresión.

El objeto Printer almacenará toda la información sin pasarla a la impresora hasta que se le
envíe la instrucción Printer.EndDoc o se le envíe un salto de página mediante la instrucción
Printer.NewPage.

El objeto Printer, al igual que otros objetos de Visual Basic tiene sus propiedades y métodos.

Las principales propiedades del objeto Printer son :

Nota El efecto de las propiedades del objeto Printer depende del controlador suministrado por
el fabricante de la impresora. Algunos valores de la propiedad pueden no tener efecto, o varios
valores distintos de la propiedad pueden tener todos el mismo efecto. Los valores fuera del
rango aceptado pueden producir error. Para obtener más información, vea la documentación del
fabricante del controlador concreto.

ColorMode

Devuelve o establece un valor que determina si una impresora de color imprime en color o en
blanco y negro. No disponible en tiempo de diseño.

Sintaxis Printer.ColorMode [= valor]

Valor puede ser un número o una constante de VB.

Si es un 1 (o la constante vbPRCMMonochrome) imprimirá en blanco y negro (normalmente en


escala de grises).

Si es 2, o la constante vbPRCMColor imprimirá en color.

El valor predeterminado depende del controlador de la impresora y de la configuración actual de


la impresora. Las impresoras en blanco y negro ignoran esta propiedad.

Copies

Devuelve o establece un valor que determina el número de copias que se van a imprimir.

Sintaxis Printer.Copies = número

Donde número debe ser una expresión numérica que especifique el número de copias que se
van a imprimir. Este valor debe ser un entero. El valor por defecto es 1.

CurrentX CurrentY

Devuelven o establecen las coordenadas horizontal (CurrentX) o vertical (CurrentY) para un


método gráfico o de impresión. No disponible en tiempo de diseño.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 16


Sintaxis
Para forzar las coordenadas del cursor de escritura del objeto Printer :

Printer.CurrentX = x Printer.CurrentY =y

Para conocer las coordenadas del cursor de escritura del objeto Printer

Posx = Printer.CurrentX Posy = Printer.CurrentY

Comentarios

Las coordenadas se miden a partir de la esquina superior izquierda del objeto. El valor de la
propiedad CurrentX es 0 en el borde izquierdo de un objeto, y el valor de la propiedad
CurrentY es 0 en el borde superior. Las coordenadas se expresan en las unidades de medida
definidas por las propiedades ScaleHeight y ScaleWidth. Si se han introducido estas
propiedades (como recomendábamos mas atrás), la propiedad ScaleMode se pone
automáticamente a User. Si no se establecen, ScaleMode puede estar en Twips, Point, Pixeles,
caracteres, .... unidades que supongo le serán mucho mas difícil de controlar que si Vd. dice
desde el principio que el papel de su impresora tiene unas medidas de 2100 por 2970
(Printer.ScaleWidth = 2100, Printer.ScaleHeight = 2970) Haciéndolo de esta última forma,
cuando queramos dibujar una línea entre dos puntos de nuestro papel DIN A4 bastará con
medir las coordenadas de inicio y final de línea, eso sí, usando como unidad de medida la
décima de milímetro. Por ejemplo, una línea a 5 mm del borde superior, que comience a 20
mm. Del borde izquierdo y termine a 10 mm del borde derecho, se dibujaría con la siguiente
instrucción :

Printer.Line (200,50) - (2870,50)

Si queremos escribir datos en una columna, que está a 30 mm. de la parte izquierda de la hoja,
comenzaremos a escribir cada fila de esa columna con un CurrentX de 300. Para ello primero
fijaremos el punto de inicio mediante CurrentX y a continuación usaremos el método Print :

Printer.CurrentX = 300 : Printer.CurrentY = (lo que corresponda a esa fila)


Printer.Print MiVariable ‘ donde MiVariable contiene el dato a escribir

CurrentX y CurrentY se quedan con los valores establecidos por el último método gráfico o
método Print usado.

Cuando se está dibujando sobre el objeto Printer, los métodos gráficos Circle y Line
establecen los siguientes valores para CurrentX y CurrentY :

Circle El centro del objeto.


Line El punto final de una línea.

El método Print establece como CurrentX la coordenada correspondiente a la parte derecha de


la última letra impresa. Como CurrentY depende de si ha terminado la sentencia Printer.Print
MiVariable con punto y coma ( ;) o sin el. En el primer caso, CurrentY es el mismo que tenía
antes de realizar ese método. En el segundo caso, avanza automáticamente una línea.

Cuando se envía la instrucción EndDoc establece los valores de estas propiedades a 0, 0.


NewPage establece igualmente los valores 0, 0.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 17


DeviceName

Devuelve el nombre del dispositivo permitido por un controlador. Esta propiedad es solo de
lectura

Sintaxis Printer.DeviceName

Cada controlador de impresora acepta uno o más dispositivos por ejemplo, HP LaserJet III es
un nombre de dispositivo.

DrawMode

Devuelve o establece un valor que determina el aspecto de la salida de un método gráfico. Vea
la Ayuda de VB para mayor detalle.

DrawStile

Devuelve o establece un valor que determina el estilo de línea de la salida de métodos gráficos.

Sintaxis Printer.DrawStyle [= número]

El número especifica el estilo de línea :

0 (Predeterminado) Continuo.
1 Rayas.
2 Puntos.
3 Raya - punto.
4 Raya - punto - punto.
5 Transparente.
6 Continuo interior.

Observaciones

Si DrawWidth se define con un valor mayor que 1, los valores de DrawStyle entre 1 y 4
producen una línea continua (el valor de la propiedad DrawStyle no cambia). Si DrawWidth se
define como 1, DrawStyle produce el efecto para cada valor descrito en la tabla anterior.

DrawWidth

Devuelve o establece la anchura de línea de lo dibujado con los métodos gráficos.

Sintaxis Printer.DrawWidth [= tamaño]

tamaño es una expresión numérica comprendida entre 1 y 32.767 que representa la anchura de
la línea en pixeles. El valor predeterminado es 1, es decir, un píxel de ancho.

Comentarios

Puede incrementar el valor de esta propiedad para aumentar la anchura de la línea. Si el valor
de la propiedad DrawWidth es mayor que 1, los valores de 1 a 4 en la propiedad DrawStyle
producirán una línea continua (el valor de DrawStyle no se modifica). Si se establece 1 en
DrawWidth, DrawStyle producirá los resultados mostrados en la tabla de esta propiedad.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 18


DriverName

Devuelve el nombre del controlador de un objeto Printer. Esta propiedad es solo de lectura

Sintaxis Printer.DriverName

Cada controlador tiene un nombre único. Por ejemplo, el DriverName de varias impresoras
Hewlett-Packard es HPPCL5MS. El DriverName es normalmente el nombre de archivo del
controlador sin la extensión.

Duplex

Devuelve o establece un valor que determina si las páginas se imprimen por los dos lados (si la
impresora tiene esta característica). No disponible en tiempo de diseño.

Sintaxis Printer.Duplex [= valor]

Donde valor es un valor o constante que especifica el tipo de impresión, tal como se describe a
continuación

Constante Valor Descripción

bPRDPSimplex 1 Impresión en una sola cara con la orientación actual.


vbPRDPHorizontal 2 Impresión en dos caras con vuelta de página
horizontal.
vbPRDPVertical 3 Impresión en dos caras con vuelta de página vertical.

Con impresión a doble cara horizontal, la parte superior de ambas caras de la hoja están en el
mismo borde de la hoja. Con impresión a doble cara vertical, la parte inferior de una página está
en el mismo borde de la hoja que la parte superior de la página siguiente. Véase el gráfico
existente en la ayuda de VB para la propiedad Duplex

FillColor

Devuelve o establece el color usado para rellenar formas; FillColor también se usa para rellenar
círculos y cuadros creados con los métodos gráficos Circle y Line.

Sintaxis Printer.FillColor [ = valor]

Donde valor es un valor o constante que determina el color de relleno. El valor puede
introducirse como RGB o con las constantes QB color

ejemplos
FillColor = QBColor(8)
FillColor = RGB (255,0,0)
El color predeterminado es el 0 (Negro).

FillStyle

Devuelve o establece el modelo usado para rellenar dibujos (círculos y los cuadros creados con
los métodos gráficos Circle y Line.

Sintaxis printer.FillStyle [= número]

Donde número Un entero que especifica el estilo de relleno, tal como se describe a
continuación

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 19


Valor Descripción

0 Continuo.
1 (Predeterminado) Transparente.
2 Línea horizontal.
3 Línea vertical.
4 Diagonal hacia arriba.
5 Diagonal hacia abajo.
6 Cruzado.
7 Diagonal Cruzada.

Cuando la propiedad FillStyle se define con su valor predeterminado, 1 (Transparente), el valor


de FillColor se ignora.

Font

Devuelve o establece el objeto Font (letra) del objeto Printer. Este objeto Font tiene a su vez
sus propiedades (Name, Size, Bold, Italic ... )

Podemos forzar la fuente a usar por el objeto Printer con un CommonDialog, igualando la
propiedad Name del objeto Font del Printer a la propiedad FontName del CommonDialog

Printer.Font.Name = CD1.FontName

Podemos averiguar que fuente está usando el objeto Printer :

Tipofuente = Printer.Font.Name

FontCount

Devuelve el número de fuentes disponibles para el dispositivo de presentación actual o la


impresora activa. (Devuelve un número) Es solamente de lectura.

Sintaxis numerodefuentes = Printer.FontCount

FontName

Devuelve el nombre de la fuente que está usando el objeto Printer

Sintaxis nombredelafuente = Printer.Fontname

(El Objeto Printer admite esta propiedad como Font.Name o FontName indistintamente)

Fonts

Devuelve todos los nombres de fuente disponibles para el dispositivo de presentación actual o
la impresora activa.

Sintaxis Printer.Fonts(índice)

La propiedad Fonts funciona de forma conjunta con la propiedad FontCount, que devuelve el
número de nombres de fuente disponibles para el objeto. Las fuentes disponibles en Visual
Basic varían de acuerdo con la configuración del sistema, y los dispositivos de presentación y
de impresión. Use las propiedades Fonts y FontCount para obtener información sobre las
fuentes disponibles para pantalla o impresora.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 20


Por ejemplo, si queremos ver en Label1 todas las fuentes disponibles para el objeto Printer,
estableceremos el siguiente código :

For i = 1 To Printer.FontCount
Label1.Caption = Label1.Caption + " " + Printer.Fonts(i)
Next i

FontSize

Devuelve o establece el tamaño de la fuente a utilizar para el texto mostrado en un control o en


una operación de dibujo o impresión en tiempo de ejecución.

Sintaxis Printer.FontSize = puntos

Donde puntos es una expresión numérica que especifica el tamaño de fuente a utilizar, en
puntos.

Puede utilizar esta propiedad para dar al texto el tamaño que desee. El valor predeterminado lo
determina el sistema. Para cambiar este valor, especifique el nuevo tamaño de la fuente en
puntos.
El valor máximo de FontSize es 2160 puntos.

Nota Las fuentes disponibles en Visual Basic varían dependiendo de la configuración del
sistema y de los dispositivos de presentación e impresión. En las propiedades relacionadas con
las fuentes sólo pueden establecerse valores para los que exista una fuente.

(El objeto Printer acepta tanto Font.Size como FontSize)

FontBold, FontItalic, FontStrikethru y FontUnderline

Devuelve o establece los estilos de fuente en los siguientes formatos: Negrita, Cursiva,
Tachada y Subrayada.

Printer.FontBold [= lógico] ‘ p.e Printer.FontBold = True escribiría con


Printer.FontItalic [= lógico] ‘ letra negrita
Printer.FontStrikethru [= lógico]
Printer.FontUnderline [= lógico]

Para el objeto Printer, el establecimiento de estas propiedades no afecta al texto ya escrito,


solamente para lo que se escriba después de cambiar la propiedad. Aprovecha esta facilidad
para cambiar de letra a lo largo de un documento.

En general, deberá modificar la propiedad FontName antes de establecer los atributos de


tamaño y estilo con las propiedades FontSize, FontBold, FontItalic, FontStrikethru y
FontUnderline. Sin embargo, cuando especifique un tamaño inferior a 8 puntos para una
fuente TrueType, primero deberá establecer el tamaño en puntos con la propiedad FontSize,
luego especificar la propiedad FontName y después establecer de nuevo el tamaño con
FontSize. El entorno operativo Microsoft Windows utiliza una fuente distinta para las fuentes
TrueType con un tamaño inferior a 8 puntos.

Printer acepta FontBold ó Font.Bold, FontItalic ó Font.Italic ....

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 21


FontTransparent

Devuelve o establece un valor Booleano que determina si el texto y los gráficos de fondo de un
objeto Printer, se muestran en el espacio situado entre los caracteres.

Sintaxis Printer.FontTransparent = True / False

La modificación de FontTransparent en tiempo de ejecución no afecta a los gráficos ni el texto


ya dibujados en un objeto Printer .

ForeColor

Devuelve o establece el color de escritura para impresoras en color. El cambio de color afecta
solamente al texto que se envíe después de realizar el cambio.

hDC

Devuelve un controlador proporcionado por el entorno operativo Microsoft Windows para el


contexto de dispositivo de un objeto.

Sintaxis Printer.hDC

Esta propiedad es un controlador de contexto de dispositivo del entorno operativo Windows. El


entorno operativo Windows se encarga de la presentación del sistema asignando un contexto
de dispositivo al objeto Printer. Se puede usar la propiedad hDC para referirse al controlador del
contexto de dispositivo de un objeto. Así se obtiene un valor que se pasa en las llamadas al API
de Windows.
Nota El valor de la propiedad hDC puede cambiar en tiempo de ejecución, así que no se debe
almacenar en una variable. En su lugar, use la propiedad hDC cada vez que lo necesite.

Height Width

Devuelven o establecen las dimensiones del objeto Printer. No están disponibles en tiempo de
diseño.

Sintaxis Printer.Height = número


Printer.Width = número

Donde número indica las dimensiones del papel configurado para el dispositivo de impresión.
No disponibles en tiempo de diseño. Si se establecen en tiempo de ejecución, los valores de
estas propiedades se utilizarán en lugar del de la propiedad PaperSize.

Para el objeto Printer, estas propiedades se miden siempre en twips. Si establece las
propiedades Height y Width para un controlador de impresora que no admite su uso, no se
producirá ningún error, y el tamaño del papel continuará siendo el mismo.

¡¡¡ Es mas recomendable utilizar la propiedad PaperSize para establecer las dimensiones del
papel. !!!

Orientation

Devuelve o establece un valor que indica si los documentos se imprimen con orientación
vertical u horizontal. No disponible en tiempo de diseño.

Sintaxis Printer.Orientation = valor

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 22


valor es un valor o constante que determina la orientación de la página, según se describe a
continuación :

Constante Valor Descripción

vbPRORPortrait 1 Los documentos se imprimen con el lado más corto


arriba.

vbPRORLandscape 2 Los documentos se imprimen con el lado más largo


arriba.

Page
Devuelve el número de página actual.

Sintaxis Variable = Printer.Page ‘Variable contiene el número de la pág. actual

Visual Basic mantiene un contador de páginas impresas desde el inicio de la aplicación o desde
la última vez que se utilizó la instrucción EndDoc en el objeto Printer. Este contador comienza
por uno y se incrementa en uno cada vez que:

Se utiliza el método NewPage.


Se utiliza el método Print y el texto a imprimir no cabe en la página actual.

Nota La salida de los métodos gráficos que no quepa en la página actual no genera una
página nueva, sino que se recorta para ajustarla a la zona de impresión de la página.

PaperBin
Devuelve o establece un valor que indica la bandeja predeterminada para la alimentación de
papel durante la impresión. No disponible en tiempo de diseño.

Sintaxis Printer.PaperBin = valor

valor es un valor o constante que especifica la bandeja predeterminada, según se describe a


continuación :
Constante Valor Descripción

vbPRBNUpper 1 Utilizar papel de la bandeja superior.


vbPRBNLower 2 Utilizar papel de la bandeja inferior.
vbPRBNMiddle 3 Utilizar papel de la bandeja intermedia.
vbPRBNManual 4 Esperar a la inserción manual de cada hoja.
vbPRBNEnvelope 5 Utilizar sobres del alimentador de sobres.
vbPRBNEnvManual 6 Utilizar sobres del alimentador de sobres, pero esperar
a la inserción manual.
vbPRBNAuto 7 (Predeterminado) Utilizar papel de la bandeja
predeterminada actual.
vbPRBNTractor 8 Utilizar papel del alimentador por tracción.
vbPRBNSmallFmt 9 Utilizar papel del alimentador de papel pequeño.
vbPRBNLargeFmt 10 Utilizar papel de la bandeja de papel grande.
vbPRBNLargeCapacity 11 Utilizar papel del alimentador de gran capacidad.
vbPRBNCassette 14 Utilizar papel del cartucho de cassette adjunto.

No todas las opciones están disponibles en todas las impresoras. Consulte la documentación
de la impresora para obtener descripciones más específicas de estas opciones.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 23


PaperSize
Devuelve o establece un valor que indica el tamaño de papel para la impresora actual. No
disponible en tiempo de diseño. El valor predeterminado es el establecido en la configuración de
la impresora en Windows. Con esta propiedad no se debe jugar alegremente. El valor que se le
dé a esta propiedad será el tamaño de ese papel “ficticio” que comentábamos mas atrás.

Sintaxis Printer.PaperSize = valor

valor es un valor o constante que especifica el tamaño del papel, según se describe a
continuación
Constante Valor Descripción

vbPRPSLetter 1 Carta, 8 ½ x 11 .
vbPRPSLetterSmall 2 Carta pequeña, 8 ½ x 11 .
vbPRPSTabloid 3 Tabloide, 11 x 17 .
vbPRPSLedger 4 Libro, 17 x 11 .
vbPRPSLegal 5 Legal, 8 ½ x 14 .
vbPRPSStatement 6 Declaración, 5 ½ x 8 ½ .
vbPRPSExecutive 7 Ejecutivo, 7 ½ x 10 ½ .
vbPRPSA3 8 A3, 297 x 420 mm
vbPRPSA4 9 A4, 210 x 297 mm
vbPRPSA4Small 10 A4 pequeño, 210 x 297 mm
vbPRPSA5 11 A5, 148 x 210 mm
vbPRPSB4 12 B4, 250 x 354 mm
bPRPSB5 13 B5, 182 x 257 mm
vbPRPSFolio 14 Folio, 8 ½ x 13 .
vbPRPSQuarto 15 Cuarto, 215 x 275 mm
vbPRPS10x14 16 10 x 14 .
vbPRPS11x17 17 11 x 17 .
vbPRPSNote 18 Nota, 8 ½ x 11 .
vbPRPSEnv9 19 Sobre #9, 3 7/8 x 8 7/8 .
vbPRPSEnv10 20 Sobre #10, 4 1/8 x 9 ½ .
vbPRPSEnv11 21 Sobre #11, 4 ½ x 10 3/8 .
vbPRPSEnv12 22 Sobre #12, 4 ½ x 11 .
vbPRPSEnv14 23 Sobre #14, 5 x 11 ½ .
vbPRPSCSheet 24 Hoja tamaño C
vbPRPSDSheet 25 Hoja tamaño D
vbPRPSESheet 26 Hoja tamaño E
vbPRPSEnvDL 27 Sobre DL, 110 x 220 mm
vbPRPSEnvC3 29 Sobre C3, 324 x 458 mm
vbPRPSEnvC4 30 Sobre C4, 229 x 324 mm
vbPRPSEnvC5 28 Sobre C5, 162 x 229 mm
vbPRPSEnvC6 31 Sobre C6, 114 x 162 mm
vbPRPSEnvC65 32 Sobre C65, 114 x 229 mm
vbPRPSEnvB4 33 Sobre B4, 250 x 353 mm
vbPRPSEnvB5 34 Sobre B5, 176 x 250 mm
vbPRPSEnvB6 35 Sobre B6, 176 x 125 mm
vbPRPSEnvItaly 36 Sobre, 110 x 230 mm
vbPRPSEnvMonarch 37 Sobre monarca, 3 7/8 x 7 ½ .
vbPRPSEnvPersonal 38 Sobre, 3 5/8 x 6 ½ .
vbPRPSFanfoldUS 39 Doblado estándar EE.UU., 14 7/8 x 11 .
vbPRPSFanfoldStdGerman 40 Doblado estándar alemán, 8 ½ x 12 .
vbPRPSFanfoldLglGerman 41 Doblado legal alemán, 8 ½ x 13 .
vbPRPSUser 256 Definido por el usuario

Al establecer las propiedades Height o Width de una impresora, se establece automáticamente


vbPRPSUser en PaperSize.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 24


Port

Devuelve el nombre del puerto a través del cual se envía un documento a una impresora.

Sintaxis puertousado = Printer.Port

El sistema operativo determina el nombre del puerto, como por ejemplo LPT1: o LPT2:.

PrintQuality

Devuelve o establece un valor que indica la resolución de la impresora. No disponible en tiempo


de diseño.

Sintaxis Printer.PrintQuality = valor

valor es un valor o una constante que especifica la resolución de la impresora, según se


describe a continuación :

Constante Valor Descripción

vbPRPQDraft -1 Resolución borrador


vbPRPQLow -2 Resolución baja
vbPRPQMedium -3 Resolución media
vbPRPQHigh -4 Resolución alta

Además de los valores negativos predefinidos, también puede indicarse en valor un número
positivo de puntos por pulgada, como por ejemplo 300.

El valor predeterminado depende del controlador de la impresora y de su configuración actual.


El efecto de estos valores varía según la impresora y el controlador. En ciertas impresoras,
algunas opciones, o todas ellas, pueden producir el mismo resultado.

ScaleHeight, ScaleWidth

¡ Estas propiedades ya se comentaron mas atrás. Es completamente necesario entender estas


propiedades para poder manejar y dominar el objeto Printer. !

Devuelven o establecen el número de unidades de medida horizontal (ScaleWidth) y vertical


(ScaleHeight) del interior del papel donde vamos a volcar la información del objeto Printer.

Sintaxis Printer.ScaleHeight = valor


Printer.ScaleWidth = valor

Donde valor es una expresión numérica que especifica la medida horizontal o vertical. Este
valor va a determinar el número de unidades de medida que tiene el papel, NO su medida. Es
decir, podemos decir, mediante estas propiedades, que el papel tiene 2100 unidades de ancho
y 2970 unidades de alto. Si el papel es un DIN A4 (Medidas 210 x 297 mm) esa unidad de
medida sería precisamente una décima de milímetro. Podríamos haber elegido otros valores,
con lo que esa unidad de medida ya no serían décimas de mm. Sería una unidad de medida
cualquiera, pero el papel seguiría siendo DIN A4 y seguiría teniendo las mismas medidas
reales.

ScaleLeft, ScaleTop

Devuelven o establecen las coordenadas horizontal (ScaleLeft) y vertical (ScaleTop) de los


bordes izquierdo y superior de un objeto al utilizar métodos gráficos o al situar controles.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 25


Sintaxis Printer.ScaleLeft = valor
Printer.ScaleTop = valor

donde valor es una expresión numérica que especifica la coordenada horizontal o vertical. El
valor predeterminado es 0.

Con estas propiedades y las relacionadas ScaleHeight y ScaleWidth, puede configurar un


sistema de coordenadas completo, con coordenadas positivas y negativas. Estas cuatro
propiedades de escala se relacionan con la propiedad ScaleMode de la siguiente forma:

Al establecer un valor en cualquier otra propiedad de escala, en ScaleMode se establece


automáticamente 0.
Al establecer en ScaleMode un número mayor que 0, ScaleHeight y ScaleWidth cambian a la
nueva unidad de medida, y en ScaleLeft y ScaleTop se establece 0. Además, los valores de
CurrentX y CurrentY cambian para reflejar las nuevas coordenadas del punto actual.

Resumiéndolo en palabras mas sencillas. Si, con las medidas de los ejemplos anteriores
(ScaleWidth = 2100, ScaleHeight = 2970) ponemos Printer.ScaleLeft = - 1050 estamos
diciendo que la coordenada horizontal absoluta en la parte izquierda de la hoja es de -1050. Si
el ancho del papel es de 2100, la coordenada X absoluta del eje central del papel será entonces
0. Y la coordenada X de la parte derecha del papel será + 1050. Por lo tanto, si ejecutamos el
método gráfico :

Printer.Circle (0,1000), 300

dibujará un circulo de radio 300, con el centro en el eje vertical de la hoja (Coordenada X=0) a
una altura de 1000 (Coordenada Y=1000) de la parte superior del papel.

Si hubiésemos puesto Printer.ScaleTop = - 1500 estaríamos diciendo que la coordenada Y


absoluta de la parte superior del papel es - 1500. En ese caso, el círculo anterior se colocaría a
una distancia de 2500 (2500 = 1000 + 1500) del borde superior del papel.

ScaleMode
Devuelve o establece un valor que indica la unidad de medida de las coordenadas de un objeto
al utilizar métodos gráficos, o al situar controles.

Sintaxis Printer.ScaleMode = valor

donde valor es un número entero que especifica la unidad de medida, según se describe a
continuación

0 User. Indica que una o más de las propiedades ScaleHeight, ScaleWidth, ScaleLeft y
ScaleTop tienen valores personalizados.
1 (Predeterminado) Twip (1440 twips por pulgada lógica; 567 twips por centímetro
lógico).
2 Punto (72 puntos por pulgada lógica).
3 Píxel (la unidad mínima de la resolución del monitor o la impresora).
4 Carácter (horizontal = 120 twips por unidad; vertical = 240 twips por unidad).
5 Pulgada.
6 Milímetro.
7 Centímetro.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 26


Recomendación del autor de esta Guía del Estudiante. Una vez mas recomiendo que
controle la posición de los métodos gráficos y método Print fijando las unidades de medida
mediante ScaleHeight, ScaleWidth, (Si le es práctico, emplee ScaleLeft y ScaleTop para que le
coincida el punto central del papel con las coordenadas 0,0 y así usaría coordenadas positivas y
negativas) y cada vez que escriba o dibuje, coloque el “cursor” de escritura mediante las
propiedades CurrentX y CurrentY

TrackDefault

Devuelve o establece un valor booleano que determina si el objeto Printer apunta siempre a la
misma impresora, o si la impresora a la que apunta cambia cuando se modifica la impresora
predeterminada en el Panel de control del sistema operativo. No disponible en tiempo de
diseño.

Sintaxis Printer.TrackDefault = lógico

Donde lógico es una expresión booleana que determina la impresora a la que apunta el objeto
Printer, según se describe a continuación.

True (Predeterminado) El objeto Printer cambia la impresora a la que apunta al modificar la


impresora predeterminada en el Panel de control del sistema operativo.
False El objeto Printer continúa apuntando a la misma impresora cuando se modifica la
impresora predeterminada en el Panel de control del sistema operativo.

Al modificar el valor de la propiedad TrackDefault mientras se realiza un trabajo de impresión,


se envía una instrucción EndPage implícita al objeto Printer.

TwipsPerPixelX, TwipsPerPixelY

Devuelve el número de twips per pixel de un objeto medido horizontal (TwipsPerPixelX) o


verticalmente (TwipsPerPixelY).

Sintaxis Printer.TwipsPerPixelX
Printer.TwipsPerPixelY

En general, las rutinas del API de Windows requieren las medidas en píxels. Puede utilizar
estas propiedades para convertir rápidamente las dimensiones sin cambiar el valor de la
propiedad ScaleMode de los objetos.

Zoom

Devuelve o establece el porcentaje en que se amplía o reduce el resultado impreso. No está


disponible en tiempo de diseño.

Sintaxis Printer.Zoom = numero

Donde numero es una expresión numérica que evalúa en el porcentaje de ajuste de la salida
impresa. El valor predeterminado es 0, que especifica que la página impresa aparece con su
tamaño normal.

Comentarios

El valor de la propiedad Zoom ajusta el tamaño de la página impresa, en un factor de


Zoom/100, en relación con el tamaño aparente de la salida impresa. Por ejemplo, una página
de tamaño carta impresa con Zoom establecido como 50 contiene tantos datos como una
página de tamaño 17 por 22 pulgadas, porque el texto y los gráficos impresos se reducen a la
mitad de su altura y anchura originales.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 27


El objeto Printers (Colección de objetos Printer)

La colección Printers le permite consultar las impresoras disponibles de forma que pueda
especificar la impresora predeterminada de la aplicación. Por ejemplo, se puede querer saber
cual de las impresoras disponibles usa un controlador de impresoras determinado. El siguiente
código comprueba todas las impresoras disponibles para saber la primera impresora cuya
orientación de página sea vertical:

Dim X As Printer
For Each X In Printers
If X.Orientation = vbPRORPortrait Then
' la define como predeterminada.
Set Printer = X
' Sale del bucle.
Exit For
End If
Next

Usando la instrucción Set se designa una de las impresoras de la colección Printers como
impresora predeterminada. El ejemplo anterior designa la impresora identificada por la variable
de objeto X, como impresora predeterminada de la aplicación.

Nota Si la colección Printers se usa para especificar una impresora concreta, como
Printers(3), sólo se puede tener acceso a sus propiedades de modo lectura. Para leer y escribir
las propiedades de una impresora concreta, primero se tiene que definir como impresora
predeterminada de la aplicación.

METODOS DEL OBJETO PRINTER

Circle

Dibuja un círculo, elipse o arco sobre un objeto. No acepta argumentos con nombre.

Sintaxis Printer.Circle Step (x, y), radio, color, inicio, final, aspecto

Vea una explicación completa de este método en el capítulo 7 Métodos Gráficos.

EndDoc

Termina una operación de impresión enviada al objeto Printer, liberando el documento al


dispositivo de impresión o a la cola.

Sintaxis Printer.EndDoc

Si EndDoc se invoca inmediatamente después del método NewPage, no se imprime la página


en blanco adicional.

KillDoc

Termina inmediatamente el trabajo de impresión actual.

Sintaxis Printer.KillDoc

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 28


Si el Administrador de impresión del sistema operativo controla el trabajo de impresión (el
Administrador de impresión está ejecutándose y la impresión en segundo plano está activada),
KillDoc elimina el trabajo de impresión actual y la impresora deja de recibir datos.
Si el Administrador de impresión no está controlando el trabajo de impresión (la impresión en
segundo plano está desactivada), puede que algunos o todos los datos se envíen a la
impresora antes de que KillDoc pueda tener efecto. En este caso, el controlador de la
impresora inicializa la impresora en cuanto puede y termina el trabajo de impresión.

Line

Dibuja líneas y rectángulos en un objeto. No acepta argumentos con nombre.

Sintaxis Printer.Line Step (x1, y1) - Step (x2, y2), color, BF

Vea este método mas ampliamente en el capítulo 7 Métodos Gráficos.

NewPage

Termina la página actual y avanza a la página siguiente en el objeto Printer.

Sintaxis Printer.NewPage

NewPage avanza a la página siguiente y restablece la posición de impresión en la esquina


superior izquierda de la nueva página. Cuando se le llama, NewPage incrementa la propiedad
Page del objeto Printer en 1.

PaintPicture

Presenta el contenido de un archivo gráfico (.BMP, .WMF, .EMF, .ICO o .DIB) en un objeto
Printer. No acepta argumentos con nombre.

Sintaxis

Printer.PaintPicture imagen, x1, y1, anchura1, altura1, x2, y2, anchura2, altura2, opecod

Puede ver mas información acerca de este método en el capítulo 7 Métodos Gráficos

Print

Imprime texto en el objeto Printer.

Sintaxis Printer.Print lista_salida

Donde lista_salida es una expresión o lista de expresiones a imprimir. Si se omite, se imprimirá


una línea en blanco.

En el argumento lista_salida puede poner un texto directamente (Printer.Print “Hola”) o una


variable (Printer.Print Textoaescribir). Puede también introducir algunas funciones de cadena
como la siguiente:

Spc(n) Se utiliza para insertar caracteres espacio en la salida, donde n es el número de


espacios a insertar.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 29


Puede introducir también Tabuladores :
Tab(n) Se utiliza para situar el punto de inserción en un número de columna absoluto, donde n
es el número de columna. Utilice Tab sin argumentos para situar el punto de inserción en la
línea siguiente, al principio de la zona de impresión.

Nota.- El uso de los tabuladores puede traerle mas problemas que ventajas. Los pasos de
tabulación dependen de cada impresora, y lo que es peor, de la programación de la propia
impresora. Por lo tanto, al usar Tab no controlamos del todo la posición de las columnas. Es
mucho mas práctico (y seguro) usar Printer.CurrentX y Printer.CurrentY para posicionar el
“puntero” de escritura del Objeto Printer.

Al terminar de imprimir Cualquier carácter o tabulador, el objeto Printer generará un Retorno de


Carro y un Avance de Línea, excepto que terminemos el método Print con un punto y coma :

Las instrucciones :

Printer.Print “Hola”
Printer.Print “¿Qué tal ?” generarán la siguiente salida por impresora :

Hola
¿Qué tal ?

Si pusiésemos

Printer.Print “Hola ” ;
Printer.Print “¿Qué tal ?” la salida por impresora sería :

Hola ¿Qué tal ?

Nota Debido a que el método Print imprime normalmente con caracteres de espaciado
proporcional, es importante recordar que no hay relación entre el número de caracteres
impresos y el número de columnas de anchura fija que tales caracteres ocupan. Por ejemplo,
una letra ancha, como W, ocupa más de una columna de anchura fija, mientras que una letra
estrecha, como I, ocupa menos. Para tener en cuenta los casos en el que se utilizan caracteres
con una anchura mayor que la media, deberá asegurarse de que las columnas de las tablas se
encuentren lo bastante lejos unas de otras. Como alternativa, puede utilizar en la impresión una
fuente de anchura fija (como Courier) para hacer que cada carácter utilice sólo una columna.

Para controlar perfectamente el punto donde se escribirá el siguiente carácter, utilice las
propiedades CurrentX y CurrentY. Es mucho mas práctico que usar, por ejemplo, el Tabulador
Tab(n)

Si usa Tab(n) con una determinada impresora, puede verse con la desagradable sorpresa que
en otra impresora no funciona de la misma forma. Como al desarrollar una aplicación nunca
sabe sobre que impresora va a imprimir, es mejor que no utilice Tab(n), sustituyéndolo por
CurrentX.

Método TextWidth

Puede conocer la anchura que va a ocupar un texto en la impresora. (o en un Formulario, en un


Picture) usando el Método TextWidth

AnchodelTexto = Printer.TextWidth (Textoaescribir)

Donde AnchodelTexto es una variable tipo Long que indicará el ancho (en las unidades de
medida definidas para el objeto Printer - Twips, Pixels, mm, o como siempre recomendaré, las
establecidas mediante ScaleWidth y ScaleHeight) y Textoaescribir es una variable tipo String
que contiene el texto a escribir.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 30


Si la cadena de texto cuya longitud de impresión queremos analizar contiene retornos de carro,
TextWidth devuelve la anchura de la línea más larga.

Mediante este método puede escribir columnas de datos, mucho mejor que usando el Tab(n).
Suponga que quiere escribir en una columna, los datos Dato(1), Dato(2), ....Dato(N) que son
números. Quiere escribirlos de tal forma que la parte derecha del número quede alineada, como
hacemos casi siempre para poder sumarlos con facilidad. Supongamos que hemos establecido
las Propiedades Printer.ScaleWidth = 21000 y Printer.ScaleHeight = 29700. Damos por hecho
que el papel es un DIN A-4 (210 x 297 mm) por lo que estamos usando, como unidad de
medida en ambas coordenadas la centésima de mm.

Si queremos que las cifras queden alineadas en una columna cuya parte final sea 5000 (la
parte final de esa columna quedará a 50 mm. del margen izquierdo del papel), deberemos
calcular la longitud de cada cifra, y poner, como inicio de escritura de esa cifra 5000 - ancho :

Haríamos un bucle mas o menos como este :

Dim Ancho as Long ‘Ancho será una variable Long


For I = 1 To N ‘Imprimiremos N datos
Ancho = Printer.TextWidth (Str(Dato(I))) ‘Calculamos el ancho (para el Printer) de cada
Printer.CurrentX = 5000 - Ancho ‘dato. Lo restamos a 5000 para que queden
Printer.CurrentY = K +(300 * I) ‘alineados por atrás. La coordenada Y
Printer.Print Str(Dato(I)) ‘será una constante K mas 3 mm
Next I

Observe que el ancho de una determinada cadena de caracteres no tiene porqué ser la misma
para un Formulario que para el Printer. Dependerá del tipo de fuente y del tamaño de esa fuente
que usemos en cada caso. Por eso, debe poner siempre Printer.TextWidth, Form1.TextWidth,
etc.

Método TextHeight

Este método es idéntico al anterior, pero relativo a la altura. No vamos a alargar la explicación
dada la similitud con el anterior. Este método nos permite separar adecuadamente las líneas de
un escrito. Es muy útil sobre todo cuando utilizamos distintos tipos de letra dentro del mismo
escrito.

Método PSet

Asigna a un punto de un objeto Printer un color especificado. No acepta argumentos con


nombre.

Sintaxis Printer.PSet Step (x, y), color

Step Opcional. Palabra reservada que especifica que las coordenadas son relativas
a la posición gráfica actual proporcionada por las propiedades CurrentX y CurrentY.

(x, y) Requeridos. Valores de simple precisión que indican las coordenadas


horizontales (eje x) y verticales (eje y) del punto a establecer.

color Opcional. Valor entero largo que indica el color RGB especificado para el punto. Si se
omite, se utiliza el valor de la propiedad ForeColor. Puede utilizar la función RGB o la función
QBColor para especificar el color.

El tamaño del punto dibujado depende del valor de la propiedad DrawWidth. Cuando
DrawWidth es 1, PSet establece un píxel al color especificado. Cuando DrawWidth es mayor
que 1, se centra el punto en las coordenadas especificadas.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 31


La forma en que se dibuja el punto depende de los valores de las propiedades DrawMode y
DrawStyle.

Cuando se ejecuta PSet, las propiedades CurrentX y CurrentY toman el valor del punto
especificado en los argumentos.

Vacíe un píxel con el método PSet especificando las coordenadas del píxel y utilizando el valor
de la propiedad BackColor como argumento color.

LSB Visual Basic - Guia del Estudiante Capítulo 7 Página 32


Visual Basic - Guía del Estudiante Cap. 8

LA FUNCION SHELL
LA FUNCION COMMAND PARA PASAR PARAMETROS
LA FUNCION DoEvents
Cajas de mensaje (Mensaje Box)
Cajas de entrada de datos (Input Box)
El Objeto APP (La Aplicación)

LA FUNCION SHELL

La función Shell se utiliza para ejecutar un programa ajeno a la aplicación que se está
ejecutando. Imaginemos que tenemos una aplicación Visual Basic que necesita, por ejemplo,
establecer una comunicación telefónica, y que esa comunicación telefónica nos la realiza un
programa desarrollado en C++ , llamado MARCADOR.EXE que funciona perfectamente y no
queremos desaprovechar. Imaginemos que ese programa tiene la posibilidad de introducirle el
número telefónico que debe marcar como un parámetro. Este parámetro se le introduce,
supongamos, añadiendo el número al nombre del programa ejecutable. Por ejemplo:

MARCADOR.EXE 1234567

En nuestra aplicación Visual Basic introduciremos una línea invocando la función Shell seguida
del nombre (y Path) del ejecutable y del parámetro que le vamos a introducir al ejecutable:

Shell "C:\VB\MARCADOR.EXE 080"

Mediante esta línea, lo que hacemos es ejecutar el programa MARCADOR.EXE e introducirle


como parámetro el número a marcar. Resultado: el programa MARCADOR.EXE llama al
número 080 (Bomberos), y una vez establecida la llamada podemos pasarle a ese Organismo
datos o lo que nuestra aplicación haga.

Veamos que dice la Ayuda de VB respecto a la Función Shell:

Ejecuta un programa ejecutable.

Sintaxis Variable = Shell ( rutaDeAcceso [, estiloDeVentana] )

donde:

Variable es identificador de la tarea (ID)

rutaDeAcceso es el nombre del programa por Ejecutar (con su Path) y cualquier argumentos o
conmutadores (switches) de línea de comando requeridos; puede incluir directorio o carpeta y
unidad de disco. También puede ser el nombre de un documento que se ha asociado con un
programa ejecutable.

estiloDeVentana es el número correspondiente al estilo de la ventana en la cual se va a


ejecutar el programa. En Microsoft Windows, si se omite estiloDeVentana, el programa se inicia
minimizado con enfoque.

El argumento con nombre estiloDeVentana tiene estos valores:

Constante Valor Descripción

vbHide 0 Se oculta la ventana y se pasa el foco a la ventana oculta.


vbNormalFocus 1 La ventana recupera el foco y vuelve a su posición y tamaño
original.
vbMinimizedFocus 2 La ventana se muestra como un icono con foco.

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 1


vbMaximizedFocus 3 La ventana se maximiza con foco.
vbNormalNoFocus 4 La ventana vuelve al tamaño y posición más recientes. La
ventana activa actual permanece activa.
vbMinimizedNoFocus 6 La ventana se muestra como un icono. La ventana activa
actual permanece activa.
Comentarios

Si la función Shell ejecuta con éxito el archivo nombrado, devuelve la identificación de la tarea
(ID) del programa iniciado. La ID de la tarea es un número exclusivo que identifica el programa
en ejecución. Este número debe ser un Long. Si la función Shell no puede iniciar el programa
nombrado, ocurrirá un error. Si desea conocer el ID de la tarea, realice una aplicación con un
botón (cmbCalculadora) y un label (label1). Ponga en ese botón en su procedimiento click, el
siguiente código. - Observe que esta aplicación inicia la calculadora de Windows -

Private Sub cmbCalculadora_Click()


Dim variable As Long
variable = Shell("C:\windows\calc.exe", 1)
label1.Caption = Str(variable)
End Sub

Posiblemente lo único que le importe sea el ejecutar esa aplicación, sin dar mayor importancia
al ID de la tarea. Utilice una línea con la siguiente expresión :

Shell ("C:\windows\calc.exe"), 1

(Observe en las dos formas de ejecutar la función Shell, que la colocación de los paréntesis y la
coma separadora es distinto.

El programa a ejecutar puede ser un programa Windows caso anterior de la calculadora) o un


programa DOS.

Nota La función Shell ejecuta otros programas de manera asíncrona. Esto quiere decir que no
se puede esperar que un programa iniciado con Shell termine su ejecución antes de que se
ejecuten las instrucciones que siguen a la función Shell en la aplicación. Esto es un gran
inconveniente de la función Shell. Excepto en contadas ocasiones, siempre es necesario
conocer cuando se ha terminado de ejecutar el programa iniciado mediante Shell. Y no es ese
el único problema. La mayoría de los programas DOS que se ejecutan con Shell no se cierran
automáticamente. Esto significa que si podemos evitar el uso de Shell debe evitarse. Pero si es
completamente necesario, tampoco pasa nada. Pero hay que controlar, tanto la terminación del
proceso DOS como su cierre.

Podemos usar para ello APIs. No las hemos explicado todavía. Por eso, y adelantar un poco
como se trabaja con ellas, vamos a presentar, sin grandes explicaciones, lo que hay que hacer
para poder detectar que se ha terminado de ejecutar el programa DOS y para cerrarlo. Verá
mas APIs mas adelante.

El programa DOS elegido para este ejemplo es el popular ARJ.EXE, un compresor de datos
que, sin ánimo de publicidad, es uno de los mejores que existen. Pero trabaja solamente en
DOS. Se utiliza un Procedimiento que he llamado ExecCmdNoFocus, para detectar que el
proceso abierto para comprimir o descomprimir ha finalizado, y proceder a cerrarlo.

La declaración de las Apis y Constantes (En la sección de Declaraciones de un Módulo) es la


siguiente:

Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)


Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As _
String, ByVal lpWindowName As String) As Long

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 2


Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal _


bInheritHandle As Long, ByVal dwProcessID As Long) As Long
Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode _
As Long) As Long

Declaramos las constantes

Public Const WM_CLOSE = &H10


Public Const STILL_ACTIVE = &H103
Public Const PROCESS_QUERY_INFORMATION = &H400

El Procedimiento podemos ponerlo en el Módulo anterior o en el formulario. Variará el tipo de


declaración de las APIs:

Public Sub ExecCmdNoFocus(ByVal CmdLine As String)

(CmdLine es el parámetro que le vamos a pasar cuando invoque este procedimiento).

'Este procedimiento inicia un proceso en DOS y espera a que termine


'Una vez terminado este proceso, cierra la ventana, que se mostrará minimizada y sin foco

Declaramos las variables locales en ese procedimiento

Dim hProcess As Long 'handle del proceso donde se invoca la función Shell
Dim RetVal As Long 'Valor donde la función GetExitCode coloca el resultado
Dim winHwnd As Long ' manipulador de la ventana que contenga el Caption
‘Finalizado - ARJ
Dim RetValls As Long 'valor de retorno de PostMessage

hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, Shell(CmdLine, _


vbMinimizedNoFocus))

Do
GetExitCodeProcess hProcess, RetVal
Sleep 100
'en este apartado comprueba si está abierta la ventana "Finalizado - ARJ"
winHwnd = FindWindow(vbNullString, "Finalizado - ARJ")
If winHwnd <> 0 Then
RetValls = PostMessage(winHwnd, WM_CLOSE, 0&, 0&)
End If
Loop While RetVal = STILL_ACTIVE

End Sub

La ventana DOS del ARJ tiene el Caption Finalizado - ARJ cuando ya ha terminado el proceso.
En el procedimiento ExecCmdNoFocus se analiza si esa ventana está presente (prueba de que
ARJ ya ha terminado, pues antes de terminar tiene otro Caption).

Para llamar a ese procedimiento hay que citarle por su nombre (ExecCmdNoFocus) que como
lo hemos declarado Public en un Módulo, podemos llamarle desde cualquier parte de la
aplicación. Debemos pasarle el parámetro CmdLine, que será el programa que vamos a
ejecutar con Shell y los parámetros adicionales que este programa necesite (En este caso, el
programa es ARJ.EXE y a continuación debe indicársele el nombre del archivo ya
comprimido, a continuación a para que añada mas ficheros a ese archivo, y a continuación el
nombre de ese fichero o ficheros a añadir :

El parámetro CmdLine del procedimiento es todo lo que va entre paréntesis.

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 3


ExecCmdNoFocus ("C:\DirA\ARJ.EXE a C:\DirB\Fichero1.Ext")

NO se preocupe si no lo entiende ahora. Es difícil.

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 4


LA FUNCION COMMAND

En el ejemplo anterior usábamos un ejecutable realizado en C++ para marcar un número


telefónico que le introducíamos como parámetro. ¿Podemos hacer eso en una aplicación VB?
La respuesta debe ser SI. Usaremos para ello la función Command. Esta función nos devuelve
el parámetro introducido tras el nombre del ejecutable realizado en VB, cuando iniciamos la
aplicación VB mediante la línea de comandos de Windows (línea Archivo | Ejecutar del Menú
de Windows 3.xx o línea Ejecutar de W95), o desde otra aplicación utilizando la función Shell.

Veamos también en este caso lo que dice la Ayuda de VB:

Command (Función)

Devuelve parte del argumento de la línea de comandos utilizada para lanzar Microsoft Visual
Basic o un programa ejecutable desarrollado con Visual Basic.

Cuando se inicia Visual Basic desde la línea de comandos, la parte de la línea de comandos
que sigue a /CMD se pasa al programa como un argumento de la línea de comandos. En el
siguiente ejemplo, cmdlineargs representa la información de argumento devuelta por la función
Command.

VB /CMD cmdlineargs

En las aplicaciones desarrolladas con Visual Basic y compiladas en un archivo .EXE, Command
devuelve los argumentos que aparezcan en la línea de comandos tras el nombre de la
aplicación. Por ejemplo:

MyApp cmdlineargs

En la ventana Código, puede usted cambiar el texto devuelto por Command eligiendo Opciones
del proyecto en el menú Herramientas.

Veamos con un par de ejemplos como se pueden usar estas dos funciones:

Marcador Telefónico

Esta aplicación debe marcar un número telefónico. El número a marcar se le pasará como
parámetro tras el nombre de la aplicación. La aplicación ya compilada se llamará
MARCADOR.EXE. Para marcar un número debemos poner, en la línea de Comando de
Windows:

Marcador.exe 1234567

o como ya sabemos, introducirle el parámetro mediante una llamada con la función Shell desde
otra aplicación:

Shell Marcador.exe 1234567

Como no vamos a realizar llamada alguna, sino comprobar que esto puede funcionar, nuestra
pequeña aplicación tendrá solamente un Label llamado FRMARCADORL1 donde
presentaremos el número a marcar. Todo el código necesario se lo metemos en el
procedimiento Activate del formulario:

Private Sub Form_Activate()


FRMARCADORL1.Caption = Command
End Sub

También podemos pasar parámetros a un ejecutable, mediante el Drag & Drop de Windows.
Hemos visto mas atrás como podemos hacer Drag & Drop en una aplicación VB. Pero como
comentábamos, el D&D no es una función de VB, sino de Windows. Y Windows lo utiliza en su

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 5


Explorador de Windows para pasar como parámetro a una aplicación el nombre del fichero
que arrastremos hacia el icono que representa a esa aplicación. Como estoy seguro que se ha
liado, vamos con un ejemplo.

Si Vd. hace un editor de textos (Editor.EXE) que soporta un formato determinado (por ejemplo
el RichTextFormat RTF), para ejecutar su programa y meterle como parámetro el nombre del
fichero Carta.RTF de forma que al arrancar lea directamente el fichero Carta.RTF, basta con ir
al Explorador de Windows, abrir la carpeta que contenga Carta.RTF, arrastrar el nombre de ese
fichero y llevarlo al icono que representa a Editor.EXE, que imaginemos que le ha preparado un
acceso directo. Suelte el botón del ratón y su editor se ejecutará, y además, le meterá como
parámetro el nombre del fichero Carta.RTF (con su Path correspondiente) Si Ud. había previsto
la captura del Command tal como se explicó mas atrás, y ha preparado su aplicación para que
tome el contenido de Command y entienda que tiene que abrir y cargar ese fichero, su
aplicación Editor.EXE cargará automáticamente ese fichero. Observe que esta es la forma de
trabajar de los procesadores de texto usados normalmente (Word, WordPerfect, Write, etc.)

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 6


La Función DoEvents
Cede el control de la ejecución al sistema operativo, para que éste pueda procesar otros
eventos. También nos permite conocer el número de formularios abiertos en una aplicación.

Sintaxis DoEvents
Cede el control al sistema operativo

Sintaxis variable=DoEvents
variable contendrá un número indicando el número de formularios abiertos en
este momento.

La función DoEvents es una instrucción obligada en todos los bucles por condición para evitar
que, en caso de meterse en un bucle infinito, podamos salir de el aunque sea teniendo que
pulsar las teclas Ctrl-Alt-Sup. Si no lleva esa línea DoEvents, es posible que tenga que
resetaear el ordenador. El siguiente bucle se pone para esperar a que el programa envíe un
mensaje a través del control de comunicaciones. Este, una vez terminada la comunicación,
pone la variable Transmitido a True. Imagínese que se corta la comunicación y Transmitido
nunca llega a ser True.

Do Until Transmitido = True


Rem Si Transmitido no llega nunca a ser true, nunca podrá salir del bucle
DoEvents ‘Esta función devuelve el control al sistema operativo cada vez que se ejecuta
‘y puede comprobar si se han pulsado las teclas Ctrl-Alt-Sup
Loop

La función DoEvents devuelve también el número de formularios abiertos por una versión única
de Visual Basic, como la versión estándar de Visual Basic. DoEvents devuelve 0 en el resto de
las aplicaciones.
El control no se devuelve hasta que el sistema operativo haya terminado de procesar los
eventos en cola y que (sólo para Microsoft Windows) se hayan enviado todas las teclas en la
cola SendKeys.
Si partes de su código consumen demasiado tiempo de procesamiento, use periódicamente
DoEvents para ceder el control al sistema operativo, de manera que eventos como la entrada
por el teclado o los clics del mouse (ratón) se puedan procesar sin grandes retrasos. Utilice esta
función sobre todo, cuando tenga bucles demasiado largos que puedan interrumpir la entrada
de datos por teclado o ratón.

Precaución Asegúrese de que el procedimiento que ha cedido el control con DoEvents no se


ejecute de nuevo desde una parte diferente del código antes de que regrese la primera llamada
a DoEvents. Esto podría causar resultados impredecibles. Además, no use DoEvents si existe
la posibilidad de que otras aplicaciones interactúen con el procedimiento, de formas
imprevistas, durante el tiempo en éste ha cedido el control.

EJEMPLO

Para explicar la función DoEvents se ha preparado un pequeño ejercicio con un formulario


principal (Form1) y dos formularios auxiliares, estos últimos solamente a efectos de contar,
mediante DoEvents el número de formularios abiertos.

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 7


Se declara la variable PARAR como booleana en las declaraciones del Form1

El botón COMENZAR introduce un bucle que no pararía nunca. También pone Label1 de color
Verde.

Private Sub Command1_Click()


Label1.BackColor = RGB(0, 255, 0)
Do While PARAR = False
N=N+1
If N = 1000 Then 'Cada vez que N=1000 ejecuta la función DoEvents.
DoEvents
N=0
End If
Loop
End Sub

En el formulario Form1, al que previamente le hemos puesto la propiedad KeyPreview a True,


se le ha puesto este código en su procedimiento KeyPress:

Private Sub Form_KeyPress(KeyAscii As Integer)


PARAR = True
Label1.BackColor = RGB(255, 255, 0)
End Sub

Si no hubiésemos puesto DoEvents en una parte del bucle del contador, nunca se podría
acceder al Procedimiento KeyPress del formulario, pues el programa lo único que haría será dar
vueltas en el bucle indefinidamente.

El botón ROJO tiene este código:

Private Sub Command2_Click()


PARAR = True
Label1.Caption = DoEvents 'Aquí comprobamos los Formularios que tenemos
Label1.BackColor = RGB(255, 0, 0) 'abiertos en este momento.
End Sub

Lo mismo ocurriría con el botón ROJO. Al estar el programa haciendo el bucle continuamente,
nunca podríamos entrar el Procedimiento Click de este botón.

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 8


Los botones FORM2, cierra Form2, FORM3, cierra Form3, lo único que hacen es mostrar u
ocultar Form2 y Form3 a efectos de poder comprobar cuantos formularios tenemos abiertos.

Private Sub Command4_Click()


Form2.Show
End Sub

Private Sub Command6_Click()


Form2.Hide
End Sub

Private Sub Command5_Click()


Form3.Show
End Sub

Private Sub Command7_Click()


Form3.Hide
End Sub

Por último SALI nos saca del programa. Observe que si no hubiésemos puesto DoEvents en el
medio del bucle, tampoco podríamos salir del programa, puesto que el sistema operativo no
podría comprobar que hemos hecho Click en este botón.

Private Sub Command3_Click()


End
End Sub

Realice esta pequeña práctica con la línea DoEvents del botón COMENZAR activada y
desactivada (Con una comilla simple). Prepárese para, en este último caso, detener la
aplicación pulsando Ctr-Pausa, pues de otra forma no la podrá detener.

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 9


LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 10
Presentación Modal de formularios. Ventana modal
(Este tema ha sido tomado parcialmente de las páginas de Mundo Visual - Visual Basic.)

Se dice que un Formulario o cualquier tipo de ventana se presenta de forma Modal cuando un
elemento de ese formulario o ventana toma el foco en el momento de mostrarse, y exige que se
realice alguna gestión sobre ella antes de permitir que otra parte de la aplicación tome de nuevo
el foco. La actuación que generalmente exige un formulario o ventana es ocultarse.

Para ver esto, cree una aplicación con dos formularios. El primero (Form1) puede ser el
formulario donde se realizan todas las operaciones de la aplicación. El segundo (Form2) puede
ser el típico formulario donde se presenta la información del fabricante de la aplicación, al que
se accede normalmente desde el menú, con la palabra Acerca de...

Cree un menú en el primer formulario con esa palabra y ponga este formulario como formulario
inicial de la aplicación. En el procedimiento click de este menú ponga el siguiente código :

Form2.Show 1

El 1 detrás de la expresión Show indica que el formulario Form2 debe mostrarse de forma
Modal, lo que significa que no se podrá volver a operar con ningún elemento de Form1 hasta
que se oculte o descargue el formulario Form2. Ponga en este Form2 el típico botón de
Aceptar, cuyo código puede ser simplemente :

Me.Hide

Ejecute la aplicación y comprobará como se comporta un formulario mostrado como Modal.

Lo dicho para un formulario puede aplicarse para otro tipo de ventanas. El MessageBox y la
ventana del CommonDialog son dos ejemplos de ventanas modales. Veamos la primera :

La caja de Mensajes. MessageBox o MsgBox


Las cajas de mensajes o MessageBox, tienen una función clara, que es la de mostrar una
determinada información, aviso, o pregunta para que el usuario tenga conocimiento de ella y
actúe.

Hay 2 formas diferentes de mostrar información:

1 - El aviso es sí, que tiene por objetivo mostrar una información de interés.

2 - El aviso con espera de respuesta, que muestra una información esperando que el usuario
seleccione una de las respuestas posibles para que el programa la trate.

Una caja de mensaje, puede ser por ejemplo, la instrucción MsgBox "Hola". Por defecto, la
caja de mensaje será similar a esta:

Debe darse cuenta de algunas cosas:


En primer lugar el mensaje, "Hola" que se escribe a continuación de la palabra MsgBox,
también debe darse cuenta del botón Aceptar que tiene el Focus de la ventana activa y que sólo
hay ese botón, y por último el título de la ventana.
Podemos modificar estos parámetros para alcanzar nuestros objetivos, por eso, vamos a
escribir ahora este código: MsgBox "Hola", ,"Ejemplo" .

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 11


El resultado es:

Como podemos apreciar en el código, la caja de mensaje posee un título Ejemplo y el mensaje,
pero es posible que deseemos escribir un mensaje en varias líneas con salto de párrafo. Nada
tan fácil como este código por ejemplo: MsgBox "Hola" & vbCrLf & "Esto es un ejemplo.", ,
"Ejemplo".
El resultado es:

Habrá observado en la expresión anterior que se ha utilizado vbCrLf (Visual Basic Carriage
Return Line Feed, VB retorno de carro y avance de línea) Vea mas adelante la aclaración de
esta expresión. Con ella logramos introducir un salto de línea.

Supongo que se habrá percatado de que entre el mensaje y el título de la ventana, hemos
escrito dos comas, esto es porque entre las comas, debe ir un número que representará el
icono a mostrar. Existen cuatro iconos diferentes además de la posibilidad de no mostrar
ninguno. Los iconos son:

Estos iconos corresponden a los siguientes mensajes:


Mensaje crítico.
Mensaje de pregunta.
Mensaje exclamativo.
Mensaje de información.

(Sólo en W32. En Windows 3.xx dispone de otros diferentes, aunque con el mismo significado)

Para mostrar el icono en cuestión o para que Visual Basic lo entienda, es necesario escribir lo
siguiente:

Mensaje crítico. VbCritical ó 16


Mensaje de pregunta. VbQuestion ó 32
Mensaje exclamativo. VbExcalamqtion ó 48
Mensaje de información. VbInformation ó 64

Note que es lo mismo insertar VbCritical o 16.

Vamos a ver un ejemplo añadiendo un icono al último ejemplo:


MsgBox "Hola" & vbCrLf & "Esto es un ejemplo.", VbQuestion , "Ejemplo"

El resultado es:

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 12


Ahora bien, es posible que queramos mostrar algún otro botón que o bien no sea el de Aceptar
o que además del botón de Aceptar haya más botones. Para este propósito, tenemos los
siguientes parámetros:

Aceptar vbOKOnly ó 0
Aceptar y Cancelar vbOKCancel ó 1
Anular, Reintentar, Ignorar vbAbortRetryIgnore ó 2
Sí, No y Cancelar vbYesNoCancel ó 3
Sí y No vbYesNo ó 4
Reintentar y Cancelar vbRetryCancel ó 5
Aplicación modal vbApplicationModal ó 0 (Es la caja de mensaje sin
icono)

La forma de hacer esto es sumar al parámetro del icono que queremos mostrar el valor de los
botones que deseamos que aparezcan.
Así por ejemplo:
MsgBox "Hola" & vbCrLf & "Esto es un ejemplo.", VbQuestion + vbYesNo , "Ejemplo"
El resultado es:

Aún así, es posible que deseemos que el Focus lo adquiera otro un botón determinado. Por
ejemplo, en este caso el Focus lo tiene el botón Sí, pero es posible que deseemos que lo tenga
el botón No por ejemplo. Esto se consigue con los siguientes parámetros:
Primer botón predeterminado vbDefaultButton1 ó 0
Segundo botón predeterminado vbDefaultButton2 ó 256
Tercer botón predeterminado vbDefaultButton3 ó 512

Por ejemplo: MsgBox "Hola" & vbCrLf & "Esto es un ejemplo.", VbQuestion + vbYesNo +
vbDefaultButton2, "Ejemplo"

El resultado es:

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 13


Si no se señala el botón predeterminado, Visual Basic seleccionará el primer botón. En caso de
seleccionar como predeterminado un botón que no existe, (por ejemplo el tercero), Visual Basic
seleccionará el primero.

Ahora bien, si decidimos mostrar un mensaje esperando una respuesta, o queremos saber que
botón ha pulsado el usuario, esto lo podemos conseguir mediante el siguiente código de
respuestas:
Aceptar vbOK ó 1
Cancelar vbCancel ó 2
Anular vbAbort ó 3
Reintentar vbRetry ó 4
Ignorar vbIgnore ó 5
Sí vbYes ó 6
No vbNo ó 7

Así por ejemplo, el siguiente código:

Dim Resp As Integer


Resp = MsgBox("Hola" & vbCrLf & "Esto es un ejemplo.", VbQuestion + vbYesNo +
vbDefaultButton2, "Ejemplo")

If Resp = 6 Then
MsgBox "Ha pulsado SI"
Else
MsgBox "Ha pulsado NO"
End If

Tiene el resultado siguiente:

Si pulsamos el botón Sí obtendremos una acción, y si pulsamos el otro botón otra acción.

Ahora bien, para elegir o seleccionar un evento o acción, el usuario debe saber combinar los
códigos, sabiendo que un MsgBox posee la siguiente sintaxis principal:
MsgBox Mensaje, Botones, Título de la ventana

InputBox

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 14


El InputBox o caja de entrada es otra de las partes más utilizadas para la interacción del usuario
con la aplicación. Es importante que el usuario interactúe con la aplicación para ser el
protagonista de esta.

El InputBox nos permite sacar una caja donde el usuario pasará un parámetro, valor o dato para
que el programa lo trate y lo ejecute.

El mensaje que quiere que aparezca se realiza de forma casi idéntica al MessageBox. Puede
escribirse varias líneas de texto seguidas por la constante de Visual Basic vbCrLf o salto de
línea o párrafo.

La sentencia es: Val = InputBox (Mensaje, Titulo, ValorPredeterminado)

Val almacenará el texto escrito por el usuario, que puede ser una cantidad, cadena string, …
etc.

Por ejemplo:
Dim Val As String

Val = InputBox("Deme su nombre", "Ejemplo")


MsgBox "Su nombre es: " & Val

Tiene como resultado:

(El usuario teclea el nombre - Mundo Visual - y hace click en Aceptar. A continuación se
muestra el MsgBox - 2ª línea del código anterior )

Ahora bien, podemos determinar un texto predeterminado a la caja de entrada, como por
ejemplo:

Dim Val As String

Val = InputBox("Deme su nombre", "Ejemplo", "Mundo Visual")


MsgBox "Su nombre es: " & Val
Obtendremos como resultado:

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 15


Es importante determinar que si el usuario elige el botón Cancelar, el programa devolverá una
cadena de caracteres igual a 0, es decir, Val ="".

La caja de entrada puede ser sin embargo más personalizada mediante dos parámetros como
son la posición de la ventana de entrada de datos en la pantalla. Estos parámetros se ponen a
continuación del ValorPredeterminado.
Por ejemplo:

Dim Val As String


Val = InputBox("Deme su nombre", "Ejemplo", "Mundo Visual", 1200, 1400)
Situará la ventana en el eje de las X a 1200 Twips (posición horizontal) y la Y a 1400 twips
(posición vertical).

Reitero mi agradecimiento a Mundo Visual


http://www.ciudadfutura.com/visualbasic/

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 16


El Objeto App
El objeto App representa a la aplicación. Es el objeto Visual Basic que contiene diversas
informaciones acerca de la Aplicación.

Alguna de estas informaciones se le pueden introducir al proyecto en tiempo de diseño, en el


cuadro de Opciones. Para ello basta con ir, en la Barra de Menú de Visual Basic a
Herramientas | Proyecto | Opciones y hacer click en Proyecto. Otra parte donde se
introducen es en el cuadro de diálogo Opciones de EXE. Para ver este cuadro proceda de la
misma forma que si fuese a crear un archivo .EXE de la Aplicación, Haga click en Archivo |
Crear Archivo EXE de la Barra de Menú, y una vez que le aparezca el cuadro de diálogo para
introducir el nombre, haga click en OPCIONES.

Estas informaciones son las Propiedades del objeto App. Este objeto no tiene Métodos ni
Eventos.

Comments (Propiedad)

Devuelve o establece una cadena que contiene comentarios sobre la aplicación en ejecución.
Es de sólo lectura en tiempo de ejecución.

Sintaxis MiVariable = App.Comments

Se establece esta propiedad en tiempo de diseño usando el cuadro Opciones de EXE.

CompanyName (Propiedad)

Devuelve o establece un valor de tipo String que contiene el nombre de la empresa o del
creador de la aplicación en ejecución. Es de sólo lectura en tiempo de ejecución.

Sintaxis Mivariable = App.CompanyName

Se establece esta propiedad en tiempo de diseño usando el cuadro de Opciones de EXE. Visual
Basic toma por defecto el nombre de la compañía con que se cargó VB.

EXEName (Propiedad)

Devuelve el nombre raíz (sin la extensión) del archivo ejecutable que se está ejecutando
actualmente. Si se utiliza en el entorno de desarrollo, devuelve el nombre del proyecto.

Sintaxis MiVariable = App.EXEName

Esta propiedad se establece bien en el cuadro de Opciones, bien al guardar el archivo .EXE

FileDescription (Propiedad)

Devuelve o establece un valor de tipo String que contiene información de los archivo de la
aplicación en ejecución. Es de sólo lectura en tiempo de ejecución.

Sintaxis Mivariable = App.FileDescription

Se establece esta propiedad en tiempo de diseño usando el cuadro Opciones de EXE.

HelpFile (Propiedad)

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 17


Ya comentada mas atrás. Especifica el nombre (con su Path) del fichero de ayuda. Se introduce
en tiempo de diseño en el cuadro de Opciones. Puede cambiarse en tiempo de ejecución.

hInstance (Propiedad)

Devuelve el controlador de la instancia de la aplicación. Es un Long

Sintaxis VariableLong = App.hInstance

Cuando se trabaja en un proyecto dentro del entorno de desarrollo de Visual Basic, la propiedad
hInstance devuelve el controlador de la instancia de Visual Basic.

El valor de esta propiedad lo pone directamente Windows.

LegalCopyright (Propiedad)

Devuelve o establece un valor de tipo String que contiene información de derechos de autor
sobre la aplicación en ejecución. Es de sólo lectura en tiempo de ejecución.

Sintaxis Mivariable = App.LegalCopyright

Esta propiedad se establece en el cuadro de diálogo Opciones de EXE.

LegalTrademarks (Propiedad)

Devuelve o establece un valor de tipo String que contiene información de marca registrada
sobre la aplicación en ejecución. Es de sólo lectura en tiempo de ejecución.

Sintaxis MiVariable = App.LegalTrademarks

Establezca esta propiedad en tiempo de diseño usando el cuadro de diálogo Opciones de EXE.

Major Minor (Propiedades)

Devuelven o establecen el número mayor (menor) de la versión del proyecto. Es de sólo lectura
en tiempo de ejecución.

Sintaxis MiVariable = App.Major MiVariable = App.Minor

El valor de estas propiedades están dentro del rango 0 a 9999.


Proporcionan información sobre la versión de la aplicación en ejecución. Se establecen en
tiempo de diseño usando el cuadro de diálogo Opciones de EXE.

Revision (Propiedad)

Devuelve o establece el número de revisión de la versión del proyecto. Es de sólo lectura en


tiempo de ejecución.

Sintaxis MiVariable = App.Revision

Mediante las propiedades Major, Minor y Revision obtenemos la versión del programa. Es muy
util conocer la version del programa para saber si lo hay que actualizar. Por ejemplo, la
instrucción:

MiVariable = App.Major & “.” & App.Minor & “.” & App.Revision

Puede devolver un dato parecido a este:

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 18


MiVariable = 2.1.4

Así conocemos que la versión del programa es la 2.1.4. Estos datos de Major, Minor y Versión
hay que introducirlos en el programa durante el tiempo de diseño. Se usa para ello la caja de
Propiedades del Proyecto

Path (Propiedad)

Especifica la ruta de acceso del archivo .VBP de proyecto cuando se ejecuta la aplicación
desde el entorno de desarrollo o la ruta de acceso del archivo .EXE cuando se ejecuta la
aplicación como un archivo ejecutable.

Esta propiedad es sumamente útil. Cuando se realiza una aplicación, no es prudente obligar al
usuario a meterla dentro de un determinado directorio impuesto por el programador. Si no es
así, no sabremos en qué directorio está el ejecutable, y es muy conveniente saberlo, sobre todo
cuando se utilizan ficheros auxiliares de inicialización, que deberían estar en el mismo directorio
de la aplicación. Si queremos abrir el fichero MiAplicacion.Cfg que estará obligatoriamente en el
mismo directorio de la aplicación (aunque no conocemos su nombre), solamente tenemos que
poner la línea de código : Open App.Path & “\MiAplicacion.ICfg” For Input as # 1, sin
importarnos cual es el nombre real de ese directorio.

PrevInstance (Propiedad)

Devuelve un valor booleano que indica si hay ya en ejecución una instancia anterior de una
aplicación. Es muy utilo saber que hay una instancia del programa en ejecución para impedir
que se vuelva a abrir otra.

Sintaxis VariableBooleana = App.PrevInstance

Puede utilizar esta propiedad en un procedimiento de evento Load para determinar si el usuario
ya está ejecutando una instancia de una aplicación. Dependiendo de la aplicación, puede ser
conveniente que sólo haya una instancia de la misma en ejecución al mismo tiempo en el
entorno operativo Microsoft Windows.

ProductName (Propiedad)

Devuelve o establece un valor de tipo String que contiene el nombre de producto de la


aplicación en ejecución. Es de sólo lectura en tiempo de ejecución.

Sintaxis MiVariable = App.ProductName

Establezca esta propiedad en tiempo de diseño usando el cuadro de diálogo Opciones de EXE.

El valor de la propiedad Revision está dentro del rango 0 a 9999.Esta propiedad proporciona
información sobre la versión de la aplicación en ejecución. Esta propiedad se establece en
tiempo de diseño usando el cuadro de diálogo Opciones de EXE.

StartMode (Propiedad)

Devuelve o establece un valor que determina si una aplicación se inicia como proyecto
independiente o como servidor de automatización OLE. De sólo lectura en tiempo de ejecución.

Sintaxis VariableLong =App.StartMode

Donde Valor es un número o una constante que determina la forma de inicio :

Constante Valor Descripción

vbSModeStandalone 0 (Predeterminado) La aplicación se inicia como proyecto


independiente.

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 19


vbSModeAutomation 1 La aplicación se inicia como servidor de automatización OLE.

TaskVisible (Propiedad)

Devuelve o establece un valor que determina si la aplicación aparece en la lista de tareas de


Windows.

Sintaxis VariableBooleana = App.TaskVisible

Donde booleano puede tomar los valores True o False :

True (Predeterminado) La aplicación aparece en la lista de tareas de Windows.


False La aplicación no aparece en la lista de tareas de Windows.

La propiedad TaskVisible sólo puede establecerse a False en aplicaciones que no presenten


interfaz, como servidores OLE que no contengan o presenten objetos Form. Mientras la
aplicación disponga de interfaz gráfica, la propiedad TaskVisible se establece automáticamente
a True.

Title (Propiedad)

Devuelve o establece el título de la aplicación que aparecen en la Lista de tareas de Microsoft


Windows. Si se modifica en tiempo de ejecución, los cambios no se guardarán con la
aplicación.

Sintaxis App.Title = “Esto es lo que va a figurar en la barra de Titulo”

Valor será una expresión de cadena que especifica el título de la aplicación. La longitud máxima
de valor es 40 caracteres.

Esta propiedad está disponible en tiempo de diseño en el cuadro de diálogo del comando Crear
EXE del menú Archivo.

Todos estos datos figuran en el archivo de proyecto (.VBP). Puede verse editándolo con el
Block de Notas de Windows, e incluso pueden modificarse estas propiedades directamente
sobre ese archivo.

LSB Visual Basic - Guía del Estudiante Capítulo 8 Página 20


Visual Basic - Guía del Estudiante Cap. 9
INTERFACE DE DOCUMENTOS MULTIPLES. (Multiple Document Interface MDI )
EL CONTROL RICH TEXT BOX

INTERFACE DE DOCUMENTOS MULTIPLES.

Lo que se va a explicar en este capítulo le será bastante familiar aunque nunca haya reparado
en ello. Posiblemente haya utilizado un procesador de texto en el que está escribiendo una
carta, y antes de terminar de escribir esa carta, comienza a escribir otro documento, y
posiblemente otro, y tenga los tres documentos en la pantalla al mismo tiempo, bien en
ventanas escalonadas, (cascada), bien en ventanas en forma de mosaico, o simplemente
tapando unas a otras completamente. Los tres documentos están en su procesador de textos, y
puede actuar sobre uno u otro simplemente eligiendo el deseado mediante el mecanismo que
le proporciona su procesador de textos. Este sistema no es ni mas ni menos que una interface
de documentos múltiples. En programación, a este tipo de aplicaciones las denominamos MDI

Para crear una aplicación MDI debe hacerse mediante un Formulario Padre al que se le
añaden tantos Formularios Hijo como documentos tengamos. Al formulario padre le
denominamos Formulario MDI, y a los formularios hijo en Visual Basic se les denomina
formularios MDIChild. En esta Guía del Estudiante se usarán indistintamente una u otra
denominación.

La única diferencia entre un formulario normal y un formulario Hijo es que éste tiene la
propiedad MDIChild a True.

Para realizar una aplicación MDI, lo primero que hay que hacer es introducir en ella un
formulario MDI. Para introducirlo, basta con hacer click en Insertar | Formulario MDI de la
barra de menú. Solamente se puede tener un formulario MDI en una aplicación. Puede
observar que una vez que ha introducido uno, la palabra Formulario MDI del submenú Insertar
queda deshabilitada.

Una vez que tiene un formulario MDI puede introducir tantos formularios hijo como desee. Para
que un formulario sea formulario hijo basta con poner a True su propiedad MDIChild.

En una aplicación MDI pueden coexistir formularios hijo y formularios normales.

Propiedades de los formularios MDI

Aparte de las propiedades de un formulario normal, un formulario MDI tiene las siguiente
propiedades :

AutoShowChildren. Muestra los formularios hijo nada mas cargarlos.

Esta propiedad puede verse si se carga un formulario hijo mediante la sentencia :

Load NombreFormularioHijo

Si la propiedad AutoShowChildren está a True, el formulario cargado se verá inmediatamente.


Si está a False, será necesario ejecutar la sentencia NombreFormularioHijo.Show para
presentarlo.

ActiveForm Mediante esta propiedad podemos conocer el formulario activo dentro de una
aplicación de documentos múltiples. (El formulario activo es aquel que tiene el foco)

MiVariable = ActiveForm.caption

MiVariable contendrá el Caption (Barra de Titulo) del formulario activo.

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 1


ActiveForm.Backcolor = RGB (255,0,0)

pondrá el fondo del formulario activo de color rojo.

ScrollBars Hace que el Formulario MDI (padre) muestre barras de Scroll para presentar
en toda su extensión a un formulario hijo, cuando las dimensiones de áste superan las de aquel.

Aparte de estas propiedades que diferencian un Formulario MDI de un Formulario normal, los
Formularios MDI presentan otras particularidades.

Inserción de Controles Solamente podrán introducirse en un formulario MDI aquellos


controles que tengan la propiedad Align. (Picture, Data, DBGrid) y solo permiten que se
presenten con alineación a uno de los lados del Formulario (Top, Bottom, Left o Right)

El control Picture puede trabajar como contenedor de otros controles. Por lo tanto, para poder
introducir cualquier control (TextBox, Label, CommandButton ...) será necesario introducir un
control Picture, y sobre el, poner los controles que se necesiten.

Línea de Menú. Cuando existe la línea de Menú en un Formulario MDI y en el Formulario Hijo
que introduzcamos en él, la línea de menú del Formulario MDI se sustituye por la línea de menú
del Formulario Hijo introducido.

Barra de Título. La Barra de Título del Formulario MDI se conserva siempre. Pero si el
Formulario Hijo insertado dentro de él está maximizado (ocupa toda la extensión del Formulario
MDI), a la barra de título se le añadirá la barra de Título del Formulario Hijo entre paréntesis.

Para hacer que un Formulario sea un formulario hijo basta con ponerle su propiedad MDIChild
a True.

Puede preparar los formularios hijo uno a uno e introducirlos dentro del formulario MDI según
las necesidades de la aplicación. Este sería el caso de una aplicación con varias pantallas,
todas ellas colocadas sobre una pantalla fija (Formulario MDI) del que se aprovecha quizás
alguna parte como parte común de toda la aplicación (Menú, Título, Barra de herramientas
montada sobre un Picture, etc.)

Puede también darse el caso de introducir un número indeterminado de ventanas iguales para
realizar varias veces la misma función, pero sobre ventanas diferentes. (Caso del procesador
de texto que tiene varias ventanas de texto, cada una con un documento. Lo que
desconocemos a priori es el número de documentos que vamos a editar)

Para el primer caso, será necesario crear cada una de las ventanas, e introducirlas y quitarlas
según pida la aplicación.

En segundo caso, bastará con crear un formulario hijo con todas las partes necesarias para su
correcto funcionamiento, y luego, realizar tantas “fotocopias” de ese formulario como ventanas
necesitemos. Lo que introducimos en la aplicación son precisamente esas “fotocopias”, pero no
el original, que lo seguimos manteniendo intacto para volver a copiarlo si fuese necesario.

A esas “fotocopias” de un formulario las llamamos Instancias. Al original le llamaremos Clase.

En realidad una Clase es la definición de un objeto Visual Basic. Un objeto Visual Basic puede
ser un Formulario, un control, un objeto de acceso a datos.

La Instancia es la réplica de una clase. Puede ser la réplica de un Formulario, de un control o


de otro objeto. La Instancia lleva las mismas Propiedades que la clase. Se dice que hereda
las propiedades. (Excepto la propiedad Visible, que siempre, por defecto, aparece a False).
Cuando se varía una propiedad de una Instancia, no se altera el valor de esa propiedad en la
Clase ni en ninguna de las restantes Instancias.

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 2


Después de toda esta teoría, ¿podemos saber como se crea una Clase de un formulario ? O
dicho de manera mas coloquial, ¿Cómo se crea un Formulario para poder hacer varias
“fotocopias” de él ?

La respuesta es obligatoriamente mas sencilla que la teoría. Con el formulario vacío que
tengamos en el proyecto (Insertemos un Formulario si fuese necesario) pongámosle todos los
controles que deseemos. Le podemos poner un Menú y cambiar a nuestro antojo todas sus
propiedades. Entre ellas, la propiedad MDIChild. Si vamos a introducir las Instancias de ese
Formulario en un Formulario MDI esa propiedad debe estar a True, y por lo tanto sus Instancias
saldrán igualmente con esa propiedad a True. Pongámosle un nombre y ya está creada la
clase. Supongamos que ese nombre es FormularioHijo

Para crear ahora Instancias de ese Formulario podemos hacerlo de dos formas :

Declarar una variable tipo Objeto. No se asuste. Para declarar que una variable es un
Formulario basta con declararla de la siguiente forma :

Dim MiVentana As Form

Esta variable debe declararla en sitio adecuado para su aplicación, y el ámbito de esa variable
objeto será el mismo que para cualquier tipo de variable. (Vea Ambito de las Variables) La
sentencia a utilizar para la declaración será Dim, Private, Public o Global tal como se explicó
para las variables.

Una vez declarada como variable puede hacerla igual a un objeto existente que servirá de
modelo (Una Clase) que estará definida por un nombre: (P.e. FormularioHijo)

Set MiVentana = New FormularioHjo

Podemos hacer las dos operaciones a un tiempo : declarar y crear la copia :

Dim MiVentana As New FormularioHijo

Una vez creado la instancia del formulario debemos cargarlo en el Formulario Padre. Para
cargarlo debemos emplear la sentencia Load MiVentana, con lo que quedará cargado en la
memoria, pero, dependiendo de como está la propiedad AutoShowChildren del Formulario
Padre se mostrará o no se mostrará. Para que se muestre, independientemente de como esté
esa propiedad, basta con ejecutar MiVentana.Show. En realidad mediante el método Show un
formulario no solamente se muestra, sino que también se carga en la memoria si no estuviese
previamente cargado. Por lo tanto podíamos habernos ahorrado la instrucción anterior para
cargarlo Load MiVentana

Es muy práctico poner un Caption distinto a cada formulario que se introduzca, caso de
introducirse varios formularios hijo iguales. El Caption es una propiedad y por lo tanto todas las
instancias heredan el Caption de la Clase. Sería prudente distinguir un formulario de otro
mediante su Caption, es decir mediante su barra de título.

Para ello podemos crear un contador en el mismo procedimiento en el que creamos una nueva
instancia, y poner el Caption de cada nuevo Formulario siguiendo un orden numeral.

Documento 1, Documento 2, Documento 3, etc.

Ese procedimiento quedará de la siguiente forma :

Static contador As Integer


Dim MiVentana As New FormularioHijo
MiVentana.Caption = “Documento “ & Str (contador)
MiVentana.Show

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 3


Referencias a los Formularios. ActiveForm y Me
Si queremos nombrar un Formulario Hijo dentro de una aplicación MDI el primer problema con
el que nos encontramos es que todos los formularios hijo (Instancias de la misma Clase) tienen
el mismo nombre. Por lo tanto no podemos nombrarlas con ese nombre, ya que la aplicación no
sabría a cual de ellas nos referimos.

Si el código donde vamos a nombrar ese formulario está fuera de él (P.e. en el Formulario
Padre) deberemos referirnos al formulario hijo mediante ActiveForm. ActiveForm nos va a
indicar cual es el formulario que está actualmente activo. Un formulario está activo cuando
estamos trabajando sobre él. En ese momento tiene el foco. Permanece activo desde que
hacemos click con el ratón sobre cualquiera de sus partes, hasta que activamos otro formulario.
Es sencillo reconocer cual es el formulario activo pues tiene su barra de título con el color vivo.

Cada vez que hacemos una operación sobre una parte de un formulario éste se pondrá activo.
Por ejemplo, si el formulario es un documento de texto, y contiene el texto en un RichTextBox
de nombre RTB1, si queremos hacer una operación con el texto desde un botón colocado en el
formulario padre (poner en negrita el texto seleccionado), haríamos lo siguiente :

ActiveForm.RTB1.SelBold = True

ya que siempre estaremos seguro de que el Formulario Activo es aquel en el que acabamos de
seleccionar el texto.

Si el botón donde hemos puesto el botón no es el formulario padre, sino el hijo, tenemos un
problema similar. Su nombre será (con los ejemplos anteriores) MiVentana, y pueden existir
varios formularios con ese nombre, tantos como documentos hayamos introducido. No
podemos por tanto nombrarlo con su nombre, pues hay (o puede haber) varios. Tampoco lo
podemos nombrar con ActiveForm, ya que esta propiedad corresponde al Formulario Padre. La
solución es nombrarle mediante Me. Me siempre se refiere al formulario que contiene al
procedimiento donde está esa palabra. Por lo tanto, si tenemos un botón en el formulario hijo
con la instrucción :

Me.RTB1.SelBold = True

Me se refiere concretamente a ese formulario.

Colocación de los Formularios Hijo - Método ARRANGE


Mediante el método Arrange podemos distribuir los formularios hijo dentro del formulario padre.
Pueden colocarse en cascada, mosaico horizontal, mosaico vertical o como iconos.

Sintaxis NFMDI.Arrange distribución

donde

NFMDI = Nombre del Formulario MDI

distribución puede tomar los siguientes valores o constantes :

Constante Valor Descripción

vbCascade 0 Dispone todos los formularios MDI secundarios no minimizados


en cascada.
vbTileHorizontal 1 Dispone todos los formularios MDI secundarios no minimizados
en mosaico horizontal.
vbTileVertical 2 Dispone todos los formularios MDI secundarios no minimizados
en mosaico vertical.
VbArrangeIcons 3 Dispone los iconos de los formularios MDI minimizados.

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 4


Las ventanas o los iconos se pueden distribuir incluso si el objeto MDIForm está minimizado.
Los resultados son visibles cuando el objeto MDIForm se maximiza.

Posición de los Formularios en el Eje Z - Método ZOrder


Cuando tenemos varios formularios hijo, unos ocultan a los otros. Mucho mas si los formularios
están maximizados. Podemos colocar un formulario hijo en la parte frontal del montón de
formularios (para que se vea completamente) o llevarle a la posición mas atrás mediante el
Método ZOrder.

Sintaxis NFH.ZOrder posición

Donde NFH = Nombre del Formulario Hijo

posición puede se 0 ó 1. Si es 0 (o si se omite) el formulario se coloca en primer plano. Si es


1 el formulario se coloca en el fondo del eje Z.

ZOrder es un método que no solamente se puede emplear con formulario hijo, sino con
cualquier instancia. Puede emplearlo también con cualquier control. Pero lea detenidamente la
Ayuda de este método, ya que no todos los controles la admiten.

Mostrar los Formularios existentes mediante el Menú -- Propiedad


WindowList
Al explicar el Editor de menús casi se pasó por alto una propiedad del menú : WindowList.
Cuando se activa esta propiedad (Puede activarse para una sola palabra del menú. Si se
pretende activar para mas de una dará un error), esa palabra que tiene activada la propiedad
WindowList mostrará al hacer click sobre ella, en un menú desplegable, el Caption (Barra de
Título) de todos los formularios hijo cargados en ese instante en la aplicación. Pueden estar
incluso minimizados.

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 5


LSB Visual Basic - Guía del estudiante Capítulo 9 Página 6
EL CONTROL RICH TEXT BOX

El control RichTextBox es una caja de texto con mas prestaciones que el TextBox. No está
normalmente en la caja de herramientas, por lo que habrá que ir a Proyecto | Componentes y
elegir Microsoft RichTextBox Control. El icono que presenta en la caja de herramientas es el
siguiente :

Frente a la rigidez del TextBox, este control nos permite escribir un texto utilizando distintos
tipos de fuentes en el mismo texto, e introducir mas de 65.536 caracteres, límite máximo del
TextBox. Aparte de estas, tiene otras características respecto a la forma de guardar y leer el
texto en un fichero, que le convierten en una herramienta muy útil para el diseño de
aplicaciones en las que haya que introducir documentos de texto.

El RichTextBox puede utilizar indistintamente formato de texto Ascii (que le llamaremos Texto
Plano) o formato RTF (RichTextFormat, que llamaremos Texto enriquecido) El formato de
Texto enriquecido es un formato de intercambio entre procesadores de texto. Vea al final del
capítulo una explicación más detallada de este formato de texto. De momento basta con decir
que permite poner tipos distintos de letras, de tamaños, de colores, introducir gráficos, y toda
una serie de ventajas que le van a permitir realizar procesadores de texto casi tan perfectos
como los editores comerciales mas conocidos. Esto nos permite por ejemplo, guardar
estrictamente las letras que componen el texto (Propiedad Text de RichTextBox) o guardar el
texto, con sus letras y todos los adornos que queramos ponerles (Tipos distintos de fuente,
negrita, cursiva, …). Esto lo logramos con la propiedad TextRTF del RichTextBox. Cuando
hablamos de guardar, nos estamos refiriendo lógicamente a guardarlo en un fichero en el disco,
y también a guardarlo en el portapapeles. Si tenemos un RichTextBox de nombre RTB (así le
llamaremos en todos los ejemplos) con un texto tal como

Te creías muy listo Flanahan, pero tus vacas no pasarán por mis tierras

La propiedad Text contendrá los siguiente

RTB.Text = Te creías muy listo Flanahan, pero tus vacas no pasarán por mis tierras

La propiedad TextRTF contiene toda la información, pero eso sí, en formato RTF

RTB.TextRTF={\rtf1\ansi\deff0\deftab720{\fonttbl{\f0\fswissMS Sans Serif;}{\f1\froman\fcharset2


Symbol;}{\f2\fswiss\fprq2Arial;}}{\colortbl\red0\green0\blue0;}\deflang1034\pard\li708\plain\f2\fs2
0 Te cre\'edas muy listo \plain\f2\fs20\b\i Flanahan\plain\f2\fs20 , pero tus \plain\f2\fs24
vacas\plain\f2\fs20 no pasar\'e1n por \plain\f2\fs20\ul mis tierras\plain\f2\fs20
\par \pard\plain\f0\fs17
\par }

(Puede que el texto anterior tenga alguna diferencia sobre el real, debido a que hubo que
introducirle algún retorno de carro para poder presentarlo)

Veamos las propiedades de este control

Propiedades del RichTextBox

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 7


El RichTextBox tiene todas las propiedades del TextBox, y además otras que son las que le
dan las características excepcionales a este control. Las tres siguientes propiedades son
idénticas para ambos controles :

SelLenght Devuelve o establece el número de caracteres seleccionados. Los caracteres


seleccionados son aquellos que se ponen en vídeo inverso cuando arrastramos
con el ratón.

SelStart Devuelve o establece el número del carácter de comienzo del texto


seleccionado.

SelText Devuelve o establece la cadena de caracteres seleccionados. Si no hay ningún


carácter seleccionado devuelve la cadena “” (cadena vacía)

En el ejemplo, el texto seleccionado es ejemplo nos permitirá, texto que hemos seleccionado
con el ratón. Las propiedades anteriores tomarán estos valores para ese texto seleccionado :

SelLenght = 21 (Recuerde que el espacio también es un carácter)

SelStart = 5 (La e de ejemplo es la sexta letra, pero empieza a contar por la 0)

SelText = ejemplo nos permitirá

Recuerde que estas propiedades son tanto de lectura como de escritura. Es decir, puede
seleccionar un texto con el ratón y analizar ese texto seleccionado, o seleccionar el texto
dándole valores a estas propiedades.

Las diferencias entre uno y otro control comienzan ahora. En un RichTextBox, con un texto
seleccionado, podemos cambiar el tipo de letra, su tamaño, su color, etc.

Tipos y tamaño de las fuentes.


El RichTextBox tiene la propiedad Font, propiedad que podemos cambiar e tiempo de diseño
o en tiempo de ejecución, y que se refiere a la globalidad del RTB. Debemos señalar que en el
RTB, la propiedad Font es en sí un objeto más. Objeto que tiene sus propiedades (Name, Size,
Bold, Italic, etc.) Esto ocurre con los controles modernos, dada la tendencia de VB de ser cada
día más un lenguaje orientado a objetos. No ocurre lo mismo con otros controles ya conocidos
(CommonDialog, por ejemplo) que deben mantenerse con la nomenclatura anterior por razones

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 8


de compatibilidad con versiones anteriores de VB. Veamos esto en el siguiente ejemplo, en el
que se modifica la propiedad Font de RTB con el CommonDialog CD1

RTB.Font.Name = CD1.FontName
RTB.Font.Size = CD1.FontSize
RTB.Font.Bold = False
RTB.Font.Italic = False

(Observe que en el RTB ponemos Font.Name y en el CD1 ponemos FontName)

Con la propiedad Font podemos escribir en el RTB usando la misma letra para todo el texto. Sin
embargo verá que esta propiedad prácticamente no se va a usar, ya que el RTB tiene la gran
ventaja que puede usar varios tipos de letra y tamaños dentro de un mismo texto. Puede usar
también varios colores. Para poder cambiar de letra no usaremos Font.Name, sino
SelFontName, (Fíjese que esta propiedad no lleva ningún punto intermedio) que cambia el tipo
de letra en el texto que hayamos seleccionado, y si no hemos seleccionado ningún texto, y el
cursor de escritura se encuentra al final del texto escrito, lo que hará será cambiar el tipo de
letra a partir de ese punto.

Propiedades SelBold, SelItalic, SelStrikethru, SelUnderline


Estas propiedades son del tipo Booleano (True/False) y nos permitirán poner el texto
seleccionado en Negrita, Cursiva, Tachada y Subrayada respectivamente.

Por ejemplo, RTB.SetBold = True pondrá el negrita el texto seleccionado.


RTB.SelItalic = True pondrá en cursiva el texto seleccionado.
RTB.SelStrikethru = True pondrá en tachado el texto seleccionado.
RTB.SelUnderline = True pondrá en subrayado el texto seleccionado.
( RTB = Nombre del control RichTextBox )

Si el texto seleccionado está en la parte final del texto, o si el cursor de escritura está al final del
escrito y no se ha seleccionado ningún texto, la propiedad elegida permanecerá vigente para la
escritura que se realice a partir de ese punto.

SelFontName Esta propiedad devuelve o establece el nombre de la fuente en el texto


seleccionado. P.e. RTB1.SelFontName = “Arial”

SelFontSize Devuelve o establece el tamaño de la fuente en el texto seleccionado.


P.e. RTB1.SelFontSize = 10

SelColor Devuelve o establece el color del texto seleccionado. Para definir el


color puede usarse cualquiera de los métodos explicados en un capítulo
anterior. Los ejemplos siguientes cambiarán el texto seleccionado a
color rojo
RTB.SelColor = RGB (255,0,0)
RTB.SelColor = 255
RTB.SelColor = &HFF

Al igual que las otras propiedades, si el texto seleccionado está al final del texto, o si el cursor
de escritura está al final del escrito, la propiedad elegida permanecerá vigente para la escritura
que se realice a partir de ese punto.

Propiedades Text y TextRTF


Las vimos al principio. La propiedad Text contiene TODO el texto del RichTextBox en formato
de texto plano. La propiedad TextRTF contiene TODO el texto del RichTextBox en formato de
texto enriquecido.

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 9


Estas propiedades son de lectura y escritura, de forma que pueden tener estas dos sintaxis:

Escritura: RTB.Text = “Siempre nos quedará París”

Esta instrucción sustituye todo el contenido del RTB por el texto Siempre nos quedará París

Lectura: MiVariable = RTB.Text

MiVariable contendrá todo el contenido de RTB en formato de texto plano

La propiedad TextRTF es similar, pero con texto en formato enriquecido. Si la usamos como
lectura:

MiVariable = RTB.TextRTF

MiVariable contendrá el texto, más los caracteres que definen el tipo de letra, tamaño, etc,
como vimos al principio.

Si la usamos como escritura:

RTB.TextRTF = TuVariable

Si TuVariable contiene un texto en formato RTF, el contenido de RTB será justamente ese
texto, con todas sus florituras de tipo de letra, tamaño, negrita, etc. Si TuVariable contuviese un
texto en formato de texto plano, lo escribirá tal cual, con el tipo y tamaño de letra que tenga en
su propiedad Font.

Propiedades SelText y SelRTF

Es conveniente no confundirlas con las anteriores. Aquellas contenían TODO el texto del
RichTextBox. Estas, solo el texto que está seleccionado.

SelText
Devuelve o establece el texto seleccionado en formato de texto plano. No está disponible en
tiempo de diseño.
Al ser una propiedad de lectura y escritura, nos permite:
Escritura: añadir texto (que se colocará en la posición en la que esté el curso) o cambiar el
texto seleccionado por otro. La instrucción

RTB.SelText = “Siempre nos quedará París”

Introducirá el texto anterior en la posición donde estuviera el cursor, o si teníamos texto


seleccionado, cambiará el texto anterior por este.

Lectura: Teniendo un trozo de texto seleccionado,

MiVariable = RTB.SelText

MiVariable tomará el valor del texto que estuviese seleccionado en formato de texto plano.
SelRTF
Devuelve o establece el texto seleccionado en formato .RTF. Al igual que SelText es de lectura
y escritura. No está disponible en tiempo de diseño.

Sintaxis (Escritura) RTB.SelRTF = MiVariable

Si el contenido de MiVariable está en formato RTF, sustituirá el texto que tuviésemos


seleccionado por el contenido de MiVariable, y lo escribirá con todos los detalles de tipo de
letra, tamaño, etc., que contuviese el formato RTF. Si no hubiésemos seleccionado previamente
ningún texto, escribirá ese texto en el lugar donde estuviese colocado el cursor.

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 10


Si el contenido de MiVariable fuese un texto plano, escribirá ese texto, usando las mismas
propiedades para la letra que tuviese el texto seleccionado previamente, o las del punto donde
se encontrase el cursor.

Sintaxis de Lectura) MiVariable = RTB.SelRTF

MiVariable contendrá el texto que estuviese seleccionado, en formato RTF.

Esta propiedad es equivalente a la propiedad SelText y funciona de forma idéntica, pero en


este caso el texto reemplazado o devuelto mediante la propiedad SelRTF está en formato RTF.
Esta propiedad devuelve una cadena de longitud cero ("") si no hay texto seleccionado en el
control.

Alineación y márgenes del texto


El RichTextBox permite crear un margen desde el borde izquierdo hasta el comienzo de la
escritura, (Propiedad SelIndent), y otro margen desde el borde derecho hasta el final de la
línea (Propiedad SelRightIndent), o limitar el ancho de la línea (Propiedad RightMargin).
También se puede poner una sangría a las líneas segunda y siguientes respecto a la primera
línea del párrafo (Propiedad SelHangingIndent). Este tipo de sangría es la sangría francesa,
sangría que no se suele usar (a lo mejor se usa en Francia). En realidad lo que se usa mucho
es separar la primera línea del párrafo un poco más que el resto de las líneas. Esto puede
conseguirse dando un valor negativo a la propiedad SelHangingIndent. Lo verá mas adelante.

La medida de estos márgenes y sangrías se realiza en las unidades de medida del formulario
que contiene al RichTextBox. Veamos un ejemplo comentado de estas propiedades.

Margen izquierdo. Con la instrucción


RTB.SelIndent = Val(TBSangria)

Separa el párrafo correspondiente a la línea donde está en ese momento al cursor. (Que a
partir de ahora la llamaremos Línea en curso) El espacio que separa ese párrafo del borde
izquierdo del RichTextBox es un valor igual al que hayamos introducido en el TextBox
TBSangría, medido en las unidades de medida del formulario que contiene a RTB. Recuerde,
sólo hace la sangría con el párrafo que contiene la línea en curso.

Si queremos separar varios párrafos, debemos seleccionar esos párrafos antes de ejecutar la
instrucción anterior. Para poner una separación desde el borde izquierdo de todas los párrafos
del texto deberemos primero, seleccionar todo el texto, y luego ejecutar la instrucción anterior.
Esto podemos lograrlo combinando estas tres instrucciones:

RTB.SelStart = 1
RTB.SelLength = Len(RTB.Text)
RTB.SelIndent = Val(TBSangria)

Margen derecho. Usaremos la propiedad SelRightIndent. Con la instrucción:


RTB.SelRightIndent = Val(TBMargenDcho)

Separamos el final del párrafo donde está la línea en curso una distancia igual al valor de
TBMargenDcho. Esta propiedad es completamente equivalente a la anterior, esta referida al
margen derecho y aquella al margen izquierdo. Es aplicable todo lo que se dijo para SelIndent.

Longitud máxima de la línea desde el borde izquierdo . Parece un poco largo la


definición de esta propiedad. Se refiere a la propiedad RightMargin. Esta propiedad marca la
distancia desde el borde izquierdo del RichTextBox hasta el límite máximo utilizable por el texto.

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 11


Este valor es el que se toma como fin de la zona utilizable por el texto, por lo tanto, ese punto
será la referencia que utilice la propiedad SelRightIndent para determinar el punto a partir del
cual creará el margen derecho. También será la referencia derecha cuando centremos un texto
o lo alineemos a la derecha.

RTB.RightMargin = Val(TBAncho)

La instrucción anterior fija como distancia máxima que puede ocupar una línea de texto la
cantidad introducida en TBAncho. Por supuesto, expresada como siempre en las unidades de
medida del formulario. La línea puede ser mas ancha que el ancho del RichTextBox. En este
caso la línea no cabe en el RTB, pero puede visualizar la línea completa usando baraas de
scroll horizontales (Vea propiedad ScrollBars más adelante)

Sangría francesa. La sangría francesa consiste en separar la segunda línea y siguientes


cierta medida a la derecha respecto a la primera línea. Algo así

Esta es la primera línea de este texto donde se explica lo que es una sangría francesa
en realidad desconozco si en Francia usan este tipo de sangría, pero a mí
me gusta más la sangría española, siempre que esté bien fresquita.

Esto se logra mediante la propiedad SelHangingIndent y afecta únicamente al párrafo donde


se encuentra la línea en curso.

Puede hacer lo que parece mas lógico, separar la primera línea un poco respecto a las demás,
dando un valor negativo a la propiedad SelHangingIndent. Pero para que esto resulte, debe
poner un valor al menos igual a la propiedad SelIndent. En el ejemplo siguiente, hacemos una
sangría solamente a la primera línea del párrafo donde está la línea en curso:

RTB.SelIndent = Val(TBSangriaEsp)
RTB.SelHangingIndent = -Val(TBSangriaEsp)

(Observe el signo menos en la segunda línea) El valor de la sangría de la primera línea será el
contenido en TBSangriaEsp

Centrado, Alineación a la izquierda o a la derecha.


El centrado de una línea o párrafo se logra mediante la propiedad SelAlignment Puede tomar
los valores 0 (alineado a la izquierda), 1 (a la derecha) ó 2 (centrado) Siempre se refiere a la
línea en curso o al párrafo que contiene la línea en curso. Si quiere alinear varios párrafos, debe
seleccionarlos antes de ejecutar la instrucción de alineamiento.

RTB.SelAlignment = 0 ‘alinea a la izquierda


RTB.SelAlignment = 1 ‘alinea a la derecha
RTB.SelAlignment = 2 ‘centra el texto

En la alineación se tiene en cuenta la propiedad RightMargin, es decir, si alinea a la derecha, lo


hará tomando como parte mas derecha del escrito el valor de la propiedad RightMargin, no el
borde lateral derecho del RTB. Lo mismo le ocurre con el centrado.

Viñetas
El RichTextBox es, como decíamos al principio, un control que nos permite realizar editores de
textos muy potentes. Incluso podemos poner viñetas

Una viñeta es un párrafo marcado con un punto en su comienzo, y que lleva una cierta sangría
respecto al borde izquierdo del RichTextBox. Para poner una viñeta es necesario jugar con dos
propiedades:
SelBullet, propiedad Booleana que si la hacemos True convertimos el párrafo donde está la
línea en curso en una viñeta. Si está en False, ese párrafo será un párrafo normal.

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 12


BulletIndent, propiedad a la que le pondremos un valor numérico igual a la separación que
queremos poner en el texto de la viñeta.

Para que tenga efecto la propiedad BulletIndent, la propiedad SelBullet debe estar puesta a
True. No tendrá efecto alguno si SelBullet = False. Por ejemplo, para poner una viñeta
podemos poner

RTB.SelBullet = True
RTB.BulletIndent = 500

Una vez puesta una viñeta en el RichTextBox, insertará otro cada vez que pulsemos ENTER.
Para quitarlo, basta con ejecutar la sentencia

SelBullet = False

La propiedad BulletIndent es de lectura y escritura. La instrucción siguiente nos devuelve la


separación de la viñeta donde tengamos el cursor. La propiedad BulletIndent devuelve 0 si la
selección abarca múltiples párrafos con distintos ajustes de margen o si el párrafo no es una
viñeta.

También podemos leer el valor de SelBullet. Devolverá

Null. La selección abarca más de un párrafo y contiene una mezcla de estilos de viñeta y no
viñeta.
True. Los párrafos de la selección tienen estilo de viñeta.
False. La párrafos de la selección no tienen estilo de viñeta.

Tabulación del RichTextBox


Si queremos crear un editor de texto de la categoría de cualquiera de los comerciales, debemos
poder tabular. Tabular significa crear unos hitos o marcas a una determinada distancia del
borde izquierdo del papel, de forma que cada vez que pulsemos la tecla Tabulador el cursor de
escritura se coloca al inicio del siguiente de esas marcas.

El primer problema es que si estamos escribiendo sobre el RichTextBox y pulsamos Tabulador,


el foco se nos escapa hacia el siguiente control, según el orden de la propiedad TabIndex.
Existe una solución, que es pulsar la combinación de las teclas Ctrl + Tab. Sin embargo esa
posibilidad no es recomendable, dado que un usuario normal no está acostumbrado a realizar
esa combinación para forzar una tabulación.

La solución está en poner la propiedad TabStop de todos los controles a False, cada vez que el
RichTextBox toma el foco. Es decir, en su procedimiento GotFocus. De esta forma, al dar el
tabulador ningún control se “querrá” quedar con el foco, y por lo tanto el foco seguirá en el
RichTextBox. En estas condiciones el resultado es que el cursor de escritura pasará a la
siguiente tabulación.

Vamos a ver como se puede poner la propiedad TabStop a False en todos los controles del
formulario. Para ello vamos a explicar un nuevo objeto Visual Basic, el objeto Controls. Este
objeto es una colección, y está formada por todos los controles del formulario. Como cualquier
colección tendrá una propiedad, la propiedad Count que toma el valor igual al número de
controles existentes en el formulario. Como cualquier cosa de VB formada por varios
elementos, cada uno de ellos se distingue por su índice. Y este índice comienza por el 0 y
termina por el n-1, siendo n = número de elementos de esa colección.

Para poner la propiedad TabStop a False en todos los controles de la colección Controls del
formulario, basta con poner este código en el procedimiento GotFocus del RTB

Private Sub RTB_GotFocus()


Dim I As Integer

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 13


‘Con la siguiente línea se evita el error producido en aquellos controles que no tienen la
‘propiedad TabStop
On Error Resume Next
For I = 0 To Me.Controls.Count - 1
Controls(I).TabStop = False
Next I
End Sub

Podemos hacerlo de otra forma. Declaremos una variable tipo Objeto Control

Private Sub RTB_GotFocus()


Dim Pepe As Control
On Error Resume Next 'De esta forma se evita el error producido en aquellos controles que no
tienen la propiedad TabStop
For Each Pepe In Controls
Pepe.TabStop = False
Next
End Sub

Nota. Si va a la información del RichTextBox podrá ver un ejemplo de esto, con el siguiente
código:
For Each Control In Controls
Control.TabStop = False
Next Control
Milagros del Visual Basic: Así no funciona

Ya funciona perfectamente el tabulador en el RichTextBox. Pero cuando salgamos del


RichTextBox, debemos volver a poner la propiedad TabStop de todos los controles a True. Para
ello, en el procedimiento LostFocus del RTB pondremos el código anterior, poniendo True en
vez de False en la propiedad TabStop.

Programar las medidas de las tabulaciones.

Propiedad SelTabCount

Establece el número de tabulaciones en un RTB. P.e., si queremos crear 5 tabulaciones

RTB.SelTabCount = 5

Propiedad SelTabs
Establece el valor numérico (separación desde el borde izquierdo) de las tabulaciones. Dado
que pueden existir varias tabulaciones, deberemos distinguirlas entre ellas mediante un índice.
El índice para la primera tabulación es el 0

RTB.SelTabs(0) = 1000
RTB.SelTabs(1) = 2000
RTB.SelTabs(2) = 3000
RTB.SelTabs(3) = 4000 Con estas líneas determinaríamos la posición de tabulación de
RTB.SelTabs(4) = 5000 los 5 tabuladores.

Antes de darle valor a la propiedad SelTabs deberemos haber creado los tabuladores mediante
SelTabCount. Si pretende darle valor a un tabulador mayor que el número de tabuladores real
(por ejemplo, si pone en el caso anterior RTB.SelTabs(5) = 5000) le dará un error.

Recuerde que los valores de los tabuladores debe darlos en las unidades de medida del
formulario.

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 14


OTRAS PROPIEDADES

Propiedad SelCharOffset
Nos permite crear subíndices y superíndices. La sintaxis es:

RTB.SelCharOffset = Número

Donde Número indica la separación del superíndice o subíndice en Twips. Si Número es


positivo, obtendremos un superíndice, si es negativo, un subíndice.

Esta forma de escribir subíndices y superíndices se debe aplicar cada vez que queramos
escribir uno de ellos, e inmediatamente, poner esa propiedad a 0, ya que si no lo hacemos así,
escribiría como subíndice o superíndice el resto del texto. P.e. para poner un superíndice:

TamIni = RTB.SelFontSize
RTB.SelFontSize = TamIni - 4
RTB.SelCharOffset = 40
RTB.SetFocus

Para restaurar los valores anteriores

RTB.SelFontSize = TamIni
RTB.SelCharOffset = 0
RTB.SetFocus

Propiedad SelProtected
Es una propiedad Booleana, que nos permite proteger contra cualquier cambio a una parte del
texto (o todo el texto) que contiene el RTB. Para proteger una parte del texto basta con
seleccionarla y a continuación ejecutar la instrucción

RTB.SelProtected = True

Una vez protegida una parte del texto, esa parte no se puede variar. Puede desprotegerse,
volviendo a seleccionarla y ejecutando la instrucción:

RTB.SelProtected = False
Propiedad ScrollBars
Pone barras de desplazamiento al RichTextBox.
Esta propiedad puede establecerse a 0 (None, ninguna), a 1 (Horizontal), 2 (Vertical) o 3 (Both,
ambas). Cuando las barras de desplazamiento no son necesarias, bien porque hay pocas
líneas, bien porque hay pocos caracteres por línea, las barras de desplazamiento están
desactivadas.

Es frecuente pensar que las barras de desplazamiento horizontal no funcionan. Y eso ocurre
porque siempre se ven desactivadas. En realidad lo que pasa es que solamente se activan
cuando la línea de texto es mas ancha que el ancho del RichTextBox. Puede ocurrir eso cuando
la propiedad RightMargin tiene un valor superior a la anchura del control, circunstancia que nos
permite escribir saliéndonos del control, y es en solamente en ese caso en el que se activa la
barra de scroll horizontal.

Las barras de desplazamiento pueden desactivarse mediante la propiedad DisableNoScroll.

Propiedad DisableNoScroll
Devuelve o establece un valor que determina si están desactivadas las barras de
desplazamiento en el control RichTextBox.

Sintaxis NombredelRichTextBox.DisableNoScroll = True / False

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 15


Si es False, las barras de desplazamiento aparecen normalmente. Si es True, las barras de
desplazamiento aparecen atenuadas.

Propiedad Appearance
Plano o tridimensional, como en el resto de los controles.

Propiedad AutoVerbMenu
Propiedad Booleana que indica si se presenta un menú emergente cuando el usuario hace click
con el botón derecho del ratón. El menú emergente muestra los comandos de Deshacer (Ctrl-Z)
cortar (Ctrl-X), copiar (Ctrl-C), pegar (Ctrl-V) y Eliminar (Supr) Pero no es necesario escribir
código en ninguna parte para que se realicen estas operaciones (Por una vez, VB nos regala
unas operaciones. No es VB, es Windows directamente)

Sintaxis NombredelRichTextBox.AutoVerbMenu = True / False

Si esta propiedad está a True muestra el menú. False no lo muestra.

Propiedad BorderStyle
Sin borde o con borde (None o Fixed Single)

Propiedad Enabled
Propiedad Booleana. Activa o desactiva el RichTextBox

FileName
Esta propiedad devuelve o establece el nombre del fichero .RTF cargado en el RichTextBox. Si
ejecutamos la línea de código :

RTB1.Filename =”C :\CursoVB\Mitexto.rtf”

lo que ocurrirá es que nuestra aplicación cargará el fichero C :\CursoVB\Mitexto.rtf en el


RichTextBox RTB1. Es decir, hace lo mismo que el Método LoadFile (Vea mas abajo).
Sólo puede especificar los nombres de archivos de texto o archivos .RTF válidos para esta
propiedad.
Le recomendamos que para cargar un texto en un RTB use siempre el método LoadFile en
vez de la propiedad Filename.

Si lo que hacemos con esta propiedad es consultar el fichero cargado en el RTB :

Variable = RTB1.Filename

obtendremos en Variable el nombre (y Path) del fichero que tenemos cargado en el RTB

HideSelection
Devuelve o establece un valor que determina si el texto seleccionado aparece resaltado cuando
el RichTextBox pierde el enfoque. Esto es justamente lo que ocurre cuando seleccionamos un
trozo de texto (Por ejemplo para pasar ese texto a negrita) y hacemos click sobre otro control
(Por ejemplo, sobre un botón de comando para cambiar a Negrita) Si tenemos esta propiedad a
False el texto seleccionado sigue seleccionado. Si está a True, el texto se deselecciona.

NOTA Le recomiendo que cuando tenga un control para cambiar el tipo de letra, hágalo sobre
un control que no acepte el foco (Label, p.e.)

Sintaxis NombreRTB.HideSelection = True / False para establecer la propiedad

Variable = NombreRTB.HideSelection para leerla

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 16


Propiedad Locked
Igual que le ocurre al TextBox, si ponemos esta propiedad a True impedimos que se pueda
cambiar el texto existente en el RichTextBox mediante el teclado.

MaxLength
Esta propiedad marca el número máximo de caracteres que puede contener. Si se pone a 0
(Predeterminado) admite cualquier número de caracteres.

MousePointer
Igual que para el resto de los controles.

Multiline
Igual que para el TextBox. Si está a True (predeterminado) el RichTextBox puede contener
varias líneas. Si está a False, una solo.

OLEDragMode
OLEDropMode
Estas dos propiedades son similares a la DragMode de otros controles. Se verán con mas
detalle al estudiar el Drag & Drop.

METODOS DEL CONTROL RichTextBox

El control RichTextBox cuenta con unos métodos especiales para abrir un fichero y guardar el
texto que contiene un poco especiales. Estos métodos (SaveFile y LoadFile) se pueden usar
solamente cuando queremos guardar o leer el texto en formato .RTF. Con ellos no es necesario
abrir el fichero (con Open Nombrefichero .....) ni cerrarlo, pero siempre para guardar o leer texto
en formato RTF. Podemos leer o guardar el texto de un RichTextBox como texto plano (Como
los ficheros ASCII .TXT). Para ello debemos utilizar los métodos Open Nombrefichero For Input
/ Output vistos en el capítulo de ficheros.

METODO SaveFile
Guarda el contenido de un control RichTextBox en un archivo.

Sintaxis NombredelRTB.SaveFile(nombre_ruta, tipo_archivo)

Donde nombre_ruta (Parámetro requerido) es una expresión de cadena que define la ruta de
acceso y el nombre del archivo que va a recibir el contenido del control, y tipo_archivo es un
entero o una constante que especifica el tipo de archivo cargado, como se describe a
continuación :

0 rtfRTF El control RichTextBox guarda su contenido como un archivo .RTF.


1 rtfText El control RichTextBox guarda su contenido como un archivo de texto.

El valor predeterminado es 0. Si no se pone este parámetro, toma el valor 0 por defecto.

Ejemplo
RTB1.SaveFile “C :\CursoVB\mitexto.rtf”, 0

Guarda el contenido del RichTextBox RTB1 en un fichero llamado mitexto.rtf que está en el
directorio CursoVB, con formato RTF

Aparte del método SaveFile, puede utilizar la función Print de Visual Basic y las propiedades
TextRTF y SelRTF del control RichTextBox para escribir archivos .RTF. Por ejemplo, puede
guardar el contenido de un control RichTextBox en un archivo .RTF de este modo:

Open "mitexto.rtf" For Output As 1


Print #1, RichTextBox1.TextRTF
Close #1

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 17


METODO LoadFile

Carga un archivo .RTF o un archivo de texto en un control RichTextBox.

Sintaxis NombreRTB.LoadFile nombre_ruta, tipo_archivo

Donde nombre_ruta (Parámetro requerido) es una expresión de cadena que define la ruta de
acceso y el nombre del archivo que se va a cargar en el control, y tipo_archivo es un entero o
una constante que especifica el tipo de archivo cargado, como se describe a continuación

0 rtfRTF El archivo cargado debe ser un archivo .RTF válido.


1 rtfText El control RichTextBox carga cualquier archivo de texto.

Al cargar un archivo con el método LoadFile, el contenido del archivo cargado reemplaza a
todo el contenido del control RichTextBox. Esto hace que cambien los valores de las
propiedades Text y rtfText.

También puede usar la función Input de Visual Basic y las propiedades TextRTF y SelRTF del
control RichTextBox para leer archivos .RTF. Por ejemplo, puede cargar el contenido de un
archivo .RTF en el control RichTextBox de este modo:

Open "C :\CursoVB\mitexto.rtf" For Input As 1


RichTextBox1.TextRTF = Input$(LOF(1), 1)
Close #1

METODO Find

Busca una cadena específica en el texto de un control RichTextBox.

Sintaxis Variable = NombreRTB.Find (cadena, inicio, fin, opciones)

Donde :
cadena (Necesario) Una expresión de cadena que desea buscar en el control.
inicio (Opcional) Un índice de caracteres de tipo Integer que determina dónde comienza
la búsqueda. Cada carácter del control tiene un índice entero que lo
identifica de forma única. El primer carácter de texto del control tiene
un índice 0.
fin (Opcional) Un índice de carácter de entero que determina dónde termina la
búsqueda.
Opciones (Opcional) Una o más valores o constantes utilizadas para especificar
características opcionales, como se describe a continuación.

Valor Constante Descripción

1 rtfWholeWord Determina si una coincidencia se basa en una palabra completa o en


parte de una palabra.
4 rtfMatchCase Determina si una coincidencia se basa el uso de mayúsculas y
minúsculas de la cadena especificada además del texto de la cadena.
8 rtfNoHighlight Determina si una coincidencia aparece resaltada en el control
RichTextBox.
Puede combinar múltiples opciones si utiliza el operador Or.

Si se encuentra el texto buscado, el método Find resalta el texto especificado y devuelve un


número con la posición del primer carácter resaltado. Si no se encuentra el texto especificado,
el método Find devuelve –1.

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 18


Si utiliza el método Find sin la opción rtfNoHighlight aunque la propiedad HideSelection sea
True y el control RichTextBox no tenga el enfoque, el control seguirá resaltando el texto
encontrado. Los usos posteriores del método Find sólo buscarán el texto resaltado hasta que se
mueva el punto de inserción.

El comportamiento de búsqueda del método Find varía según la combinación de valores


especificados para los argumentos inicio y fin. Esta tabla describe los comportamientos
posibles:

Inicio Fin Comportamiento de búsqueda

Especificado Especificado Busca desde la ubicación inicial especificada hasta la


ubicación final especificada.
Especificado Omitido Busca desde la ubicación inicial especificada hasta el final del
texto del control.
Omitido Especificado Busca desde el punto de inserción actual hasta la ubicación
final especificada.
Omitido Omitido Busca en la selección actual si el texto está seleccionado o en
todo el contenido del control si no hay texto seleccionado.

METODO GetLineFromChar

Devuelve el número de la línea que contiene una posición de carácter especificado en un


control RichTextBox.

Sintaxis Variable = NombreRTB.GetLineFromChar (pos_carácter)

Donde pos_carácter (Requerido) es un entero largo que especifica la posición del carácter
cuya línea desea identificar. El índice del primer carácter del control RichTextBox es 0.

Utilice el método GetLineFromChar para averiguar qué línea del texto de un control
RichTextBox contiene una determinada posición de carácter. Es posible que necesite hacerlo
porque puede variar el número de caracteres de cada línea, lo que hace muy difícil averiguar
qué línea del texto contiene un determinado carácter, identificado por su posición en el texto.

METODO SelPrint

Envía texto con formato de un control RichTextBox a un dispositivo de impresión.

Sintaxis NombreRTB.SelPrint(hdc)

Donde hdc es el contexto de dispositivo del dispositivo que va a utilizar para imprimir el
contenido del control.

Si hay texto seleccionado en el control RichTextBox, el método SelPrint sólo enviará el texto
seleccionado al dispositivo de destino. Si no hay texto seleccionado, se enviará el contenido
completo del control RichTextBox al dispositivo.
El método SelPrint no imprime texto desde el control RichTextBox. En su lugar, envía una
copia del texto con formato a un dispositivo que pueda imprimirlo. Por ejemplo, puede enviar el
texto al objeto Printer utilizando código como éste:

RichTextBox1.SelPrint(Printer.hDC)

Observe que la propiedad hDC del objeto Printer se utiliza para especificar el argumento de
contexto de dispositivo del método SelPrint.

Nota Si utiliza el objeto Printer como destino del texto desde el control RichTextBox, deberá
inicializar en primer lugar el contexto de dispositivo del objeto Printer. Esto es necesario, ya que

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 19


Visual Basic no conoce el hDC del Printer hasta que se imprime algo. La información de
Microsoft recomienda imprimir una cadena de longitud cero.
(Ejecutar la instrucción Printer.Print “”) Sin embargo esa no es buena solución ya que da un
error de impresora. Vale mas forzar la posición del papel, aunque no hiciese falta
Printer.Orientation = 1

Mediante SelPrint nos podemos ahorrar la tediosa programación del Printer, pero tiene también
inconvenientes: No controlamos el cambio de página, si tenemos papel preimpreso es muy
difícil ajustarlo, etc.

METODO Span

Selecciona texto en un control RichTextBox basándose en un conjunto de caracteres


especificado.

Sintaxis NombreRTB.Span juego_caracteres, hacia_adelante, negado

donde :

juego_caracteres (Requerido) Una expresión de cadena que especifica el juego de caracteres


que se va a buscar al ampliar la selección, basándose en el valor de negado.

hacia_adelante (Opcional) Una expresión booleana que determina en qué sentido se mueve el
punto de inserción, como se describe mas adelante.

Negado (Opcional) Una expresión booleana que determina si los caracteres de


juego_caracteres definen el conjunto de caracteres de destino o se excluyen del conjunto de
caracteres de destino, como se describe mas adelante.

Los valores para hacia_adelante son:

True (Predeterminado) Selecciona texto desde el punto de inserción actual o desde el


principio de la selección actual hacia delante, hacia el final del texto.
False Selecciona texto desde el punto de inserción actual o el principio de la selección actual
hacia atrás, hacia el principio del texto.

Los valores para negado son:

True Los caracteres incluidos en la selección son los que no aparecen en el argumento
juego_caracteres. La selección se detiene en el primer carácter encontrado que aparece en el
argumento juego_caracteres.
False (Predeterminado) Los caracteres incluidos en la selección son los que aparecen en el
argumento juego_caracteres. La selección se detiene en el primer carácter encontrado que no
aparece en el argumento juego_caracteres.

El método Span se utiliza principalmente para seleccionar fácilmente una palabra o una frase
en el control RichTextBox.
Si el método Span no encuentra los caracteres especificados basándose en los valores de los
argumentos, el punto de inserción o la selección actual permanece sin cambios.
El método Span no devuelve datos.

METODO Upto

Mueve el punto de inserción hasta el primer carácter (sin incluirlo) que sea miembro del
conjunto de caracteres especificado en un control RichTextBox.

Sintaxis NombredelRTB.Upto (juego_caracteres, hacia_adelante, negado)

Donde :

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 20


juego_caracteres (Requerido) Una expresión de cadena que especifica el conjunto de
caracteres que se va a buscar al mover el punto de inserción, basándose en el valor de negado.
hacia_adelante (Opcional) Una expresión booleana que determina en qué sentido se
mueve el punto de inserción, como se describe en Valores.

negado (Opcional) Una expresión booleana que determina si los caracteres de


juego_caracteres definen el conjunto de caracteres de destino o se excluyen del conjunto de
caracteres de destino, como se describe en Valores.

Valores

Los valores de hacia_adelante son:

True (Predeterminado) Mueve el punto de inserción hacia delante, hacia el final del texto.
False Mueve el punto de inserción hacia atrás, hacia el principio del texto.

Los valores para negado son:

True Los caracteres no especificados en el argumento juego_caracteres se utilizan para


mover el punto de inserción.
False (Predeterminado) Los caracteres especificados en el argumento juego_caracteres se
utilizan para mover el punto de inserción.

El Portapapeles y el RichTextBox
Imagínese que seleccionamos un texto en un RichTextBox y ese texto lo metemos al
portapapeles. Dado que el texto está escrito en RTF, ¿Como nos lo guarda el Portapapeles ?

La solución es que puede guardarlo en las dos versiones. En formato de texto plano (Guarda
estrictamente los caracteres ASCII del texto seleccionado) o como texto enriquecido (RTF),
guardando en este caso, además del texto limpio y puro, la información del tipo de letra,
tamaño, color, etc. típicas del formato RTF.

Para ello debemos indicarle al portapapeles en qué formato queremos guardarlo. La línea de
código :

Clipboard.SetText RTB1.SelRTF, vbCFRTF

guarda en el portapapeles el texto seleccionado en ese momento, en formato RTF. La línea

Clipboard.SetText RTB1.TextRTF, vbCFRTF

guarda en el portapapeles todo el contenido del RichTextBox (llamado RTB1 en los ejemplos)
en formato RTF

Las líneas :

Clipboard.SetText RTB1.SelRTF, vbCFText


Clipboard.SetText RTB1.TextRTF, vbCFText

guardarán, respectivamente, el texto seleccionado y todo el texto de RTB1, en formato de texto


plano

Pero esta no es la única forma de introducir texto procedente del RichTextBox en el


portapapeles. Podemos introducir el texto seleccionado con formato RTF de la forma :

ClipBoard.SetText RTB1.SelRTF

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 21


Y el texto plano con Clipboard.SetText RTB1.SelText

Para introducir TODO el texto del RTB en formato RTF

Clipboard.SetText RTB1.TextRTF

Para meter TODO el texto del RTB en texto plano

Clipboard.SetText RTB1.Text

APENDICE

Constantes del control RichTextBox

Constante Valor Descripción

Propiedad Appearance
rtfFlat 0 Uniforme. Pinta sin efectos visuales.
rtfThreeD 1 (Predeterminado). 3D. Pinta con efectos tridimensionales.

Método Find
rtfWholeWord 2 Determina si una coincidencia se basa en una palabra completa o en
parte de una palabra.
rtfMatchCase 4 Determina si una coincidencia se basa en el uso de mayúsculas y
minúsculas de la cadena especificada además del texto de la cadena.
rtfNoHighlight 8 Determina si una coincidencia aparece resaltada en el control
RichTextBox.

Métodos LoadFile y SaveFile


rtfRTF 0 (Predeterminado) RTF. El archivo cargado debe ser un archivo .RTF
válido (método LoadFile) o el contenido del control se guarda en un
archivo .RTF (método SaveFile).
rtfText 1 Texto. El control RichTextBox carga cualquier archivo de texto
(método LoadFile) o el contenido del control se guarda en un archivo de
texto (método SaveFile).
Propiedad MousePointer
rtfDefault 0 (Predeterminado) La forma está determinada por el objeto.
rtfArrow 1 Flecha.
rtfCross 2 Cruz (cursor en forma de cruz).
rtfIbeam 3 Cursor en forma de I.
rtfIcon 4 Icono (cuadrado pequeño dentro de un cuadrado).
rtfSize 5 Tamaño (flecha de cuatro puntas que señala al norte, sur, este y oeste)
rtfSizeNESW 6 Tamaño NE-SO (flecha de dos puntas que señala al nordeste y al
sudoeste).
rtfSizeNS 7 Tamaño N S (flecha de dos puntas que señala al norte y al sur).
rtfSizeNWSE 8 Tamaño NO, SE.
rtfSizeEW 9 Tamaño EO (flecha de dos puntas que señala al este y al oeste).
rtfUpArrow 10 Flecha hacia arriba.
rtfHourglass 11 Reloj de arena (espere).
rtfNoDrop 12 No colocar.
rtfArrowHourglass 13 Flecha y reloj de arena.
rtfArrowQuestion 14 Flecha y signo de interrogación.
rtfSizeAll 15 Ajustar todo.
rtfCustom 99 Icono personalizado especificado por la propiedad MouseIcon.

Propiedad Selalignment
rtfLeft 0 (Predeterminado) Izquierda. El párrafo se alinea a lo largo del margen
izquierdo.
rtfRight 1 Derecha. El párrafo se alinea a lo largo del margen derecho.
rtfCenter 2 Centro. El párrafo se centra entre los márgenes izquierdo y derecho.

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 22


Propiedad Scrollbars
rtfNone 0 (Predeterminado) Ninguna.
rtfHorizontal 1 Sólo barra de desplazamiento horizontal.
rtfVertical 2 Sólo barra de desplazamiento vertical.
rtfBoth 3 Barras de desplazamiento horizontal y vertical.

El FORMATO RTF

Cuando se edita un texto mediante un procesador de textos, el fichero resultante se guarda don
un formato distinto para cada procesador. De esta forma, un texto editado en WP no es
compatible con el P.T. AmiPro, con Word o con cualquier otro. Los fabricantes de estos
procesadores de textos han tenido que incluir una herramienta capaz de convertir un formato a
otro para poder alcanzar la compatibilidad entre ellos que el mercado exigía.

El Formato de Texto Enriquecido pretende ser un nexo de unión entre todos los procesadores
de texto, para poder intercambiar ficheros editados en uno u otro. De hecho, las últimas
versiones de los mas importantes procesadores de textos incluyen la posibilidad de guardar y
buscar el texto en este formato. (WP, Word)

Este formato consiste en guardar mediante caracteres ASCII plenamente legibles tanto el texto
escrito como los tipos de letra, tamaño, saltos de carro, etc. Veamos un ejemplo comparativo
del mismo texto escrito en Word, guardado en RTF y en ASCII :

Texto1

Este texto está escrito en Word. Observe que podemos poner letra negrita, letra cursiva, letra
subrayada. Podemos cambiar el color de las letras, rojo, verde, azul. Podemos cambiar el
tamaño de las letras a tamaño mas grande , mas pequeño, etc.

Fin Texto 1

El mismo texto en ASCII puro :

Texto1

Este texto est escrito en Word. Observe que podemos poner letra negrita, letra cursiva, letra
subrayada. Podemos cambiar el color de las letras, rojo, verde, azul. Podemos cambiar el
tamaño de las letras a tamaño mas grande, mas pequeño, etc.

Fin Texto 1

Y ahora el mismo texto en formato RTF. En este formato hubo que seccionar las líneas para
poder mostrarlas en una hoja, ya que RTF utiliza líneas sin retornos de carro. Se han
seccionado las líneas terminándolas con un guión bajo y comenzando en la línea siguiente
también con un guión bajo.

{\rtf1\ansi \deff5\deflang1033{\fonttbl{\f5\fswiss\fcharset0\fprq2 Arial;}}_


_{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;_
_\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;
\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\_
_green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\_
blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue_
_192;}{\stylesheet{\widctlpar
\f5\fs20\lang1034 \snext0 Normal;}{\*\cs10 \additive Default Paragraph Font;}_
_}{\info{\author LUIS SUAREZ BERNALDO}{\operator LUIS SUAREZ BERNALDO}_
_{\creatim\yr1997\mo3\dy9\hr11\min8}{\revtim\yr1997\mo3\dy9\hr11\min9}_

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 23


_{\version1}{\edmins1}{\nofpages1}
{\nofwords38}{\nofchars220}{\*\company }{\vern57431}}\margl1701\margr1701\_
_margt1417\margb1417 \deftab708\widowctrl\ftnbj\aenddoc\hyphhotz425\formshade_
_ \fet0\sectd \linex0\headery709\footery709\colsx709\endnhere {\*\pnseclvl1
\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstar_
_t1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\_
_pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5
\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcl_
_tr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\_
_pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pn_
_start1\pnindent720\pnhang
{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{_
_\pntxtb (}{\pntxta )}}\pard\plain \qj\widctlpar \f5\fs20\lang1034 Texto1
\par
\par Este texto est\'e1 escrito en Word. Observe que podemos poner letra _
_{\b negrita}, letra {\i cursiva}, letra {\ul subrayada}. Podemos cambiar_
_ el color de las letras, {\cf6 rojo}, {\cf4 verde}, {\cf2 azul}. Podemos _
_cambiar el tama\'f1o de las letras a {
\fs24 tama\'f1o mas grande}, {\fs16 mas peque\'f1o}, etc.
\par
\par
\par Fin Texto 1
\par \pard \widctlpar
\par }

Como puede observar, el RTF incluye el texto escrito casi en ASCII, pero añadiendo una serie
de datos respecto al tipo de letra, codifica los acentos, las eñes, y hasta incluye, tomándolo del
ordenador, el nombre del operador que lo ha escrito. Estas informaciones también se guardan
cuando se archiva un texto en el formato propio del procesador de textos, pero lo hace en
binario, por lo que no lo podemos visualizar. El formato RTF, dentro de que mete toda esa
información adicional, lo archiva con caracteres ASCII.

MUY IMPORTANTE

Observe que el fichero .RTF comienza por {\rtf Cuando tenga que importar un texto hacia un
RichTextBox, puede que ese texto esté en formato RTF o como Texto Plano (Fichero ASCII
puro) Para saber si el texto está en RTF analice los Cinco primeros caracteres del texto a
importar. Si son {\rtf es que está en presencia de un texto RTF.

Para saber si un fichero contiene texto enriquecido, basta con abrirlo como un fichero
secuencial, (recuerde que un fichero .RTF tiene solamente caracteres ASCII) y leer los cinco
primeros caracteres.

Ejercicio Propuesto. Conlos conocimientos de los Documentos de Interfaces Multiples, y los


del RichTextBox que ha adquirido en este capítulo, y los conocimientos del menú y los ficheros
que ya tiene de los capítulos anteriores, ya está en condiciones de realizar un editor de textos,
casi tan bueno como el Word. Debe ponerle las funciones típicas de cortar, copiar y pegar,
documento nuevo, cerrar, guardar, guardar como, y cada vez que cierra un documento debe
saber si ha habido cambios para proponer que se guarden.

LSB Visual Basic - Guía del estudiante Capítulo 9 Página 24


LSB Visual Basic - Guía del estudiante Capítulo 9 Página 25
Visual Basic - Guía del Estudiante Cap. 10

Procedimientos y funciones en VB
CORRECCION DE ERRORES Y DEPURACION DE PROGRAMAS - EL OBJETO ERROR
LA AYUDA DE WINDOWS

Procedimientos
Un Procedimiento en Visual Basic es un trozo de código que realiza una determinada tarea. Un
procedimiento es el código que asociamos a un evento de un control (CommandButton_Click,
Form_Load, ...). Un control puede tener por lo tanto, muchos procedimientos asociados. Uno a
cada uno de sus eventos.

Si queremos realizar una determinada tarea en un programa, y esta tarea se repite muchas
veces en ese programa, podemos, por ejemplo, repetir el código tantas veces como sea
necesario en los puntos del programa que así lo pidan. Esto nos llevaría a escribir líneas y
líneas repetidas en nuestras aplicaciones, con el consiguiente incremento de trabajo y del
volumen de la aplicación.

Podemos hacer otra cosa mas práctica y elegante. Escribir ese código una sola vez, creando
con él un Procedimiento. Este Procedimiento tendrá un nombre, y cada vez que queramos que
se ejecute ese código bastará con nombrar por ese nombre al Procedimiento.

Un procedimiento puede insertarse en un Módulo o en Formulario. Para crear un Procedimiento


basta con hacer click en la Barra de Menú de VB en Insertar | Procedimiento. Observará que
la palabra Procedimiento del Menú desplegable está deshabilitada si no está abierta ninguna
ventana de código. Para habilitarla, abra la ventana de código del Formulario o Módulo donde
quiere insertar el nuevo Procedimiento.

Una vez hecho Click en Insertar | Procedimiento le aparecerá esta ventana :

En esta ventana debe teclear el nombre que quiere dar al Procedimiento. En tipo debe elegir la
opción Procedimiento (Veremos mas adelante la Función y en otro capítulo las opciones
Propiedad y Evento) y en el Ambito debe elegir Public o Private dependiendo del ámbito que
quiera darle :

Public. Se podrá acceder a él desde cualquier Formulario o Módulo del programa.


Dependiendo de donde se haya insertado el Procedimiento (Formulario o Módulo), debe citarse
de la siguiente forma :

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 1


Si se ha insertado en un Módulo, puede citarse solamente por su nombre. Puede citarse
también por el nombre del módulo seguido por el nombre del procedimiento, separando ambos
por un punto. Si el procedimiento tiene por nombre NombreProcedimiento y se ha insertado en
el Módulo1 puede citarse de las dos formas siguientes en cualquier parte del programa:

NombreProcedimiento
Modulo1.NombreProcedimiento

Si se ha insertado en un Formulario, desde ese Formulario basta con citarle por su nombre.
Desde otro Formulario o Módulo, hay que citarlo mediante el nombre del Formulario donde está
insertado, seguido del nombre del procedimiento, separados por un punto.

Private. Si elige este ámbito, sólo se podrá acceder a ese Procedimiento desde el Formulario o
Módulo donde se haya insertado.

La caja de opción (Check) que pone Todas las variables locales como estáticas nos va a
poner todas las variables declaradas dentro del procedimiento como estáticas (No ponen a cero
o nulo su valor cuando salimos y volvemos a entrar en ese procedimiento). Puede ahorrarnos
un poco de código.

El código de los Procedimientos se guarda en el General del Formulario o Módulo donde se han
insertado :

Para llamar a un procedimiento desde cualquier parte del código basta con escribir en una línea
el nombre del procedimiento.

fpublico

Muchos programadores anteponen la palabra Call

Call fpublico

No hace falta poner Call, aunque Visual Basic lo admite. Algunos programadores me dicen que
al poner Call, siempre se enteran mejor de que están llamando a un procedimiento. Me parece
muy bien, y creo que es una buena razón. Pero no existe otra razón para ello.

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 2


Los datos que se puedan generar en un procedimiento debe extraerlos de ese procedimiento
mediante variables. Verá que con las funciones es distinto.

Cuando se llama a un procedimiento, se lleva a ese procedimiento la condición de tratamiento


de errores que existe en el procedimiento desde el que se llamó. Por ejemplo:

Private Sub Boton1_Click()


On Error GoTo RutErr

Lineas de código de este procedimiento


‘Llamada al Procedimiento Calcula_Dietas
Calcula_Dietas

Mas líneas de código de este procedimiento

RutErr:
End Sub

Si al ejecutarse el procedimiento Calcula_Dietas ocurre un error, al detectarse ese error


interceptable, el programa salta a ejecutar la línea RutErr del procedimiento Boton1_Click.

Esto puede producirse serios problemas a la hora de depurar su programa. Para evitar que
suceda eso, y que se pare la ejecución del programa en la línea del procedimiento
Calcula_Dietas en la que se produjo el error, inicie este procedimiento con una instrucción que
anule la condición de tratamiento de errores:

Public Sub Calcula_Dietas()


On Error Goto 0
…………….
Ens Sub

Funciones
Una función es una forma especial de realizar un procedimiento. En realidad es un
procedimiento al que le pasamos una o varios parámetros con los que realizará una operación
(cualquier operación, no tiene porqué ser matemática) y obtendrá un resultado de esos
parámetros. Este resultado puede leerse desde otra parte de la aplicación en una variable que
tienen el mismo nombre que la función. La forma de obtener los datos de la función es llamar
directamente a esa función, como verá un poco más adelante.

Para insertar una Función se procede de igual forma que para un Procedimiento, pero
marcando el botón de opción Tipo Función en la caja de diálogo de la figura anterior.

El ámbito de una Función es el mismo que el un Procedimiento. Si se declara Pública puede


usarse en toda la aplicación. Si se declara Privada, solamente en el Formulario o Módulo donde
se haya insertado.

Para llamar a una Función son válidos igualmente los criterios expuestos para los
Procedimientos en cuanto a la sentencia Call.

Parámetros de una Función

Se dijo anteriormente que a una Función se le pasan uno o varios parámetros con los que va a
realizar alguna operación. Al declarar la Función, hay que decirle el nombre de los parámetros
que se le van a pasar, de que tipo son (String, Integer, Boolean, ...) y cómo se le van a pasar
(ByVal, ByRef, ParamArray). Esto hay que introducírselo en la propia declaración

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 3


Public Function MiFuncion(ByVal Variable1 as String, ByVal Variable2 as Integer)

End Function
La función MiFuncion sabe que debe recibir dos parámetros, y que el primero será una cadena
de caracteres y el segundo un integer. Los nombres Variable1 y Variable2 son los nombres que
usa la Función internamente. No tienen porqué coincidir con los nombres que tengan las
variables que contienen esos valores en otras partes del programa.

Una función siempre da un resultado. Este resultado se le introduce en una variable que tiene el
mismo nombre que la función. Esta variable no hace falta declararla, ya que la declaración de
la función lleva implícito que exista una variable con ese nombre.

Imaginemos que lo que va a hacer la función de este ejemplo es tomar una cadena de
caracteres (Variable1) y obtener de ella otra cadena con los caracteres iniciales de la primera,
tantos caracteres como nos indique la segunda variable (Variable2)

Si, por ejemplo, le pasásemos los valores :

Variable1 = Guía del Estudiante


Variable2 = 14

Obtendríamos como resultado la cadena Guía del Estud

Ya se habrá dado cuenta de que debemos emplear Left para obtener los caracteres iniciales de
una cadena. Nuestra función quedará de la forma :

Public Function MiFuncion(ByVal Variable1 as String, ByVal Variable2 as Integer) As String


MiFuncion =Left (Variable1, Variable2)
End Function

(Observe que hemos añadido la expresión As String al final de la declaración. Esto quiere
significa que le estamos diciendo a la función que su resultado es un String,)

Donde MiFuncion es una variable que se ve en todo el ámbito de la función. Para llamar a la
función, basta con citarla por su nombre y ponerle los parámetros necesarios. Cuando esté
tecleando el código, Visual Basic le invitará a introducir los parámetros citándole su nombre. (En
nuestro ejemplo, ByVal Variable1 as String, ByVal Variable2 as Integer

En cualquier parte del programa podemos poner :

Label1.Caption = MiFuncion (Guía del Estudiante, 14)

y Label1 tomará como Caption la cadena Guía del Estud

Pruebe esto con una pequeña aplicación. En un formulario, ponga un TextBox (Text1) donde va
a introducir la cadena original, otro TextBox donde va a introducir el número de caracteres a
tomar, y un Label (Label1) donde va a ver el resultado. Ponga un Botón de comando
(Command1) donde llamará a la función. Inserte una función (MiFuncion) en ese formulario :

Private Sub Command1_Click()


Label1.Caption = MiFuncion(Text1.Text, Val(Text2.Text))
End Sub

Public Function MiFuncion(ByVal Variable1 As String, ByVal Variable2 As Integer) As String


MiFuncion = Left(Variable1, Variable2)
End Function

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 4


Puede pensar que para hacer esta cosa tan elemental no merece la pena hacer una función.
Efectivamente. Bastaría con poner en el botón Command1_Click el siguiente código :

Label1.Caption = Left(Text1.Text, Val(Text2.Text))

y funcionaría igual. Lógicamente, una función debe introducirse cuando vaya a realizar un
código un poco mas complejo, y sobre todo, cuando se va a repetir en muchos procedimientos.

Hemos visto que los parámetros de la función pueden pasarse Por Valor (ByVal), caso del
ejemplo anterior, y Por Referencia (ByRef). ¿Cuál es la diferencia ? La diferencia es que si le
pasa un valor por valor (ByVal) ese valor, aunque lo cambie la función internamente, ese
cambio no se manifiesta fuera de ella. Si se pasa por referencia (ByRef), y la función cambia el
valor de esa variable, ese cambio se mantiene fuera de la función.

Veamos esto de una forma muy sencilla : Vamos a hacer una función que multiplica dos
números. Pero dentro de la función vamos a cambiar uno de esos números, sumándole 2. Una
vez realizada la operación presentamos el valor de los dos factores en dos Label a ver si ha
cambiado. Insertemos dos funciones, MultiplicaA y MultiplicaB. En MultiplicaA le introducimos
los datos Por Valor y en MultiplicaB por Referencia.

Public Function MultiplicaA(ByVal X1 As Integer, ByVal X2 As Integer) As Integer


x1 = x1 + 2
MultiplicaA = x1 * x2
End Function

Public Function MultiplicaB(ByRef X1 As Integer, ByRef X2 As Integer) As Integer


x1 = x1 + 2
MultiplicaB = x1 * x2
End Function

Las dos funciones son idénticas, excepto en la forma de pasarle los parámetros. Pongamos un
Botón de Comando para multiplicarlo con MultiplicaA y otro con MultiplicaB. Al final del
procedimiento click de cada uno de ellos presentamos las dos variables que se pasan a la
función en sendos Label. Cuando se usa MultiplicaA el valor de X1 (pepe en el
CommandButton) se mantiene. En MultiplicaB cambia al valor pepe+2

Private Sub Command1_Click()


Dim pepe As Integer
Dim juan As Integer
pepe = Val(Text1)
juan = Val(Text2)
Label1 = MultiplicaA(pepe, juan)
Label2 = pepe
Label3 = juan
End Sub

Tras esto, se pone en Lable2 el valor pepe

Private Sub Command2_Click()


Dim pepe As Integer
Dim juan As Integer
pepe = Val(Text1)
juan = Val(Text2)
Label1 = MultiplicaB(pepe, juan)
Label2 = pepe
Label3 = juan
End Sub

Tras esto, se pone en Label2 el valor pepe + 2 (se mantienen el cambio realizado en la función
MultiplicaB x1 = x1 + 2

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 5


No queda ahí la cosa. Un valor puede pasarse también por ParamArray. En principio parece
que esto ya es para nota. No es para tanto.

Vamos a ver que sucede cuando queremos realizar una suma. La suma de los importes de
varios productos de un ticket de compra. En principio no sabemos cuantos productos va a
comprar un cliente, por lo tanto no sabemos a priori cuantos parámetros le tenemos que pasar.
Para pode pasar un número indeterminado de parámetros se los pasamos como PamArray :

Public Sub sumacifras(ParamArray cifra())


Dim I As Integer
Dim suma As Integer
For I = LBound(cifra) To UBound(cifra)
suma = suma + CInt(cifra(I))
Next I
Label1.Caption = suma
End Sub

Private Sub Command2_Click()


sumacifras 1, 2, 3, 4, 5, 6, 7, 8
End Sub

Este código nos suma las cifras 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8

La variable que se pasa con ParamArray debe ser Variant

Existe otra forma de pasar parámetros : Optional

Cuando se declara una función con un determinado número de parámetros, es necesario


pasárselos todos. Si no se hace así, VB nos dará un error. Pero puede que algún parámetro no
exista siempre. Cuando uno o varios de los parámetros que se pasan a una función son
opcionales, se le pueden pasar como Optional.

Se pueden pasar uno o mas parámetros como Optional. Las condiciones para los parámetros
opcionales es que ocupen los últimos lugares y que sean del tipo Variant

Hagamos un ejemplo en el que vamos a poner en un TextBox (TB4) el nombre y apellidos de


una persona. El segundo apellido se lo pasamos como Opcional. La declaración de la función
será :

Public Function SUMANOMBRES(NOMBRE As String, APE1 As String, Optional APE2 _


As Variant)
‘ Debemos detectar si se le ha pasado el parámetro opcional. Usamos para ello IsMissing
If IsMissing (APE2) Then
TB4.Text = NOMBRE & " " & APE1
Else
TB4.Text = NOMBRE & " " & APE1 & " " & APE2
End If
End Function

Los parámetros los tomamos de tres TextBox (TB1, TB2 y TB3, siendo este último el que es
opcional. En un botón de comando ponemos este código :

Private Sub Command1_Click()

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 6


If TB3 <> "" Then
SUMANOMBRES TB1, TB2, TB3
Else
SUMANOMBRES TB1, TB2
End If
End Sub

Salir de una función


La forma natural de salir de una función es cuando se ejecuta todo su código. Al final siempre
tiene la sentencia End Function

Se puede salir de una función antes de que termine. Por ejemplo, si se cumple una
determinada condición, se puede salir de la función mediante la sentencia Exit Function

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 7


CORRECCION DE ERRORES Y DEPURACION DE PROGRAMAS
EL OBJETO ERROR

Una vez que conocemos gran parte del Visual Basic, y que seguramente habremos hecho
alguna aplicación, es momento de pararnos en una de las cosas que un programador nunca
debe olvidar: Un programa no solo debe funcionar, sino que debe funcionar bien.

Parece que esta afirmación carece de sentido o que al menos es una afirmación gratuita. Sin
embargo es un defecto muy común entre programadores noveles, quizás por la alegría que da
el trabajo terminado, olvidarse de algo tan fundamental como la calidad del programa, y perder
por ello la alegría que da el trabajo bien hecho.

Cuando terminamos un programa, lo normal es que no funcione bien. Mucho antes de


terminarlo ya habremos tenido la sorpresa de que Visual Basic ha detectado un error y detiene
la ejecución del programa. Iremos corrigiendo los errores elementales que van apareciendo,
errores de sintaxis, ficheros que ya estaban abiertos, End If que nos faltaban, etc. Y el
programa parece que ya puede funcionar hasta el final. El programa debe entrar entonces en la
fase de corrección de errores y optimización.

Corrección de Errores.
Denominamos Corrección de errores al proceso de la programación en la que se analizan y
corrigen los errores existentes en el código o en el funcionamiento del programa.

Podemos por tanto dividir los errores en errores de código y errores de funcionamiento.

Es un error de código, por ejemplo, la siguiente línea de programa:

Open A:\MiFicher.Txt For Input as #1

Habrá notado el error de bulto consistente en que A:\MiFicher.Txt debe ir entre comillas dobles.
Este tipo de error se detecta generalmente al ejecutar el código. En este caso, Visual Basic nos
dará el mensaje de error “Error de Sintaxis” nada mas terminar de escribir la línea. Errores
como este, o el típico If sin End If seguro que se los ha encontrado repetidas veces y no vamos
a ahondar mas en ellos. Se corrige el error sintáctico en el momento y el problema queda
resuelto. Pero volvamos a la línea de código anterior, esta vez ya bien escrita:

Open “A:\MiFicher.Txt” For Input as #1

Al estar escrita correctamente, esta línea no nos puede dar error de sintaxis. Pero, ¿Que ocurre
cuando estamos ejecutando el programa que contiene esa línea, y en el momento de ejecutarla
no tenemos metido un disquete en la unidad A:? O piense lo que ocurriría si tenemos un
disquete en A:, pero no existe en él el fichero MiFicher.Txt. No existe ningún error de sintaxis.
El programa puede funcionar correctamente si, en el momento de la ejecución de esa línea,
tenemos un disco en la unidad A: y éste contiene un fichero llamado MiFicher.Txt. Sin embargo
no puede funcionar si no tenemos metido el disquete, o si este no tiene el mencionado fichero.

En cualquiera de estos dos últimos casos se produce un Error de Ejecución.

Existen dos tipos de errores de ejecución: Errores Interceptables y Errores que no se pueden
interceptar.

Los errores interceptables son aquellos que Visual Basic conoce. Los dos errores anteriores
son de este tipo. Son errores no interceptables, aquellos que Visual Basic no puede detectar.
No porque no los conozca, sino porque el propio error deja sin trabajar a Visual Basic o incluso
al sistema operativo. Afortunadamente el sistema operativo está muy protegido, pero no por ello
dejan de ocurrir estos errores. ¿Recuerda la frase “El programa xxx ha causado un error de
protección general en el Módulo..... “ Bueno, acaba de producir un error No Interceptable.

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 8


No solamente existen estos errores, también hay errores no catalogados y aplicables solamente
al programador. Piense en un bucle infinito. Un bucle infinito es una secuencia de instrucciones
tal como:

Do While n < 2000


n=n+1
If n = 1000 then n = 0
Loop

Podrá advertir que este bucle no se termina nunca, ya que n no podrá alcanzar nunca el valor
2000 ya que cada vez que llega a 1000 le cambiamos su valor a 0. Este tipo de error, más
normal de lo que parece, ni lo detecta VB ni produce una caída del sistema operativo. Sin
embargo es un error, pero en este caso será el propio programador quien se tenga que dar
cuenta de él, ya que VB no puede ayudarnos debido a que el código, línea a línea, está
perfectamente escrito.

Vemos por tanto que VB solamente nos ayudará en los errores de sintaxis, durante el tiempo de
diseño, y los errores interceptables en tiempo de ejecución.

Errores Interceptables.

Veamos lo que dice la ayuda de VB para este tema:

Los errores interceptables pueden producirse cuando está ejecutando una aplicación, tanto
en el entorno de Visual Basic como en modo autónomo. Algunos de estos errores pueden
ocurrir también en tiempo de diseño o en durante la compilación.

Un error interceptable es, como decíamos anteriormente, un error que Visual Basic conoce.
Para conocerlos, VB dispone de un objeto que vamos a ver a continuación. El Objeto Error

Objeto Error
Contiene información sobre errores en tiempo de ejecución.

El Objeto Error tiene Propiedades y Métodos. Las propiedades del objeto Error las establece
quien genera el error. Por ejemplo, si el error se genera durante la ejecución, será VB quien
genera las propiedades del objeto Error. Pero puede ser también el programador quien genere
el error. Lo veremos mas adelante

Al objeto Error se le designa por Err

Las propiedades del Objeto Error son:

Description, HelpContext, HelpFile, LastDLLError, Number, Source

Propiedad Description
Devuelve o establece una cadena descriptiva asociada a un error.

Sintaxis Variable = Err.Description


Err.Description = Cadena descriptiva del error

Veremos un ejemplo mas adelante.

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 9


Propiedad HelpContext

Devuelve o establece el identificador de contexto de un tema para un archivo de Ayuda de


Microsoft Windows.

Sintaxis Err.HelpContext [= id_contexto]


Variable = Err.HelpContext

Esta propiedad y la siguiente le permiten presentar automáticamente la ayuda cuando se


produce un error.

Propiedad HelpFile

Devuelve o establece la ruta completa del archivo de Ayuda de Microsoft Windows que debe
mostrarse al producirse el error.

Sintaxis Err.HelpFile = “C:\MiCarpeta\MiFicherodeAyuda.Hlp”

También puede leer el valor de esta propiedad:

Variable = Err.HelpFile

Cuando se especifica un archivo de Ayuda de Microsoft Windows en HelpFile, se le llama


automáticamente cuando el usuario presiona el botón Ayuda (o la tecla F1) del cuadro de
diálogo del mensaje de error. Si la propiedad HelpContext contiene un identificador de contexto
válido para el archivo especificado, se mostrará automáticamente el tema correspondiente. Si
no se especifica nada en HelpFile, aparecerá el archivo de Ayuda completo.

Propiedad LastDLLError
Devuelve un código de error de sistema producido por una llamada a una biblioteca de vínculos
dinámicos (DLL). Esto ocurre cuando falla la ejecución de una función API.

Propiedad Number
Esta es la propiedad mas importante del Objeto Error. Por ello es la propiedad predeterminada.
Permite conocer el número del error producido. También nos permite establecer el número de
error, cuando nos interesa provocar un error mediante código, con el método Raise

¡¡¡ Number es una variable tipo Long !!!

Sintaxis Variable = Err.Number

Al ser la propiedad predeterminada, no es necesario poner Number. La siguiente línea es


operativamente igual a la anterior:

Variable = Err

Source

Devuelve o establece el nombre del objeto o aplicación que ha generado el error


originariamente.

Sintaxis Variable = Err.Source


Err.Source = expresión_cadena

Vea en la ayuda de VB la explicación (muy ilustrativa) de esta propiedad.

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 10


El Objeto Error tiene solamente dos métodos:

Método Clear
Borra los valores de todas las propiedades del objeto Err.

Sintaxis Err.Clear

Puede utilizar Clear para borrar explícitamente el objeto Err una vez que se ha tratado un error.
Visual Basic llama al método Clear automáticamente siempre que se ejecuta alguna de las
instrucciones siguientes:

Cualquier tipo de instrucción Resume


Exit Sub, Exit Function, Exit Property
Cualquier instrucción On Error

De aquí se desprende que un error no “sale” del procedimiento en el que se generó. Para salir
de un procedimiento el programa debe pasar necesariamente por una instrucción Exit Sub. En
ese momento, desaparecen todas las propiedades del Objeto Error.

Método Raise
Genera un error en tiempo de ejecución.

Sintaxis Err.Raise(Número, Origen, Descripción, ArchivoAyuda, ContextAyuda)

Los argumentos de Raise se describen a continuación.

Número Requerido. Entero de tipo Long que identifica la naturaleza del error.
Origen Opcional. Expresión de cadena que indica el objeto o aplicación que ha generado
originariamente el error.
Descripción Opcional. Expresión de cadena que describe el error.
ArchivoAyuda Opcional. Ruta del archivo de Ayuda de Microsoft Windows en el que se
encuentra la información sobre el error.
ContextoAyuda Opcional. Identificador de contexto que especifica el tema del archivo indicado
en ArchivoAyuda que contiene la información de ayuda del error.

Todos los argumentos son opcionales, excepto Número. Sin embargo, si utiliza Raise sin
especificar algunos argumentos, y si los valores de las propiedades del objeto Err no se han
borrado, tales valores se conservarán para el error actual.

Decíamos al principio del Objeto Error que sus propiedades las establece quien las generó. Con
el Método Raise se genera un error. Y vea que se pueden establecer sus propiedades.

Control de los errores


Ya sabemos que herramienta usa Visual Basic para detectar errores. Vamos a ver ahora como
usarla. Pero veamos previamente lo que es en Visual Basic una Rutina. No se extrañe si
alguien le llama Label o Etiqueta. En otros lenguajes se llama así, incluso en Q-Basic, donde
no existían los controles Visual Basic llamados etiquetas, se usaba esta denominación. En
Visual Basic no podemos usarla, para no confundirla con el control.

Una Rutina es un trozo de código escrito en un procedimiento, que tiene un nombre. El nombre
de la Rutina puede ser cualquiera, y debe terminar con el carácter dos puntos (:) Por ejemplo:

RutinaErrores:

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 11


El nombre de la rutina debe ocupar él solo una línea. Se accede directamente a la rutina cuando
citamos su nombre en el código del procedimiento donde está la Rutina.

Para citarla, debemos usar ese nombre, quitando el carácter dos puntos final. Podemos
llamarla mediante la sentencia GoTo. Veamos un pequeño ejemplo. Es un botón de comando,
y un TextBox. Si el TextBox (Text1) mantiene su texto original (Text1) hacemos que el
programa pase por la rutina. Si lo hemos variado, hacemos que no pase:

Private Sub Command1_Click()


If Text1 = "Text1" Then
GoTo Rutina
Else
MsgBox "No pasa por la Rutina"
End If
Exit Sub
Rutina:
MsgBox "Sí pasó por la Rutina"
End Sub

La rutina es en realidad un trozo de código del procedimiento que se ejecutará, bien porque
hayamos dirigido allí la ejecución del programa (mediante GoTo) o bien porque el programa
pase por la rutina al ejecutarse. Observe el Exit Sub que tiene en la línea inmediatamente
anterior a la Rutina. Si no lo ponemos, el programa pasará por la rutina una vez ejecutada la
sentencia condicional If - Else - End If, igual que si se tratase de cualquier otra parte del
programa. Para evitar que pase por ella, ponemos ese Exit Sub que hará que el programa salga
del procedimiento sin llegar al final.

En el ejemplo anterior, la condición para que pasase por la rutina era que se cumpliese una
determinada condición en Text1. Para que pase por una rutina, al darse la condición de que ha
ocurrido un error, usaremos la instrucción On Error GoTo

Importante. Cuidado con GoTo


Hay un dicho entre los programadores de Visual Basic. Los programadores se dividen en tres
grupos. Los que nunca usan GoTo. Los que usan GoTo sin saber usarla y los que usan GoTo
sabiendo usarla, pero dicen que de estos últimos hay muy pocos.

Instrucción On Error GoTo


Activa una rutina de tratamiento de errores y especifica la ubicación de la misma en un
procedimiento. También puede utilizarse para desactivar una rutina de tratamiento de errores.

Sintaxis On Error GoTo Rutina ‘Va a la Rutina especificada


On Error Resume Next ‘Pasa del error y continúa en la línea siguiente a
‘la que provocó el error
On Error GoTo 0 ‘Desactiva todo el tratamiento de errores que
‘haya activado en el procedimiento actual.

Veamos el ejemplo anterior, con la instrucción On error GoTo.

Private Sub Command1_Click()


On Error Resume Next
‘Con la línea anterior le decimos que se olvide del error y siga en la línea siguiente
‘a la que provocó el error
If Text1 = "Text1" Then
GoTo Rutina
Else
On Error GoTo 0
‘La línea anterior desactiva el tratamiento de errores generado en la línea segunda (On
‘Error Resume Next). Pruebe a quitar y poner esta línea (On error GoTo 0)

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 12


Err.Raise 53
‘En la línea anterior generamos “artificialmente” el error 53
MsgBox "No pasa por la Rutina"
Exit Sub
End If

Rutina:
MsgBox "Sí pasó por la Rutina"
End Sub

Cuando insertamos la línea On Error GoTo Rutina, el programa sabe que nada mas
producirse un error, debe ir a la rutina señalada. En esa rutina tomaremos las medidas
adecuadas para que se subsane el error producido. Así por ejemplo, si en una línea le decimos
al programa que vaya a leer un fichero de la unidad A:, puede ocurrir que la unidad no tenga
metido el disco. O que lo tenga metido pero que no exista el fichero en ese disco.

La rutina de corrección de errores debe contemplar cada uno de esos dos casos, y actuar de
forma distinta en uno y en otro.

Hagamos un ejemplo donde al pulsar un botón (Command2) se busca el fichero Mificher.Txt en


el disco A: y el contenido de ese fichero se coloca en Label1

Private Sub Command2_Click()


Dim Variable As String
Open "A:\Mificher.Txt" For Input As #1
Line Input #1, Variable
label1.Caption = Variable
Close #1
End Sub

Si no está metido el disco en la unidad A nos dará el siguiente error:

Se ha producido el Error ‘71’ de tiempo de ejecución. El disco no está listo

Si estuviese metido el disco, pero no tuviera un fichero llamado Mificher.Txt, daría este error:

Se ha producido el Error ‘53’ de tiempo de ejecución. No se ha encontrado el archivo

En realidad estos errores no son de programa, sino de una utilización incorrecta del programa,
ya que debería estar metido el disco, y que contuviese un fichero llamado Mificher.Txt. Pero en
programación hay que prever estas eventualidades. Y lo lógico sería poner un aviso diciéndole
al usuario que la unidad A: no está preparada (caso 1) o que el disco no contiene el fichero
buscado (caso 2)

Instrucción Resume
Hemos visto en el apartado anterior la sentencia On Error Resume Next, de la que decíamos
que “pasaba” del error y continúa en la línea siguiente a la que provocó el error. Es así ya que
la Instrucción Resume hace desaparecer el error mediante código (Pone Err.Numbber = 0). Si
le añadimos Next el programa sigue ejecutándose en la línea siguiente a la que generó el error.
La Instrucción Resume puede tener las siguientes sintaxis:

Sintaxis Resume [0]


Resume Next
Resume Rutina

Resume [0] Si el error se ha producido en el procedimiento que contiene el controlador de


errores, la ejecución continúa con la instrucción que lo causó.

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 13


Puede ocurrir que el error no se haya producido en el mismo procedimiento que contiene la
rutina de tratamiento de errores, sino en otro al que se le ha llamado desde este. En este caso,
la ejecución continúa en la instrucción del procedimiento que contiene la rutina de tratamiento
de errores desde la que se llamó a otro procedimiento.

Resume Next Si el error se ha producido en el procedimiento que contiene el controlador de


errores, la ejecución continúa con la instrucción inmediatamente posterior a la que lo causó. Si
el error se ha producido en un procedimiento llamado, la ejecución continúa en la instrucción del
procedimiento que contiene la rutina de tratamiento de errores (o la instrucción On Error
Resume Next) inmediatamente posterior a aquélla desde la que se llamó a otro procedimiento.

Resume Rutina La ejecución continúa en la rutina citada en la instrucción. La rutina debe


encontrarse en el mismo procedimiento que el controlador de errores.

Ya que conocemos las instrucciones On Error GoTo y Resume, veamos en el ejemplo anterior
como resolvemos el problema de que no exista disco en la unidad A: o que en el disco no exista
el fichero buscado:

EJEMPLO

Activemos la detección de errores e introduzcamos una rutina que detecte el error ocurrido y
que haga lo que tenga que hacer en cada caso:

Private Sub Command2_Click()


On Error GoTo RutinaErrores
Dim Variable As String
Open "A:\Mificher.Txt" For Input As #1
Line Input #1, Variable
Label1.Caption = Variable
Close #1

RutinaErrores:
If Err.Number = 71 Then ‘No hace falta poner Err.Number. Basta con Err
MsgBox "La Unidad A no tiene ningún disco. Introduzca uno"
Resume ‘Al poner Resume (sin mas) el programa seguirá ejecutándose
‘en la misma línea que provocó el error. Como hemos
‘intercalado un MsgBox, que lleva implícita una espera a que se
‘le haga click en su botón, durante esa espera el usuario puede
‘cambiar el disco y al reiniciarse el programa en esa línea, ya
‘puede tener un disco para que no se repita el error.
End If

If Err = 53 Then ‘Aquí hemos puesto solamente Err


MsgBox "El disco A no tiene ningún fichero llamado Mificher.Txt. Ponga el disco correcto"
Resume
End If
End Sub

Ventana de Depuración. El Objeto Debug


Es momento ahora de hablar de la ventana de depuración. Esta ventana permite que Visual
Basic se comunique con nosotros en tiempo de ejecución. Es la ventana de Debug. No está
presente normalmente en la pantalla, pero se presenta haciendo click en Ver | Ventana de
Depuración de la barra de menú de Visual Basic. En esta ventana se presenta lo que
escribamos en un objeto preparado para ayudarnos en la corrección de errores, que se llama
precisamente Objeto Debug:

Este objeto no tiene propiedades y tiene solamente un método: el Método Print

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 14


En esta ventana podemos presentar otro tipo de datos, por ejemplo el valor de una variable en
un determinado momento:

Debug.Print MiVariable

Veremos en el ejemplo de este capítulo una aplicación de la ventana de depuración que le


dejará claras las ideas.

Si queremos que cuando se produzca un error se nos presente en esa ventana, basta con
insertar esta línea de código en la Rutina de Error:

Debug.Print Err.Number o simplemente


Debug.Print Err

Hemos visto la forma de detectar un error y tomar las medidas oportunas para que el programa
siga funcionando. Aquí lo hemos hecho solicitándole una operación al usuario. En otros casos
nos interesará que el programa “pase” del error, en otras que repita un procedimiento... El
programador deberá ver en cada caso la respuesta que debe dar el programa a un determinado
error.

Un programa perfecto es aquel que contempla todas las posibilidades de error y les da solución
a todas. Esto quiere decir, que un programa debería tener en cada procedimiento una llamada a
la detección de errores (On error GoTo ... ) y una rutina de corrección. El trabajo es grande. La
recompensa también.

Pero un error muy común entre programadores es autocomprobar sus errores. Realiza un
programa y comienza a ejecutarlo intentando descubrir los errores en los que puede caer. Le
recomiendo que esa labor la realice un compañero. La persona que realizó el programa sabe
perfectamente lo que debe hacer. Y aún queriendo, le cuesta mucho trabajo cometer errores.
Una persona que nunca haya trabajado con el programa, lo que le cuesta trabajo es no
cometerlos.

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 15


LA AYUDA DE WINDOWS

NOTA sobre las ayudas de los programas Windows


Hasta ahora era normal presentar las ayudas en el formato cásico de fichero .Hlp. Sin embargo,
dado el auge que ha tomado el formato Html (sobre todo desde que Microsoft lo incluyó como
una parte más de Windows), actualmente se está usando más el formato .Html que el .Hlp. Las
razones son bastante obvias. La edición de un fichero Html es mucho mas sencilla que la de un
Hlp (Y si no se lo cree, léase este capítulo) Pese a todo, se sigue incluyendo este tema, ya que
el formato Hlp sigue siendo actual. Eso sí, este capítulo no se ha actualizado, y cuando se habla
del HC.Exe deberíamos estar hablando del HelpWorkShop (HWC.Exe), un programa que
funciona en Windows, y para el que es aplicable todo lo descrito aque de los fichero .Hpj.

Toda aplicación bien terminada debe tener una ayuda. Cualquier aplicación realizada en Visual
Basic puede tenerla, usando para ello los recursos que brida Windows.

La presentación de la ayuda podría hacerse mediante un formulario, donde se presentan


distintos ficheros según las necesidades del usuario. Sin embargo esta forma de presentar la
ayuda nunca llegará a ser tan completa como la que brinda Windows, y el trabajo a desarrollar
para igualar la presentación de Windows sería laborioso. Solución : utilizar los recursos de
Windows.

El recurso de Windows es un programa capaz de presentar ficheros de ayuda. Estos ficheros


son un poco especiales y solamente se pueden presentar mediante ese presentador de ficheros
de ayuda. Ese es el programa WinHelp.Exe para las versiones de 16 bits y las primeras
versiones de Windows 95, y el WinHlp32.Exe para Windows 98 y Windows NT4. Como en
todas las aplicaciones de Microsoft (MS) tienen compatibilidad hacia arriba. Por lo tanto no se
extrañe que una ayuda que le abre perfectamente el WinHlp32.Exe, si la pretende abrir con el
WinHelp.exe (que es más antiguo) le diga que no se trata de un fichero de ayuda.

Windows dispone de otra utilidad, el programa HC.EXE (Help Compiler) que puede adaptar el
fichero .RTF donde escribirá la ayuda, a un formato capaz de ser interpretado por el
WINHELP.EXE Lo vamos viendo todo paso a paso.

Antes de comenzar a explicar como se realiza una ayuda Windows vamos a comentar el
formato de archivos RTF. Este formato posiblemente le sea familiar debido a que el control
RichTextBox puede guardar y leer ficheros en ese formato. Las siglas RTF vienen
precisamente de Rich Text Format, en castellano, Formato de Texto Enriquecido.

Cuando se edita un texto mediante un procesador de textos, el fichero resultante se guarda don
un formato distinto para cada procesador. De esta forma, un texto editado en WP no es
compatible con el P.T. AmiPro, con Word o con cualquier otro. Los fabricantes de estos
procesadores de textos han tenido que incluir una herramienta capaz de convertir un formato a
otro para poder alcanzar la compatibilidad entre ellos que el mercado exigía.

El Formato de Texto Enriquecido pretende ser un nexo de unión entre todos los procesadores
de texto, para poder intercambiar ficheros editados en uno u otro. De hecho, las últimas
versiones de los mas importantes procesadores de textos incluyen la posibilidad de guardar y
buscar el texto en este formato. (WP, Word)

Este formato consiste en guardar mediante caracteres ASCII plenamente legibles tanto el texto
escrito como los tipos de letra, tamaño, saltos de carro, etc. Veamos un ejemplo comparativo
del mismo texto escrito en Word, guardado en RTF y en ASCII :

Texto1

Este texto está escrito en Word. Observe que podemos poner letra negrita, letra cursiva, letra
subrayada. Podemos cambiar el color de las letras, rojo, verde, azul. Podemos cambiar el
tamaño de las letras a tamaño mas grande , mas pequeño, etc.

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 16


Fin Texto 1

El mismo texto en ASCII puro :

Texto1

Este texto est escrito en Word. Observe que podemos poner letra negrita, letra cursiva, letra
subrayada. Podemos cambiar el color de las letras, rojo, verde, azul. Podemos cambiar el
tamaño de las letras a tamaño mas grande, mas pequeño, etc.

Fin Texto 1

Y ahora el mismo texto en formato RTF. En este formato hubo que seccionar las líneas para
poder mostrarlas en una hoja, ya que RTF utiliza líneas sin retornos de carro. Se han
seccionado las líneas terminándolas con un guión bajo y comenzando en la línea siguiente
también con un guión bajo.

{\rtf1\ansi \deff5\deflang1033{\fonttbl{\f5\fswiss\fcharset0\fprq2 Arial;}}_


_{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;_
_\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;
\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\_
_green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\_
blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue_
_192;}{\stylesheet{\widctlpar
\f5\fs20\lang1034 \snext0 Normal;}{\*\cs10 \additive Default Paragraph Font;}_
_}{\info{\author LUIS SUAREZ BERNALDO}{\operator LUIS SUAREZ BERNALDO}_
_{\creatim\yr1997\mo3\dy9\hr11\min8}{\revtim\yr1997\mo3\dy9\hr11\min9}_
_{\version1}{\edmins1}{\nofpages1}
{\nofwords38}{\nofchars220}{\*\company }{\vern57431}}\margl1701\margr1701\_
_margt1417\margb1417 \deftab708\widowctrl\ftnbj\aenddoc\hyphhotz425\formshade_
_ \fet0\sectd \linex0\headery709\footery709\colsx709\endnhere {\*\pnseclvl1
\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstar_
_t1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\_
_pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5
\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcl_
_tr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\_
_pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pn_
_start1\pnindent720\pnhang
{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{_
_\pntxtb (}{\pntxta )}}\pard\plain \qj\widctlpar \f5\fs20\lang1034 Texto1
\par
\par Este texto est\'e1 escrito en Word. Observe que podemos poner letra _
_{\b negrita}, letra {\i cursiva}, letra {\ul subrayada}. Podemos cambiar_
_ el color de las letras, {\cf6 rojo}, {\cf4 verde}, {\cf2 azul}. Podemos _
_cambiar el tama\'f1o de las letras a {
\fs24 tama\'f1o mas grande}, {\fs16 mas peque\'f1o}, etc.
\par
\par
\par Fin Texto 1
\par \pard \widctlpar
\par }

Como puede observar, el RTF incluye el texto escrito casi en ASCII, pero añadiendo una serie
de datos respecto al tipo de letra, codifica los acentos, las eñes, y hasta incluye, tomándolo del
ordenador, el nombre del operador que lo ha escrito. Estas informaciones también se guardan
cuando se archiva un texto en el formato propio del procesador de textos, pero lo hace en
binario, por lo que no lo podemos visualizar. El formato RTF, dentro de que mete toda esa
información adicional, lo archiva con caracteres ASCII.

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 17


La utilidad que tiene Windows para presentar las ayudas utiliza precisamente este formato RTF.
Por ello, debemos disponer de un procesador de textos que pueda guardar el texto escrito en
este formato. (Word, WP5, WP6 y otros) Los ejemplos de estos apuntes se han realizado en
Word.

Antes de decidirnos a escribir el fichero de ayuda debemos pensar muy bien lo que vamos a
poner en él. Pensemos ante todo a que personas va dirigida la aplicación, sus posibles
conocimientos de informática y de otros temas que estarán relacionados con la aplicación. Es
decir, planifiquemos la ayuda antes de comenzar a hacerla.

Para acceder a la ayuda, Windows ofrece la posibilidad de pulsar F1 . Nuestras aplicaciones


deben sacar la ayuda pulsando F1. Lo podrán hacer mediante otros procedimientos.
Comencemos por lo mas sencillo, una ayuda de una única página.

Escriba el texto de ayuda con Word y guárdelo en formato RTF, en cualquier directorio, pero
preferentemente en uno que no se mezcle con otros ficheros para poder localizarlo mejor. Cree
si es necesario un directorio exclusivo para la ayuda. Imaginemos que lo creamos y es el
C :\DIRAYUDA, donde guardamos el fichero de ayuda con el nombre AYUDA1.RTF

Este archivo no lo puede utilizar directamente el programa WINHELP.EXE. Hay que compilarlo.
Para ello utilizamos el compilador HC.EXE. Este compilador no es una herramienta Windows,
por lo que tendrá que ir al DOS y ejecutarlo. El programa HC.EXE se encuentra en el directorio
C :\ ..... \VB\HC

Pero al compilador HC.EXE hay que suministrarle la información para que pueda trabajar. Esa
información se la damos en un fichero que le pasaremos como parámetro, que debe tener
extensión .HPJ y que meteremos en el mismo directorio donde tengamos el fichero de ayuda
AYUDA1.RTF

Este fichero estará editado en ASCII puro. Puede editarlo con el EDIT de MS-DOS o con el
Block de Notas de Windows. Imaginemos que lo vamos a llamar FICHAYUD.HPJ y como se
dijo, se meterá en el mismo directorio donde está el fichero de ayuda. (C :\DIRAYUDA) El
nombre que decida para este fichero con extensión .HPJ será el que tenga el fichero de ayuda
(Que se obtendrá de la compilación y tendrá por extensión .HLP) Tendrá, de momento, dos
líneas.

[FILES]
AYUDA1.RTF

Vayamos al directorio C :\ ...... \VB\HC (en MS-DOS) y tecleemos

HC C:\DIRAYUDA\ FICHAYUD.HPJ

La compilación no suele dar problemas sobre todo en un fichero de ayuda tan simple de una
única página. Al compilar, obtenemos un fichero con el mismo nombre que el fichero .HPJ y
extensión .HLP, (FICHAYUD.HLP en nuestro caso) que lo dejará en el directorio donde
estuviera el programa HC.EXE. (Posiblemente el C :\VB\HC) Debe moverlo a otro directorio
donde no estorbe y lo podamos localizar sin problemas. Movámoslo al C :\DIRAYUDA
Vayamos a nuestra aplicación VB y abramos el menú de Herramientas | Opciones para sacar
el cuadro de Opciones. Vaya a la pestaña de Proyecto y busque el directorio y nombre del
fichero .HLP haciendo click sobre el cuadrado con tres puntos (...) que está a la derecha del
TextBox de Archivo de Ayuda. Se le abrirá un CommonDialog para buscarlo.

NOTA : Para evitar liarse con los directorios, es medida siempre prudente llevarse el
compilador de ayudas HC.EXE al directorio donde tengamos el fichero .RTF y el .HPJ.

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 18


Haga click en Aceptar y ejecute la aplicación. Pulse F1. ¡SORPRESA ! Tenemos en pantalla la
ventana de ayuda de Windows con el fichero que habíamos escrito. F1 ha invocado a
WINHELP.EXE y este programa presentó el fichero de ayuda asociado con el proyecto.
Observe que el texto se adapta a las dimensiones de la ventana. Y si supera en vertical las
dimensiones de la ventana, aparecen barras de scroll verticales. Puede de esta forma recorrer
todo el fichero de ayuda.

Sin embargo este procedimiento no sería el mas indicado para una información de ayuda
extensa. Deberemos poner varias páginas. Si lo hacemos así, al pulsar F1 siempre aparecerá
la página 1. Si aparece siempre la página 1, pongamos en esta primera página el índice de
temas, y en las páginas sucesivas cada uno de los temas. Ya veremos como acceder a cada
una de las páginas haciendo click sobre la línea del índice que contiene el título del tema
deseado. Tal y como lo hace con cualquier aplicación Windows.

Volvamos al editor Word y abramos el fichero que habíamos creado de una página, y añádale
mas páginas introduciendo avances de página manuales (Se introducen con Control + Intro)

Imaginemos que tenemos esta configuración del fichero :

INDICE

1 - Introducción a la aplicación
2 - Acceso a la Base de Datos
3 - Introducción de datos
4 - Lectura de datos

--------------- salto de página manual - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Introducción a la Aplicación

Esta aplicación está realizada para . . . . . . . . . .

-------------- salto de página manual - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Acceso a la Base de Datos

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 19


Para abrir la Base de datos . . . . . . . . .

-------------- salto de página manual - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Introducción de datos

Para introducir datos . . . . . . . . . . . .

-------------- salto de página manual - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Lectura de datos

Para leer los datos . . . . . . . . . . . . . . . .

Ya tenemos hecho un fichero de ayuda con varias páginas. No es suficiente esto, ya que
WINHELP.EXE , pulsando F1, solamente nos mostrará la página 1. Debemos hacer algo para,
una vez en la página 1, que nos estará mostrando el índice, poder acceder a cada una de las
páginas haciendo click sobre la línea del índice que contiene el tema de interés.

Para ello debemos poner un identificador a cada una de las páginas. Este identificador debe ser
único, es decir, no pueden existir dos páginas con el mismo identificador.

Para introducir un identificador en una página, una vez que tenga el fichero de ayuda terminado,
sitúese con el cursor al comienzo del título de la primera página (después del índice),
justamente al lado de Introducción a la Aplicación . Inserte en ese punto una Nota al pié
(Abra el Menú Insertar | Nota al Pié del Word) Le aparecerá esta ventana :

Introduzca una almohadilla (#) en el TextBox Marca personal. Haga click sobre Aceptar.

Le aparecerá en la parte inferior de la pantalla un cuadro para introducir el identificador de esa


página. Repita el proceso para todas las páginas insertándoles una Nota al pié a cada una. Al
final obtendrá este resultado :

INDICE

1 - Introducción a la aplicación
2 - Acceso a la Base de Datos
3 - Introducción de datos
4 - Lectura de datos
- - - - - - - - - - - - - - - - - - - - - salto de página manual - - - - - - - - - - - - - - - - - - - - - - - -
#
Introducción a la Aplicación

Esta aplicación está realizada para . . . . . . . . . .

#
Introducción

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 20


- - - - - - - - - - - - - - - - - - - - - salto de página manual -----------------------
#
Acceso a la Base de Datos

Para abrir la Base de datos . . . . . . . . .

- - - - - - - - - - - - - - - - - - - - - salto de página manual - - - - - - - - - - - - - - - - - - - - - - - -


#
Introducción de datos

Para introducir datos . . . . . . . . . . . .

-------------------- salto de página manual -----------------------


#
Lectura de datos

Para leer los datos . . . . . . . . . . . . . . . .

EN ESTA PARTE DE LA PAGINA VERA UNA SEPARACION QUE PONE, A LA IZQUIERDA


Todas las notas al pie
#
Introducción
#
Acceso
#
Meterdatos
#
Leerdatos

(Observe que estamos simulando la ventana de Word. Donde ve - - salto de página manual - -
entienda que estamos simulando lo que Vd. ve en la ventana real)

En la parte inferior puede ver los identificadores que se han asociado a cada página. ¿Qué
podemos hacer para asociar estos identificadores a las líneas correspondientes del índice ?
Muy sencillo, y es el siguiente paso que debe hacer :

Volvamos a la primera página del documento Word, donde tenemos el índice.

INDICE

1 - Introducción a la aplicación
2 - Acceso a la Base de Datos
3 - Introducción de datos
4 - Lectura de datos

Habrá observado en las aplicaciones Windows que para seleccionar un tema hay que poner el
puntero del ratón sobre la línea deseada, que está en color verde, y en ese momento el puntero
se convierte en una mano. En nuestra aplicación ocurrirá lo mismo. Seleccione todas las líneas
que quiere asociar a cada uno de los identificadores (Una a una o todas a la vez, dependiendo
de como las tenga dispuestas), y vaya al menú Formato | Fuentes . Le aparecerá el cuadro de
diálogo. Vaya al TextBox Subrayado de ese cuadro de diálogo y elija Doble.

#
Acceso
#
Meterdatos
#
Leerdatos

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 21


Al ponerles doble subrayado, le aparecerán en la ayuda de color verde, y el puntero se le
transformará en una mano cuando lo ponga encima de una de esas líneas. Pero todavía queda
asociarlas a cada uno de los identificadores. Para ello tiene que llevar el puntero del ratón
justamente al final de cada una de las líneas. Al hacer click el puntero de escritura se coloca en
ese punto. Tiene que escribir a continuación de cada línea el nombre del identificador que
corresponda. Pero lógicamente no querrá que se vea en la pantalla de ayuda. Por lo tanto debe
hacerlo invisible. Para escribir un texto invisible en Word hay que pulsar las teclas Control +
Mayúsculas + O. Pulse las tres al mismo tiempo y a continuación escriba el nombre del
identificador que corresponda. No verá lo que escribe pues para eso está escribiendo con texto
invisible. Puede visualizarlo mediante el botón

del editor Word. Verá también todos los caracteres de control del documento. Si lo prefiere,
vaya al menú Herramientas | Opciones y sobre la pestaña Ver seleccione Texto oculto.

Proceda de igual forma con todas las líneas del índice. Cuando termine, guarde el documento
en formato RTF y compílelo de la forma explicada mas atrás. Posiblemente ahora le salgan
errores de compilación, pues el compilador comprueba que todos los identificadores se
corresponden en el índice y en las páginas. Si le falta algún pie de página o un salto de carro
manual le dará error. También le dará un error, mejor dicho una observación, indicándole que
hay párrafos ocultos. Es lógico, ha detectado los textos ocultos que contiene el fichero. Ni caso.
Le habrá creado el archivo .HLP y le sugiero que lo pruebe, moviéndolo al directorio
C :\DIRAYUDA y ejecutando la aplicación. Pulse F1 y le saldrá la página con el índice y las
líneas del índice en verde. Si lo ha hecho todo perfectamente, al seleccionar una y otra línea le
aparecerá la página correspondiente.

¡ Ya tenemos una ayuda de varias páginas !

Ventanas Emergentes

Es posible que dentro de la información presentada en cualquiera de las páginas anteriores,


exista una palabra o frase que quisiera explicar con mas detalles. Habrá observado en las
ayudas de Windows que algunas frases dentro de las páginas de ayuda están en verde, y al

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 22


acercar el puntero del ratón a ellas se convierte en una mano. Para poder hacer lo mismo en
nuestra ayuda, volvamos al documento Word.

INDICE

1 - Introducción a la aplicación
2 - Acceso a la Base de Datos
3 - Introducción de datos
4 - Lectura de datos
- - - - - - - - - - - - - - - - - - - - - salto de página manual - - - - - - - - - - - - - - - - - - - - - - - -
#
Introducción a la Aplicación

Esta aplicación está realizada para . . . . . . . . . .

- - - - - - - - - - - - - - - - - - - - - salto de página manual -----------------------


#
Acceso a la Base de Datos

Para abrir la Base de datos . . . . . . . . .

- - - - - - - - - - - - - - - - - - - - - salto de página manual - - - - - - - - - - - - - - - - - - - - - - - -


#
Introducción de datos

Para introducir datos . . . . . . . . . . . .

-------------------- salto de página manual -----------------------


#
Lectura de datos

Para leer los datos . . . . . . . . . . . . . . . .

Observe unas palabras que están subrayadas. Imagínese que esas palabras tienen un
significado que queremos explicar con mayor detalle. Puestos en nuestro caso, queremos
explicar con mas detalle lo que es una aplicación, una Base de Datos, introducir y leer.

Pretendemos que, al hacer click sobre una de estas palabras se abra, dentro de la ventana de
ayuda, otra ventana con la explicación de lo que es esa palabra concreta. Por lo tanto, debemos
introducir esas informaciones a base de introducir nuevas páginas en el documento Word
donde editamos el fichero de ayuda. Añádalas de la misma forma insertándoles un pie de
página y el identificador deseado, de la misma forma que se explicó mas atrás. Recuerde que el
identificador debe ser único.

Una vez terminado de introducir todas las nuevas páginas, vaya a las palabras o frases que
quiere explicar con el texto de esas páginas, selecciónelas y deles el atributo de subrayado
simple (Hágalo de forma similar a cuando hizo lo del subrayado doble, pero esta vez SIMPLE)
Introduzca inmediatamente después de la palabra o frase un texto oculto con el nombre del
identificador seleccionado para la página deseada en esa palabra. Guarde el documento Word
y vuelva a compilar como anteriormente. Ejecute la aplicación y compruebe como vamos
avanzando en el tema de las ayudas de Windows.

Si repasamos las propiedades de los controles, seguro que se acuerda de la propiedad


HelpContextID que tenían la mayoría de los controles VB. En aquel momento decíamos que
esa propiedad que establece un número de contexto asociado para este control. Este número
se aplica para determinar la ayuda interactiva asociada a este control. Ha llegado el momento
de sacarle partido a esa propiedad.

#
Introducción
#
Acceso
#
Meterdatos
#
Leerdatos

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 23


Podemos usar la tecla F1 para acceder al índice de la ayuda de una aplicación y movernos a lo
largo de la ayuda seleccionando una u otra información. A veces resulta práctico seleccionar
directamente la ayuda correspondiente a la función de un control. Para poder hacer esto,
asociaremos una de las páginas del documento Word anterior al número que figura en la
propiedad HelpContextID. Cuando ese control tenga el foco, al pulsar F1 saldrá como página
por defecto la página asociada mediante la propiedad HelpContextID.

Para establecer esta relación vayamos al fichero con extensión .HPJ que servía para introducir
los datos al Help Compiler. En nuestro caso se llamaba FICHAYUD.HPJ y tenía por el
momento, solamente dos líneas.

[FILES]
AYUDA1.RTF

En estas dos líneas le introducíamos el nombre del fichero de ayuda [FILE]. Añadamos ahora
en otro apartado [MAP] la relación entre los identificadores de página y los números de contexto
de la propiedad HelpContextID de cada uno de los controles que la tengan activada (valor
distinto a 0). Se escribirá el nombre del identificador de página, y separado por un espacio o un
tabulador, el número de contexto :

[MAP]
Identificador1 1
Identificador2 2
Identificador3 3
Identificador4 4

En este caso, cuando un control que tiene en su propiedad HelpContextID el número 3 tiene el
foco, al pulsar F1 aparecerá como página por defecto la correspondiente a la explicación con
identificador nombre Identificador3. Lo mismo ocurrirá con el resto de los identificadores.

Añada a su aplicación 4 TextBox y asígneles los valores 1, 2, 3 y 4 a sus propiedades


HelpContextID. Vuelva a compilar la ayuda y ejecute la aplicación. Vaya pasando el foco de uno
a otro TextBox y comprobándolo.

Puede que las ayudas que quiera aportar a cada uno de los controles sea muy breve, caso por
ejemplo de la que puede introducir en los TextBox para indicar al usuario lo que se va a hacer
con el dato concreto que se va a meter en ese TextBox. Y que esas ayudas breves sean muy
numerosas y tal vez cambiantes de un usuario a otro. Esto complicaría su fichero de ayuda
original, al que debería introducir muchas páginas nuevas. Puede editar estas pequeñas ayudas
en otro documento Word, de la misma forma que se ha descrito, y darle un determinado
nombre (AYUDA2.RTF para nuestro ejemplo) y añadirlo como otro fichero en la lista [FILES].
Colóquelo tras el fichero anterior, pues el que lleva el índice debe ser el primero que figure en la
lista. Debe añadir la relación entre los nombres de identificador que haya puesto en ese nuevo
fichero y los números de contexto de cada control.

El fichero FICHAYUD.HPJ queda de momento con la siguiente forma :

[FILES]
AYUDA1.RTF
AYUDA2.RTF

[MAP]
Identificador1 1
Identificador2 2
Identificador3 3
Identificador4 4

Este procedimiento de acudir rápidamente a la ayuda de un determinado control puede que no


sea el ideal, ya que en una aplicación, siempre tiene el foco algún control. Si ese control que
ahora mismo tiene el foco tiene activado el HelpContextID, y el usuario pulsa F1, con la

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 24


intención de ir a ver cualquier cosa no relacionada con el control que tiene actualmente el foco,
se verá sorprendido con que aparece una información que nada tiene que ver con la esperada
(índice). En cualquier caso, siempre podrá ir al índice haciendo click en el botón CONTENIDO
de la ventana de ayuda, pero en principio no está bien que le aparezca en pantalla una
información no esperada. Tiene solución, incluya en el menú (palabra Ayuda) o en un control
Image con el símbolo ? una llamada al programa WINHELP.EXE, pasándole como parámetro
el nombre del fichero de ayuda. Esto lo podemos hacer mediante la función SHELL

SHELL “WINHELP.EXE C:\DIRAYUDA\FICHAYUD.HLP “, 1

(Vea función Shell. No se olvide del 1 final, pues si no lo pone la ayuda le saldrá minimizada.
Puede poner también un 4)

También puede utilizar para este fin el CommonDialog. Introduzca un CommonDialog en su


aplicación y ponga en su propiedad HelpFile el nombre del fichero de ayuda. La propiedad
HelpCommand de este CommonDialog debe estar puesta a 3 para que comience mostrando el
índice de la ayuda. En estas condiciones, en vez de acudir a la función Shell para ejecutar el
WINHELP.EXE, ejecute CommonDialog.ShowHelp. Vea con mas detalles las propiedades
del CommonDialog, pues le permite presentar otras funciones de la ayuda de Windows (Ayuda
de la Ayuda, etc.)

Titulo de la ventana de Ayuda

Habrá observado que la ventana de ayuda tiene, en la barra de título el siguiente texto : Ayuda
de Windows. Si deseamos personalizarlo y poner el nombre de nuestra aplicación, basta con
añadir un par de líneas al fichero FICHAYUD.HPJ. Las correspondientes al apartado
[OPTIONS]. Este apartado debe ir en primer lugar del fichero, y puede llevar la información de
la barra de título y el CopyRight. Estos dos parámetros se introducen de la siguiente forma :

[OPTIONS]
TITLE= Nuestra Aplicación VB - Fichero de Ayuda
COPYRIGHT= Nombre del Autor(a)

[FILES]
AYUDA1.RTF
AYUDA2.RTF

[MAP]
Identificador1 1
Identificador2 2
Identificador3 3
Identificador4 4

El dato introducido en la línea COPYRIGHT sale en el menú de la pantalla de ayuda, en Ayuda


| Versión.

Gráficos en la ventana de Ayuda.

Si necesita introducir un gráfico en la ventana de ayudas puede hacerlo de dos formas :

- Introducirlo en el fichero Word. Esta opción es recomendable si el gráfico es muy pequeño.


- Introducirlo directamente desde un fichero .BMP ó .WMF (Metarchivo). Recomendable
cuando el gráfico es grande. Este método se denomina de referencia a un gráfico.

Para introducirlo por el primer procedimiento, inserte el gráfico en el texto Word y proceda como
siempre.

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 25


Para introducirlo por el segundo método, tiene tres posibilidades : Introducir el gráfico en el
centro de la ventana de ayuda, introducirlo a la izquierda con texto a su derecha o a la derecha
con texto a su izquierda.

Se supone que el gráfico está en un fichero llamado GRAFICO1.BMP en el directorio


C:\DIRAYUDA. Vayamos al documento Word, y en el sitio donde desee introducir el gráfico
inserte la(s) línea(s) :

{bmc c:\dirayuda\grafico1.bmp}Le colocará este gráfico en medio de la ventana de ayuda, y


este texto inmediatamente debajo del gráfico.

{bml c:\dirayuda\grafico1.bmp}Le colocará este gráfico a la izquierda de la ventana de ayuda,


y este texto a la derecha del gráfico.

{bmr c:\dirayuda\grafico1.bmp}Le colocará este gráfico a la derecha de la ventana de ayuda,


y este texto a la izquierda del gráfico.

Se han resaltado en negrita las tres opciones. Recuerde la llaves donde se encierra la posición
y el nombre (y path) del gráfico.

Debe tener cuidado al introducir gráficos, ya que el compilador (HC.EXE) trabaja en DOS, y me
da la impresión de que no utiliza mas que los primeros 640 Ks. de memoria. Con un gráfico de
470 Ks. usado en la preparación de estos apuntes fue incapaz de compilarlo, dando error de
memoria insuficiente. (Y no es que el Ordenador no tenga RAM suficiente)

Historial

La Ayuda de Windows nos permite recordar todas las páginas sobre las que se hizo una
consulta. Esto puede ser muy útil, pues tenemos muy accesible los temas que hemos
consultado, para poder realizar una nueva lectura de los mismos si fuese necesario.

Para obtener la ventana de historial, basta con hacer click en la barra de menú de la ventana de
Ayuda en Opciones | Mostrar Ventana de Historial.

Pero para que se pueda mostrar el historial, es necesario darle un nombre a las páginas, y será
ese nombre el que figure en la ventana de historial. Ese nombre es distinto del identificador de
página, aunque no hay ningún problema porque sea el mismo. Ponga como nombre de la
página una palabra que identifique esa página de una forma única.

Para poner el nombre a la página, vaya al comienzo de cada página e introduzca una nota al pié
de la misma forma que cuando ponía el identificador. En este caso el símbolo a introducir en la
Marca personal es el $. Proceda a introducir el nombre en la parte de abajo de la pantalla de
Word

Palabras Clave

La Ayuda de Windows nos permite accede a una página usando como criterio de búsqueda
ciertas palabras que ponemos como clave. Por ejemplo, si queremos que aparezca nuestra
página de ejemplo que habla de Acceso a la Base de Datos, cuando el usuario busca una de
las siguientes palabras : Tablas, Base, Registro, y a la de Lectura de Datos cuando busque
Obtener, Leer y Visualizar

Volvamos al editor Word, a las dos páginas nombradas y al lado de las notas al pié anteriores,
introduzca otra, esta con la Marca personal K. En la parte inferior de la pantalla, donde pone el
nombre de la nota al pie, ponga introduzca las palabras clave para cada una de ellas,
separadas con una coma. Salve el fichero RTF y vuelva a compilar. Ejecute la aplicación y

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 26


saque la Ayuda. Observará que el botón Búsqueda de la ventana de ayuda está habilitado.
Haga click en este botón y verá que esas palabras ya figuran en la lista.

Usar los Gráficos de la Ayuda como enlaces a páginas

Lo mismo que hacíamos con las palabras, bien las del índice, a las que con un subrayado doble
les introducíamos un enlace a una página, o con cualquier palabra o frase de una página, que
mediante un subrayado simple les introducíamos un enlace a una ventana emergente, lo mismo
podemos hacer con la referencia a un gráfico. (Vea un poco mas arriba, las referencias a los
gráficos del tipo {bmc c:\dirayuda\grafico1.bmp} ) Si seleccionamos esa referencia y le
ponemos el atributo de doble subrayado, al acercar el puntero del ratón a ese gráfico (en la
ayuda) nos mostrará una mano, y haciendo click sobre el gráfico sacará la página
correspondiente. Si le ponemos el atributo de subrayado simple, nos sacará una ventana
emergente. Eso sí, en cualquiera de los dos casos, deberemos poner, a continuación de la
referencia al gráfico, con texto invisible, el indicador de página que especifique la página o
ventana emergente que queremos mostrar.

Páginas en secuencia

Si tenemos una ayuda muy larga y la queremos leer toda, con lo que sabemos deberíamos ir al
índice y desde allí acceder a la página 1, leerla, volver al índice, acceder a la página 2, leerla,
volver al índice ....

Para evitar este proceso, y acceder secuencialmente a cada una de las páginas, podemos
asignar a cada una de las páginas un código de secuencia, que podrá estar formado por
caracteres alfanuméricos. Este código de secuencia será el que marque el orden de aparición
de las páginas. Pero el orden de aparición será según el código ASCII de los caracteres que
formen ese código, comenzando por la izquierda. Por lo tanto puede ocurrirle la paradoja de
que aparezca primero la página 100 que la 65. Es decir, si los códigos están formados por
números aparecerán primero todas las páginas que comiencen por 1, aunque el valor numérico
de una de ellas sea superior a otra que comience por 2, 3, 4, ...

Para asignar este código de secuencia deberemos introducir otra nota al pié para cada página,
en este caso con la marca personal + (signo mas). También deberemos indicarle al WinHelp
que deseamos sacar los botones (<<) y (>>) para desplazarnos por las páginas. Esto se
consigue añadiendo una nueva sección al archivo .HPJ que se denomina [CONFIG] y le
introduciremos en esta sección la expresión BrowseButtons()

El fichero FICHAYUD.HPJ quedará de la siguiente forma :

[OPTIONS]
TITLE= Nuestra Aplicación VB - Fichero de Ayuda
COPYRIGHT= Nombre del Autor(a)

[FILES]
AYUDA1.RTF
AYUDA2.RTF

[MAP]
Identificador1 1
Identificador2 2
Identificador3 3
Identificador4 4

[CONFIG]
BrowseButtons()

Encabezado de páginas

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 27


Habrá observado en la ayuda de Visual basic que una o dos líneas en la parte superior de la
ventana de ayuda se conservan allí continuamente aunque nos desplacemos hacia abajo
mediante los cursores de desplazamiento. Esas líneas son el Encabezado de página. Para
conseguir esto en nuestra ayuda deberemos escribir las líneas que queramos que se conserven
como encabezado de página al principio de cada página, seleccionarlas con el cursor del ratón
y abrir el menú Formato | Párrafo (Se supone que está utilizando el procesador de texto
Microsoft Word) donde le aparecerá un cuadro de diálogo con dos solapas, Sangría y Espacio
y Presentación. Elija Presentación y dentro de esta solapa, active la casilla Conservar con el
Siguiente. Las líneas que hubiera seleccionado se le conservarán como Encabezado de
página.

VENTANAS MULTIPLES

Con frecuencia es útil emplear varias ventanas para mostrar la información de una aplicación.
El ejemplo que tenemos mas a mano es el de la Ayuda de Visual Basic. Cuando tenemos
seleccionada la ayuda de un control, se pueden observar al menos dos palabras que nos llevan
a una segunda ventana : Propiedades y Eventos. Cuando elegimos una de estas informaciones
aparece una segunda ventana que nos muestra la información pedida, sin perder la información
que tenemos en la primera ventana.

Esta segunda ventana se comporta de manera idéntica a la primera, en cuanto a llamadas a


otras páginas o a menús emergentes.

Para poder presentar esta segunda ventana es necesario primero definirla. Para ello volvamos
a nuestro fichero .HPJ y le añadiremos un nuevo apartado : WINDOWS, donde introduciremos
el nombre de la nueva ventana, el título de la misma (El título que aparecerá en su parte
superior), y, entre paréntesis, su posición y dimensiones.

El fichero .HPJ quedará de la siguiente forma, tras introducirle dos nuevas ventanas :

[OPTIONS]
TITLE= Nuestra Aplicación VB - Fichero de Ayuda
COPYRIGHT= Nombre del Autor(a)

[FILES]
AYUDA1.RTF
AYUDA2.RTF

[MAP]

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 28


Identificador1 1
Identificador2 2
Identificador3 3
Identificador4 4

[CONFIG]
BrowseButtons()

[WINDOWS]
Ventana2 = “Titulo de esta Ventana”, (PosiciónX, PosiciónY, DimensiónX, DimensiónY)
Ventana3 = “Titulo de esta Ventana”, (PosiciónX, PosiciónY, DimensiónX, DimensiónY)

Para llevar la información a una de estas ventanas, en vez de a la ventana principal, se añadirá
tras el identificador de la página que queremos enviar a la nueva ventana el símbolo > y a
continuación el nombre de la ventana.

El Objeto App

Introducimos aquí un nuevo objeto Visual Basic. El objeto App es un objeto global al que se
accede con la palabra clave App. (No se líe. El objeto App no es ni mas ni menos que un
conjunto de datos acerca de la aplicación) Determina o especifica información sobre el título
de la aplicación, la ruta de acceso de su archivo ejecutable y los archivos de Ayuda, y si está
ejecutándose una instancia anterior de la aplicación. Este objeto tiene solamente propiedades.
No tiene ni Eventos ni Métodos. Una de sus propiedades es HelpFile, propiedad que es de
lectura y escritura. Es decir, podemos obtener el nombre del fichero de ayuda de una aplicación
consultando el valor de esa propiedad del Objeto App. En el ejemplo siguiente introducimos el
nombre del fichero de ayuda en el Label1

Label1.caption= App.HelpFile

Como la propiedad HelpFile también es de escritura, se puede cambiar en tiempo de ejecución


el fichero de ayuda. Piense lo útil que puede resultar esto para cambiar el idioma de la ayuda de
una aplicación. Para ello basta con imponer el nombre (con su Path) del nuevo fichero de
ayuda :

App.HelpFile = "C:\ ..... \ ..... \ nuevaayuda.hlp"

(Vea un poco mas adelante mas información sobre el Objeto App)

Otros Compiladores de Ayuda (HCP.EXE, HCW.EXE, ...)

En este capítulo hemos citado como compilador del fichero de ayuda al programa HC.EXE que
habitualmente se encuentra en el directorio C :\ . . . . \ VB\HC. Este compilador trabaja
perfectamente con ficheros .RTF creados con las versiones primeras del Word.

Si Ud. realiza los ficheros .RTF con el Word para Windows95 (Word 6.0), no habrá tenido
ningún problema con lo descrito anteriormente. Si tiene Word de office97 (W97) habrá
observado que al compilar la ayuda con el HC.EXE le sale un error. No se preocupe. Es que el
fichero RTF creado por W97 es distinto del creado por W95, lo cual, aparte de dar una idea de
como se trabajan los temas de compatibilidad entre procesadores que deberían ser
compatibles, nos obliga a buscar otro compilador de ayudas.

No lo intente con el HCP.EXE. Tampoco vale. Busque por Internet un fichero llamado
HCW.EXE, compilador que tiene además la ventaja de que trabaja en Windows. Usa el mismo
fichero .HPJ y acepta los ficheros .RTF creados con W95 y W97
El aspecto de este compilador de ayudas es el siguiente :

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 29


Aparte de este compilador, existen otros que funcionan de forma similar. No vamos a explicar
cada uno de los compiladores que podamos encontrar, que como se dijo hay bastantes y (creo
que) shareware. Lo importante es que todo lo dicho respecto a la edición de los ficheros :RTF y
.HPJ sigue siendo válida para estos compiladores. Existen algunos compiladores que también
crean el fichero .HPJ. Es comprensible no intentar examinar uno a uno en esta Guía del
Estudiante.

LSB Visual Basic - Guía del Estudiante Capítulo 10 Página 30


Visual Basic - Guía del Estudiante Cap. 11
BASES DE DATOS EN VISUAL BASIC (1)

A modo de introducción
Todo lo visto hasta ahora en este libro es el Visual Basic elemental que debe conocer
necesariamente para realizar una aplicación. Sin embargo hay algo que falta. El 90 % de las
aplicaciones que va a realizar van a llevar una base de datos. Es lógico. Una aplicación se hace
normalmente para presentar datos, datos que habrá que introducir y mostrar de forma
conveniente. Lo de introducir y mostrar datos son las materias que va a ver en los capítulos
siguientes, pero no olvide lo de mostrarlos de forma conveniente, y es en eso donde tendrá
que aplicar todo lo que lleva aprendido hasta ahora. Se observa con mucha frecuencia que el
alumno tiene una prisa desmesurada por llegar a los temas que tratan las bases de datos,
dejando un poco de lado la interface necesaria para su introducción y presentación, que es lo
que da ergonomía y elegancia a una aplicación. El conocimiento de bases de datos es
necesario. Lo explicado hasta ahora, imprescindible.

Visual Basic nos permite trabajar directamente con distintas bases de datos (ACCESS,
dBaseIII, dBaseIV , dBase 5, Excel3, Excel4, Excel5, Excel7, FoxPro2.x, Foxpro3.0,
LotusWK1, LotusWK3, LotusWk4, Paradox3.x, Paradox4.x y Paradox5.x Esto lo logra
mediante el Motor de Bases de Datos Jet, herramienta de Microsoft para administrar los datos
en bases de datos Access. Tiene un nombre que mas parece de una materia de ingeniería
aeronáutica, pero en realidad no es mas que un conjunto de programas que se cargan en el
disco duro cuando instala Access o Visual Basic. E esta forma de acceder a las bases de datos
se le llama Acceso mediante objetos DAO. Lo de DAO viene de Data Access Objet. Y es la
forma más sencilla y rápida de acceder a una base de datos Access instalada en el propio disco
duro o en un disco de red de área local rápida. (Lo de facilidad de acceso a una base de datos
Access viene implícito en la política de Microsoft de facilitar la compatibilidad entre sus
aplicaciones)

Pero esto se quedaría muy corto si solamente se pudiese conectar con las bases de datos
citadas. No se puede concebir un sistema de desarrollo que no pueda acceder a bases como
Oracle, Informix, SQL Server, etc. Estas bases de datos, aparte de tener su propia interface
para acceso a datos, disponen de una forma de acceso común a todas : ODBC

Lo de ODBC (Open Data Base Conectivity) es un mecanismo de conexión entre bases de


datos abiertas. Lo de abiertas significa que tienen esa interface de acceso común, interface a
través de la cual puede acceder a sus datos cualquier aplicación. Esta interface utiliza el
lenguaje SQL, y es necesario establecer una conexión ODBC en Windows. Lo veremos mas
adelante.

Los objetos DAO pueden acceder también a bases de datos a través de ODBC. Esto podemos
decirlo con la versión DAO 3.5, no podemos decir lo mismo con la 2.5, procedimiento previsto
pero que no funcionaba.

Este pobre funcionamiento de DAO con ODBC llevó a Microsoft a crear otro tipo de acceso a
datos: el RDO (Remote Data Objet), y los objetos de acceso a datos RDO. Esto consiste en
objetos parecidos a los DAO, pero que en vez de atacar directamente a la base de datos como
lo hace DAO, lo hacen a través de una conexión ODBC previamente establecida en Windows.
Así por ejemplo, en un objeto DAO hablamos del nombre de la base de datos, refiriéndonos al
nombre del fichero que contiene los datos (C:\Mis Documentos\MiBase.Mdb), y en RDO nos
referimos al nombre de la conexión ODBC (Connection) refiriéndonos al nombre de una
conexión ODBC ya establecida, que apunta a una base de datos que es donde vamos a leer o
escribir. Este método tiene la gran ventaja de que podemos establecer hoy una conexión con
una base determinada, y si queremos cambiar mañana la base de datos sobre la que vamos a

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 1


trabajar, basta con cambiar esa conexión apuntando hacia otra base de datos. Así no es
necesario realizar ningún cambio a nuestro código

Un error bastante general con los objetos RDO es pensar (seguramente por aquello de Remote
Data Objet) que solamente pueden trabajar con una base de datos que esté en otro ordenador,
al cual estaremos unidos por cualquier forma de conexión. No tiene nada que ver. RDO significa
solamente que accedemos a los datos a través de ODBC, y podemos hacerlo (al igual que con
DAO) a una base que esté en el mismo disco duro que la aplicación, o una que esté en un
servidor unido a través de una Red de Area Local.

Pero RDO no tiene las prestaciones que tiene DAO para trabajar con bases de datos Access.
De hecho, RDO pierde grandes facilidades que aporta DAO para este tipo de bases de datos.
RDO trabaja sobre una conexión ya instalada, que apunta a una base de datos ya creada. Con
RDO no podemos crear esa base de datos. Esto es obvio, con RDO podemos entrar en una
base de datos Oracle, por ejemplo. Nadie puede pretender que Visual Basic cree una base de
datos de esa marca. Sin embargo, con ADO sí podemos crear una base de datos Access.
Piense en la facilidad para distribuir una aplicación que tenga una base de datos Access cuyos
campos puedan tener un tamaño definido por el propio usuario. Bastaría poner una herramienta
en la propia aplicación donde el usuario introdujese los tamaños de los campos tipo texto, para
adaptar la base de datos a sus necesidades. Esto puede hacerlo con DAO puesto que nos
permite crear bases de datos Access, pero no lo podemos hacer mediante RDO.

RDO utiliza una terminología ligeramente distinta de DAO. Por ejemplo, sonde en DAO
ponemos OpenRecordset, en RDO debemos poner OpenResultset. Es una pena que no se
pueda trabajar con la misma terminología y con todas las prestaciones que tiene DAO a través
de ODBC. Esto mismo pensó Microsoft, y esa fue la razón de implementar en los objetos DAO
3.5 la conexión ODBCDirect.

ODBCDirect nos permite trabajar con los mismos objetos DAO pero a través de una conexión
ODBC, que en este caso, funciona. Puede ser un poco más lenta que DAO, pero en esto hay
opiniones para todos. De esta forma es posible seguir utilizando los viejos métodos aprendidos
para DAO (Y lo que es mejor, reutilizar el código ya escrito en anteriores aplicaciones) a través
de una conexión ODBC. Lo veremos mas adelante.

Pero no debemos pensar que aquí se acaban los métodos de acceso a datos. Existe otro mas,
muy reciente denominado ADO. ADO quiere sustituir a DAO y RDO.

En este punto ponía hace dos años que eso lo va a determinar el mercado. Hoy (Nov.2002) se
puede decir que ADO ha sustituido en todas las aplicaciones nuevas a RDO, y ha dejado a
DAO solamente el mercado de las pequeñas aplicaciones domésticas. ADO es una maravilla.
Por eso, la Guía del Estudiante dedica un nuevo capítulo y un amplio ejemplo a ADO. Pero eso
no implica que no haya que ir paso a paso. Y primero hay que aprender DAO. Pero ahora todo
lo que aprenda de DAO le va a servir para ADO, pues en ADO sí coincide el código.
Aprendamos pues DAO, y luego aplicaremos nuestros conocimientos a ADO. La gran ventaja
de ADO es que en aquellas aplicaciones que leen una base situada en un servidor, ocupa
menos la red de área local, ya que trabaja una aplicación Cliente – Servidor.

Adelanto de términos. Aplicaciones Cliente servidor Piense en una base de datos instalada
en una red no muy rápida. Si creamos un acceso a datos (recordset) con DAO, el tráfico de
datos por la red es muy grande, dado que puede darse el caso de tener que ver toda la base de
datos para extraer de ella solamente un dato. Una aplicación Cliente – Servidor lo que hace es
montar un programa en el servidor, al cual le pedimos desde nuestra aplicación el dato
deseado. Ese programa posiblemente tenga que ver toda la base de datos para encontrar el
dato que nos interesa, pero lo hace localmente en el servidor, sin verter todos los datos a la red
de área local. Una vez que lo ha encontrado, nos pasa a través de la red el dato solicitado, con
lo que bajamos el tráfico por la red de forma muy importante. Lo veremos mas adelante pero no
con una gran profundidad. Es un tema que se sale necesariamente de este curso debido a su
extensión. Existen multitud de libros que tratan el tema.

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 2


No se preocupe de los que acaba de leer. Con las explicaciones anteriores parece que esto de
las bases de datos debe ser cosa de gurús informáticos, vedado al resto de los mortales. Nada
mas lejos de la realidad. Y para demostrarlo, en lo que queda de capítulo vamos a trabajar con
bases de datos SIN escribir una sola línea de código. No digo que sea lo mejor, pero puede
hacerse. Esto se logra mediante controles OCX creados por Microsoft, que controlan
directamente a ese conjunto de programas que habíamos dado en llamar Motor de bases de
Datos Jet o a los programas similares de RDO o ADO.

Comenzaremos el estudio de bases de datos con los objetos DAO. Y para DAO el control que
organiza el trabajo al Motor Jet es el Control Data. Existen controles similares para RDO y
para ADO. Pero no corramos y centrémonos sobre DAO y nuestro motor Jet

DAO - Acceso a bases de datos mediante el Control Data


Para acceder a estas Bases de Datos basta con introducir un control Data en el formulario, y
fijarle las propiedades apropiadas para que trabaje sobre uno u otro tipo de base de datos. El
control Data nos permite acceder de una forma sencilla a cualquier base de datos de estos
tipos, y sirve de enlace entre la base de datos y los controles que son habilitados para presentar
los datos de esa base. Utiliza el motor de bases de datos Jet para el acceso a los datos.

El Control Data

El control Data puede tomarse directamente de la caja de herramientas. Al contrario que los
controles similares RDO y ADO, este está siempre en la caja de herramientas. En el formulario
tiene el aspecto de una barra deslizante :

Decíamos que el control Data sirve de enlace entre la base de datos y los controles que pueden
presentar datos. Estos controles a los que nos referimos son los llamados Controles
Enlazados a Datos, y que son viejos conocidos nuestros, al menos algunos de ellos.

Los dos más sencillos son el control Label y el control TextBox

Un control Label puede presentar un dato. Si queremos que ese dato sea un campo de una
tabla de una base de datos, basta que enlacemos la base de datos al control data, y que
enlacemos luego el control Label con el control Data. Si hacemos lo mismo con el TextBox, no
solamente podremos presentar datos de la BD, sino que los podemos introducir, al ser el
TextBox un control bidireccional.

Veamos como se enlaza un control data a una base de datos. Se supone que el alumno conoce
la estructura de una base Access, BD con la que vamos a iniciar este estudio. De cualquier
forma, y para los que han suspendido la asignatura de base de datos Access, citar solamente
que una base de datos Access contiene dentro de un fichero (P.e. C:\MiCarpeta\MiBase.Mdb)
varias Tablas (P.e. Tabla1, Tabla2 y Tabla3) Cada tabla es en sí una base de datos en el
sentido estricto. Tiene un número indeterminado de registros, (filas) que guardan la información
en varios Campos.

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 3


El fichero, que tiene por extensión Mdb es la base de datos, y ese nombre (Dirección completa
de la carpeta y nombre del fichero) es lo que debemos poner al control Data en su propiedad
DataBaseName. Con esto, el control data ya sabe donde tiene que ir a leer los datos. Pero le
falta todavía por saber en que tabla dentro de esa BD los tiene que leer. El nombre de la tabla
se lo indicamos al control Data en la propiedad RecordSource. Para elegir esta propiedad
basta con desplegar la lista de las tablas haciendo click en la flecha de la línea de la propiedad
RecordSource. Dado que el control Data ya sabe en que base de datos debe leer los datos (Ya
tiene puesta la propiedad DataBaseName), ya puede saber cuantas tablas tiene y los nombres
de estas tablas. Elija la tabla deseada. En nuestro ejemplo, Authors

Con esto ya podría trabajar, pero le faltan aún ciertos detalles. Por ejemplo, el tipo de recordset
que debe crear. (Dynaset, Snapshot, Table) Esto se lo indicamos en la propiedad
RecordsetType, que por defecto le va a poner Dynaset. (Ya veremos que es cada uno de ellos)
Y ya tenemos casi todas las propiedades del control Data cubiertas. Las demás son las típicas
de todos los controles. Casi todas las propiedades, porque hay una que se ha introducido en la
versión 6 de VB para permitir las dos formas de atacar a la base de datos, con el motor Jet o a
través del citado ODBCDirect.. Esa propiedad es DefaultType y nos permite elegir entre usar
el motor de base de datos Jet (Poniendo a esta propiedad el valor 2 o dbUseJet) o usar
ODBCDirect (Poniéndole el valor 1 ó dbUseODBC) El valor por defecto es usar el motor Jet y
así trabajaremos en principio.

Ya tenemos enlazado el control Data a la base de datos. Falta ahora enlazar una etiqueta y un
TextBox al control Data para tener el enlace completo. Eso es aún más sencillo. Si
desplegamos las propiedades del TextBox por ejemplo, veremos que tiene unas propiedades
que cuando lo estudiamos, las habíamos pasado un poco por alto: DataSource y DataField.

En la figura puede ver que la propiedad DataSource puede desplegarse, mostrando en este
caso el nombre del único control Data que tenemos en el formulario: Data1 Si tuviésemos mas
controles Data, aparecerían los nombres de todos ellos. Se elige uno.

A continuación debemos señalarle qué campo queremos que nos presente. Podemos
desplegar la lista, donde podemos ver los campos de la tabla elegida para la propiedad
RecordSource del control Data. Elegimos uno y ejecutamos la aplicación.

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 4


Podemos observar que ya funciona. Si ponemos tantos TextBox como campos tiene la tabla
elegida, podemos ver todo el contenido de la Base de datos moviéndonos a lo largo de ella
mediante las flechas de cursor del control Data. Todo ello sin escribir una línea de código tal y
como habíamos prometido.

Entremos ahora en un estudio un poco más avanzado del control Data.

El control Data proporciona acceso a datos almacenados en bases de datos usando uno de los
tres tipos de objetos Recordset. El control Data le permite ir de registro en registro y presentar
y manipular los datos de los en controles enlazados. Sin un control Data, los controles
enlazados con datos de un formulario no pueden tener acceso automáticamente a los datos.
Los controles enlazados solamente pueden tener acceso a un control Data si este está en el
mismo Formulario.

En el tema de Bases de Datos se emplean términos no conocidos aún. Se irán viendo a lo largo
del curso, pero no queda otro remedio mas que comenzar a utilizarlos. Se irán haciendo
avances de estos términos, que serán explicados en profundidad en su momento.

Avance de términos.
Objeto Recordset (conjunto de registros)
Es un conjunto lógico de registros. Los tres tipos de objetos Recordset son Dynaset, (Permite la
lectura y escritura de un registro) Snapshot (Realiza una lectura instantánea de los registros,
no permitiendo modificarlos) y Table. (Representación en el código de una tabla base que
puede utilizarse para agregar, modificar o eliminar registros de una sola tabla).
Controles enlazados
Son los controles que pueden presentar directamente datos de uno o varios campos de una
Base de Datos. Los controles DBList, DBCombo y DBGrid tienen la posibilidad de presentar un
conjunto de registros cuando se asocian con un control Data. Los controles CheckBox, TextBox,
Label, Picture, Image, ListBox y ComboBox también son controles enlazados con datos y
pueden asociarse a un único campo de un Recordset administrado por un control Data.

La mayoría de las operaciones de acceso a datos se pueden realizar usando el control Data sin
escribir ningún código. Los controles enlazados con un control Data presentan de forma
automática los datos de uno o más campos del registro actual o, en algunos casos, de un
conjunto de registros a ambos lados del registro actual. El control Data realiza todas las
operaciones sobre el registro actual.

Avance de términos
Registro Actual. Un registro es un conjunto completo de campos. Una base puede tener
muchos registros, pero el “puntero” de la base de datos apunta a un único registro en cada
momento. Ese registro al que apunta el puntero se llama registro actual.

Si el control Data recibe instrucciones de moverse a un registro diferente, todos los controles
enlazados pasan automáticamente los cambios al control Data para ser guardados en la base
de datos. El control Data se sitúa después en el registro requerido y pasa los datos del registro
actual a los controles enlazados donde son presentados. Esto significa que se pueden modificar
los datos de una base de datos simplemente cambiando los datos en los controles enlazados
que lo permitan, y moviendo el puntero de la base de datos, es decir, cambiando el registro
actual.

Una vez iniciada la aplicación, Visual Basic usa las propiedades del control Data para abrir la
base de datos seleccionada, abrir un objeto Database y crear un objeto Recordset. Las
propiedades Database y Recordset del control Data hacen referencia a los objetos Database y
Recordset recién creados que pueden ser manipulados por el control Data. Siempre podremos
conocer el Recordset usado por el control Data leyendo esa propiedad

VariableTipoRecordset =Data1.Recordset

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 5


Y si tenemos otro control Data en la aplicación (Puede estar en otro formulario) siempre
podemos hacer que el recordset de este segundo control Data sea igual al del primero

Set Data2.Recordset = VariableTipoRecordset

(Obviamente el ámbito de VariableTipoRecordset debe permitir que se vea en los formularios


donde está Data1 y Data2

Cuando se usa un control Data para crear un objeto Recordset o cuando se crea un objeto
Recordset en el código y se asigna al control Data, el motor de base de datos Jet de Microsoft
puebla automáticamente el objeto Recordset. Como resultado, los marcadores (y en los objetos
Recordset de tipo snapshot, los datos del conjunto de registros) se guardan en la memoria
local; el usuario no necesita manipular el control Data y no es necesario invocar el método
MoveLast en el código para conocer el número total de registros. Los bloqueos de página
usados para crear el Recordset se liberan más rápidamente, haciendo posible que otros objetos
Recordset accedan a los mismos datos. Los objetos Recordset creados en el código pero que
no se asignan a un control Data no son poblados automáticamente por el motor Jet. Se deben
poblar desde el código.

El párrafo anterior, tomado casi literalmente de la información de Microsoft, exige al menos una
explicación.
Cuando se crea un Recordset mediante un control Data, se leen inmediatamente todos los
registros que forman parte de ese Recordset (Recuerde que un Recordset es un conjunto de
registros). De esta forma, en una base que estuviera compartida por varios usuarios a través de
una Red de Area Local (RAL) un usuario leería todos los datos en el mismo momento de la
creación del Recordset por el control Data, llevaría esos datos a su memoria RAM y no volvería
a estorbar en la base de datos (cuando un usuario de una RAL lee un dato en una BD, bloquea
esta BD mientras dura su lectura y no pueden acceder a ella otros usuarios) Si el Recordset se
crea por código, se lee solamente un registro (la base se bloquea en el momento de la lectura e
inmediatamente se libera), y cuando se le pide otra operación (p.e. que avance un registro)
vuelve a bloquear la BD, lee ese registro y la desbloquea. En principio el leer el Recordset de
una vez parece que tiene ventajas en aquellas instalaciones que tienen una base de datos
compartida. Todo ello a un precio. Ocupar mas memoria RAM en cada uno de los PCs de los
usuarios. Esta limitación hace en algún caso que no sea posible utilizar un control Data por falta
de memoria RAM en los puestos de usuario.

El control Data puede manipularse con el mouse, moviéndose de registro en registro o al


principio o al final del Recordset. El control Data no permite que el usuario se pase de los
límites del Recordset usando el mouse. No se puede mover el enfoque al control Data.

Observación muy importante

El control Data crea un objeto Database y un objeto Recordset automáticamente. Estos objetos
de acceso a datos son idénticos a los creados mediante código, y tienen las mismas
propiedades y métodos. Podemos referirnos a ellos usando el nombre del control Data seguido
del nombre del objeto (Database o Recordset). Por ejemplo :

Data1.Database Data1.Recordset

El objeto Database creado por un control Data no se cierra aunque se cambie la propiedad
DatabaseName del control Data. Lo mismo ocurre con el objeto Recordset. Solamente
podemos cerrarlos utilizando el método Close :

Data1.Database.Close Data1.Recordset.Close

Esta observación debe ser tenida muy en cuenta sobre todo cuando el control Data abre la

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 6


Base de Datos de forma exclusiva, o cuando tenemos que hacer una operación con la Base de
Datos que exija que esté cerrada. Por ejemplo, el método CompactDatabase y otros métodos
que veremos mas adelante.

Objetos para acceso a datos

Los objetos para acceso a datos Database y Recordset creados por el control Data tienen
cada uno sus propiedades y métodos propios y se pueden escribir procedimientos que usen
estas propiedades y métodos para manipular los datos.
Por ejemplo, el método MoveNext de un objeto Recordset mueve el registro actual al siguiente
registro del Recordset. Para invocar este método, se podría usar el siguiente código:

Data1.Recordset.MoveNext

El control Data puede crear cualquiera de los tres tipos de objetos Recordset (Dynaset,
Snapshot, Table) Si no se indica el tipo a crear, se crea un Recordset de tipo Dynaset.

Nota. Las constantes usadas para requerir un tipo específico de Recordset cuando se usa un
control Data son diferentes de las constantes usadas para determinar el tipo de Recordset
creado o que se va crear usando el método OpenRecordset.

Para seleccionar un tipo específico de Recordset, establezca la propiedad RecordsetType del


control Data a:

Tipo de Recordset Valor Constante control Data Constante OpenRecordset

Table 0 vbRSTypeTable dbOpenTable


Dynaset 1 vbRSTypeDynaset dbOpenDynaset
Snapshot 2 vbRSTypeSnapshot dbOpenSnapshot

Diferencias entre la Edición Standard y la Edición Profesional de Visual Basic


En cuanto al acceso a datos, la diferencia principal entre las ediciones Estándar y la Profesional
de Visual Basic es la capacidad de crear nuevos objetos para acceso a datos. En la edición
Estándar NO se pueden declarar en el código (con la palabra clave Dim) variables como
objetos para acceso a datos. Esto quiere decir que sólo el control Data puede crear objetos
Database y Recordset.
En la edición Profesional y Empresarial de Visual Basic, SI se puede crear un nuevo objeto
Recordset y asignarlo a la propiedad Recordset del control Data.
¡Esta diferencia ha llevado a la locura a muchos alumnos y programadores usando la versión de
su casa y la de su empresa o centro escolar !

En la pequeña aplicación realizada al comienzo de este tema ha visto que los controles
enlazados a datos permiten visualizar e introducir datos en la base de datos a través del control
Data. Efectivamente, no tendría sentido poner un control data sin enlazarlo a otros controles
para que estos nos sirvan de elementos de presentación y captura de datos. Veremos mas
adelante en este capítulo los controles enlazados a datos.

Consultas almacenadas

Otra opción importante cuando se usa el control Data es la posibilidad de presentar una
consulta realizada previamente en Access. Si se ha creado previamente una consulta, el control
Data nos mostrará esa consulta como si se tratase de una tabla más de la base de datos, al
desplegar la lista de tablas para cubrir la propiedad RecordSource. Puede por lo tanto presentar
solamente los campos que necesite en su aplicación, tomados de una tabla (o de varias tablas
si ha establecido las relaciones oportunas) y de esta forma su aplicación va a trabajar más
rápido que si tuviese que seleccionar esos campos mediante una instrucción SQL Para

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 7


presentar una consulta, establezca la propiedad RecordSource del control Data al nombre de
esa consulta (En vez de poner el nombre de una tabla, ponga el nombre de la consulta). Esto
no puede hacerse si la consulta contiene parámetros. Esto le ocurre cuando la consulta se ha
creado partiendo de los datos de otra consulta.

Es mucho más rápida una consulta utilizando una consulta ya creada en Access que
introduciendo la consulta en SQL. La razón es muy sencilla. Al crear una consulta es Access
quien crea una especie de “tabla nueva” en la propia base de datos. Esta tabla nueva no
contiene datos, sino referencias a registros de una tabla. Por lo tanto, el motor de bases de
datos se limita a recorrer esa “tabla nueva”, tomar el número del registro que debe presentar, ir
a ese registro y tomar el dato que contiene. Si lo que hace es una consulta SQL, se debe
obtener la información registro a registro según las condiciones establecidas en la cláusula
SQL. Esta segunda opción tarda logicamente más. Y si está leyendo la base de datos a través
de una red de área local, la ocupación de esta red es mucho menor si el recordset se crea con
la consulta de Access.

Estamos hablando de una consulta SQL establecida en el control Data. ¿Dónde? Justamente
en la propiedad RecordSource del control data. Hasta ahora habíamos puesto en esa propiedad
el nombre de una tabla o de una consulta ya hecha en Access. Si en vez del nombre de la tabla
ponemos una consulta SQL, la cosa también funciona:
Con una Tabla

Data1.RecordSource = “Autores”

Con una consulta SQL

Data1.RecordSource = “Select * From Autores Where Apellidos = ‘Cervantes Saavedra’”

Esta consulta obtiene de la tabla Autores, solamente los registros en los que el campo Apellidos
sea igual a “Cervantes Saavedra” Funciona, pero para averiguar el número de registros que
tienen esos apellidos deberá recorrerlos todos, comprobar si son iguales a los expresados en la
sentencia SQL y en caso afirmativo pasarlos al recordset creado. Si se hubiera creado una
consulta previamente en Access, y pusiésemos el nombre de la consulta en la propiedad
RecordSource del control Data, éste iría directamente a los registros que gozan de tan ilustres
apellidos, ya que Access habría hecho una tabla con los números de los registros que cumplen
esa condición (esa tabla no contiene los datos, sino el número de los registros que los
contienen), el control data leería esos números e iría a los registros indicados en esos números,
evitando de esta forma tener que leer el contenido del campo Apellidos del resto de los
registros. De cualquier forma, si la base de datos está en el mismo ordenador que la
aplicación, esto empieza a ser importante cuando trate tablas con muchos registros. Si está en
una red de área local no hace falta tener muchos registros para comprobar que se ralentiza la
aplicación.

Propiedades del control Data

Align El control Data puede programarse para que se ajuste automáticamente a la parte
superior o inferior de su formulario primario usando la propiedad Align. En cualquier caso, el
control Data ajusta su tamaño horizontal al de su formulario primario cuando el tamaño de éste
cambia. Esta propiedad permite situar un control Data en un formulario MDI sin requerir un
control Picture que lo contenga.

Appearance Flat y 3-D

Backcolor Color de fondo de la parte intermedia del control

Administración de BOF/EOF

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 8


Las propiedades BOFAction y EOFAction establecen el comportamiento del control Data
cuando llega al principio o final de los registros. En esos casos se produce el BOF y EOF
respectivamente.

BOF (Begin Of File). Se produce el BOF cuando el control Data se posiciona sobre el registro
inmediatamente anterior al primero (No es un juego de palabras). Este registro será el -1.
EOF (End Of File) Se produce la condición EOF cuando el control Data se posiciona en el
registro inmediatamente posterior al último. Este registro será también el -1.

La propiedad BOFAction permite seleccionar el comportamiento del Data cuando nos hemos
pasado de registros por abajo. Tiene las opciones MoveFirst (se mueve al primer registro) o
BOF (se queda donde está)

La propiedad EOFAction establece el comportamiento del control Data cuando se sobrepasa


el último registro. Podemos indicarle que se mueva al último registro (MoveLast), que se quede
donde está (EOF), o que introduzca un nuevo registro (AddNew)

Caption El nombre que figurará en la parte intermedia del control.

Connect Muy Importante. En esta propiedad debemos indicarle al control Data el tipo de base
de datos a la que va a conectarse. Admite todas las bases enumeradas al principio de este
capítulo.

DatabaseName En esta propiedad se le indica el nombre (Con su Path) de la base de datos a


la que debe conectarse. Para facilitar la búsqueda de la base de datos, haciendo click en esta
propiedad en la caja de propiedades, podemos sacar un cuadro de diálogo haciendo click de
nuevo en los tres puntos que aparecen a la derecha de la propiedad. El cuadro de diálogo
seleccionará directamente las extensiones de los ficheros de bases de datos acordes con el
tipo de base de datos seleccionada en la propiedad Connect.

Database (Solo en ejecución)

Esta propiedad es sólo de lectura. Devuelve una referencia a un objeto Database subyacente
de un control Data.

Sintaxis Variable = nombredelcontroldata.Database

El objeto Database creado por el control Data se basa en las propiedades DatabaseName,
Exclusive, ReadOnly y Connect del control.
Los objetos Database tienen propiedades y métodos que puede utilizar para administrar los
datos. Puede utilizar cualquier método de un objeto Database con la propiedad Database de un
control Data, como Close y Execute. También puede examinar la estructura interna de la
Database empleando su colección TableDefs y, a su vez, las colecciones Fields e Indexes de
objetos TableDef individuales.

NOTA. Aunque puede crear un objeto Recordset y pasarlo a la propiedad Recordset de


un control Data, no puede abrir una base de datos y pasar el objeto Database recién
creado a la propiedad Database del control Data.

DragIcon, DragMode , Enabled Igual que todos los controles.

DefaultType

Devuelve o establece un valor que indica el tipo del origen de datos (Motor Jet u ODBCDirect)
que se usan en el control Data.

Sintaxis NombreDelControlData.DefaultType = 1

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 9


Puede tomar los valores 1 (Usa ODBCDirect) y 2 (Usa el Motor Jet) Pueden usarse también las
constantes dbUseODBC o dbUseJet respectivamente

EditMode
Solo lectura en tiempo de ejecución. Devuelve un valor que indica el estado de modificación del
registro actual.

Sintaxis Variable = NombreDelControlData.EditMode

Variable tomará uno de los siguientes valores :

dbEditNone No se está realizando ninguna operación de modificación.


dbEditInProgress Se ha invocado el método Edit y el registro actual se encuentra en el
búfer de copia.
dbEditAdd Se ha invocado el método AddNew y el registro actual del búfer de
copia es un registro nuevo que aún no se ha guardado en la base de
datos.
La propiedad EditMode es especialmente útil cuando se desea partir de la funcionalidad
predeterminada de un control Data, o cuando no se utiliza un control Data en Visual Basic
Edición profesional. Puede comprobar el valor de la propiedad EditMode y el del parámetro
acción del procedimiento del evento Validate para determinar si se debe invocar el método
Update.
También puede comprobar si el valor de la propiedad LockEdits es True y el de EditMode es
dbEditInProgress para determinar si la página de datos actual se encuentra bloqueada.

Exclusive Devuelve o establece un valor (True / False) que indica si la base de datos está
abierta para acceso de un único usuario o de múltiples usuarios.

Font, ForeColor, Height, Index, Left, MouseIcon, MousePointer, Name, igual que el resto de
los controles.

Negotiate Propiedad característica de los controles que tienen la propiedad Align. Establece un
valor que determina si se muestra un control que puede alinearse cuando un objeto activo del
formulario muestra una o más barras de herramientas. No está disponible en tiempo de
ejecución.

Options Devuelve o establece un valor que especifica una o más características del objeto
Recordset de la propiedad Recordset del control Data. Puede ponerse en el cuadro de
propiedades o en tiempo de ejecución. Puede tomar los siguientes valores o nombres de
constantes (estos nombres solo si los introduce en tiempo de ejecución)

1 dbDenyWrite En un entorno multiusuario, otros usuarios no pueden realizar


cambios en registros del Recordset.
2 dbDenyRead En un entorno multiusuario, otros usuarios no pueden leer
registros (sólo Recordset de tipo tabla).
4 dbReadOnly No se pueden realizar cambios en registros del Recordset.
8 dbAppendOnly Puede agregar nuevos registros al Recordset, pero no puede
leer los registros existentes.
16 dbInconsistent Las actualizaciones pueden aplicarse a todos los campos del
Recordset, aunque infrinjan la condición de unión.
32 dbConsistent (Predeterminado) Las actualizaciones sólo se aplican a los
campos que no infringen la condición de unión.

64 dbSQLPassThrough Cuando se utilizan controles Data con una instrucción SQL en


la propiedad RecordSource, envía la instrucción SQL a una
base de datos ODBC, como SQL Server o Oracle, para su
procesamiento.

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 10


256 dbForwardOnly El Recordset es un desplazamiento sólo hacia adelante. El
único método de movimiento permitido es MoveNext. Esta
opción no puede utilizarse en objetos Recordset manipulados
con el control Data.
512 dbSeeChanges Genera un error interceptable si otro usuario está cambiando
datos que usted edita.

Para establecer mas de un valor de los descritos, basta con sumar sus valores. También
puede establecer más de un valor para esta propiedad, combinando opciones sumando valores
entre sí. Por ejemplo, para establecer dbReadOnly y dbInconsistent puede utilizar este
código:

Data1.Options = dbAppendOnly + dbInconsistent

Para determinar si la propiedad contiene un valor específico, puede utilizar el operador And. Por
ejemplo, para averiguar si el Recordset está abierto para acceso de sólo lectura, podría usar
este código:

If Data1.Options And dbReadOnly Then...

Si cambia la propiedad Options en tiempo de ejecución, deberá utilizar el método Refresh para
que el cambio sea efectivo.

ReadOnly Devuelve o establece un valor que determina si la Database del control está abierta
para acceso de sólo lectura.

RecordsetType

Devuelve o establece un valor que indica el tipo de objeto Recordset que desea que cree el
control Data.

Los valores o nombre de la constante que puede adoptar son los siguientes:

0 vbRSTypeTable Un Recordset de tipo tabla.


1 vbRSTypeDynaset (Predeterminado) Un Recordset de tipo hoja de respuestas
dinámica.
2 vbRSTypeSnapshot Un Recordset de tipo instantánea.

Si no especifica un RecordsetType antes de que el control Data cree el Recordset, se creará


un Recordset de tipo hoja de respuestas dinámica. (Dynaset)

Recordset

Devuelve o establece un objeto Recordset definido por las propiedades de un control Data o por
un objeto Recordset existente.

Veremos mas adelante las propiedades de un objeto Recordset, propiedades que son en todo
aplicables al Recordset del control Data.

El Recordset es como se adelantó, un conjunto de registros. Si las propiedades Connect,


DatabaseName, Options, RecordSource, Exclusive, ReadOnly y RecordsetType establecidas
para el control Data son válidas, se crea un Recordset automáticamente basándose en dichas
propiedades. Ese será el Recordset del control Data. Pero también puede crearse previamente
un Recordset mediante la instrucción OpenRecordset y forzar que el Recordset del control Data
sea justamente ese mediante la instrucción Set Data1.Recordset = MiRecordset

Sea cual fuera la forma de crearlo, a partir del momento en que el Data tenga su Recordset

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 11


podemos referirnos a él, por ejemplo para ir al primer registro (Data1.Recordset.MoveFirst),
avanzar un registro (Data1.Recordset.MoveNext), al anterior (Data1.Recordset.MovePrevious)
ir al último (Data1.Recordset.MoveLast), añadir un registro (Data1.Recordset.AddNew), guardar
los cambios en la Base de Datos (Data1.Recordset.Update), o borrar el registro actual
(Data1.Recordset.Delete)

Si se cambia alguna de las propiedades citadas al principio que cambien el Recordset, es


necesario volver a crearlo. Para ello basta con utilizar el Método Refresh. (Data1.Refresh)

RecordSource

Devuelve o establece la tabla, el objeto QueryDef (Consulta) o la instrucción SQL subyacente


para un control Data. Esta propiedad puede fijarse en el cuadro de propiedades del control data,
(el caso mas usado) o introducirse como código. En los dos primeros casos, lo normal es
introducir el nombre de una tabla o una consulta de las existentes en la base de datos
especificada en la propiedad DatabaseName, nombres que se pueden elegir desplegando la
lista que se obtiene haciendo click sobre la flecha que aparece al lado de la casilla de esta
propiedad. Observe que en la lista desplegada figuran los nombres de las tablas y de las
consultas que tiene la Base de Datos elegida en la propiedad DatabaseName. Ni que decir tiene
que para poder introducirla de esta forma es necesario fijar previamente la propiedad
DatabaseName.

Puede introducirse en tiempo de ejecución mediante código con la siguiente expresión :

NombreDelControlData.RecordSource = “NombredelaTabla

Donde NombredelaTabla es una expresión de cadena que especifica el nombre de una Tabla o
una Consulta, de las que componen la base de datos especificada en la propiedad
DatabaseName, o una consulta SQL válida que utiliza sintaxis apropiada para la base de datos
especificada en la propiedad DataBaseName. La propiedad RecordSource especifica el origen
de los recursos accesibles a través de controles enlazados del formulario. Si establece la
propiedad RecordSource como el nombre de una tabla existente en la base de datos, todos los
campos de esa tabla serán visibles a los controles enlazados adjuntos a este control Data. El
orden de los registros recuperados lo establece el objeto Index que selecciona mediante la
propiedad Index del Recordset. Si no establece la propiedad Index, los datos se devolverán sin
ningún orden concreto.

Si establece la propiedad RecordSource como el nombre de una consulta existente en la base


de datos, todos los campos devueltos por la consulta serán visibles a los controles enlazados
adjuntos al control Data. El orden de los registros recuperados lo establece la consulta Si en la
consulta no se ha especificado un orden, los datos se devolverán sin ningún orden concreto.

Si establece la propiedad RecordSource como una instrucción SQL que devuelve registros,
todos los campos devueltos por la consulta a SQL serán visibles a los controles enlazados
adjuntos al control Data. Esta instrucción puede incluir una cláusula ORDER BY para cambiar el
orden de los registros devueltos por el Recordset creado por el control Data o una cláusula
WHERE para filtrar los registros.

Después de cambiar el valor de la propiedad RecordSource en tiempo de ejecución, deberá


utilizar el método Refresh para activar el cambio.

Nota. Asegúrese de que cada control enlazado tiene un valor válido para su propiedad
DataField. Si cambia el valor de la propiedad RecordSource de un control Data y, a
continuación, utiliza Refresh, el Recordset identificará el nuevo objeto. Esto puede invalidar los
valores de DataField de controles enlazados y producir un error interceptable.

Las Propiedades Tag, Top, Visible, WhatThisHelpID, Width, igual que el resto de los

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 12


controles.

METODOS DEL CONTROL DATA

(Se explican aquí los métodos que inciden directamente en el tratamiento de bases de datos.
No se comentan los métodos Drag, Move y ZOrder que son idénticos a los del resto de
controles)

Método Refresh

De momento es aplicable al control Data. Veremos que también es aplicable a otros objetos de
acceso a datos (QueryDef). El método Refresh no puede utilizarse con colecciones que no
sean persistentes, como Databases, Recordsets o Workspaces.

Actualiza los datos del recordset del control data. Imagínese que el control data accede a una
base de datos compartida. Mediante este método actualizamos el contenido del recordset del
Data y por lo tanto los datos presentados a través de los controles enlazados. El método
Refresh también se utiliza para cerrar y volver a generar el objeto Recordset o las estructuras
de datos creadas por un control Data.

Sintaxis NombredelcontrolData.Refresh

Puede utilizar el método Refresh sobre un control Data para abrir o reabrir la base de datos (si
han variado las propiedades DatabaseName, ReadOnly, Exclusive o Connect) y volver a
generar el objeto Recordset indicado por la propiedad Recordset del control.

Método UpdateControls

Actualiza los datos presentes en los controles enlazados a datos vinculados al control Data.

Sintaxis Nombredelcontroldata.UpdateControls

Utilice este método para restablecer en los controles enlazados sus valores originales, por
ejemplo cuando un usuario modifica los datos y luego decide cancelar los cambios.
Este método produce el mismo efecto que hacer actual de nuevo al registro actual, excepto en
que no se produce ningún evento ni introduce en la Base de Datos los posibles valores que se
hubiesen cambiado en los controles enlazados.

Método UpdateRecord

Guarda en la base de datos los valores actuales de los controles enlazados.

Sintaxis NombredelcontrolData.UpdateRecord

Puede utilizar este método para guardar el contenido actual de los controles enlazados en la
base de datos. Los cambios introducidos en los controles enlazados a datos se pasan a la
base de datos al cambiar el registro actual, bien mediante código (Data1.Recordset.MoveNext,
p.e.) o usando las flechas del control data, o cambiando el registro actual en un DBGrid. Sin
embargo hay circunstancias en las que no es apropiado hacer esto. Mediante el método
UpdateRecord introducimos los cambios en la BD. Este método no desencadena el evento
Validate.

En algunos casos, la actualización puede no tener lugar, debido a que la operación vulnere las
restricciones de integridad referencial, o que la página que contiene el registro esté bloqueada,
o que la base de datos u objeto Recordset no sean actualizables, o a que el usuario no cuente
con el permiso adecuado para la operación. En cualquiera de estas circunstancias, se producirá
un error interceptable.

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 13


Estos son los métodos del Control Data. Este control tiene su Recordset, y el Recordset
del control Data tiene sus métodos, idénticos a los de un Recordset creado por código.

EVENTOS DEL CONTROL DATA

Error

Se produce solamente como resultado de un error de acceso a datos que tiene lugar cuando no
está ejecutando código Visual Basic. Lo explicamos.

El control data carga los datos durante la carga del formulario que lo contiene, abriendo la base
indicada en su propiedad DataBaseName. Imagínese que no existe esa base de datos en el
disco. En ese caso no se producirá ningún interceptable ya que no se ejecuta ningún código
escrito. Tampoco se ejecuta ningún código escrito cuando el usuario hace click en uno de los
botones del control data.

El procedimiento Error del control Data se ejecuta cada vez que ocurre un error por una
maniobra de este tipo, y pasa el código de error como parámetro. Analizando el código de error
podemos escribir código en este procedimiento para paliar el error. La ayuda de VB tiene un
buen ejemplo del uso de este procedimiento.

Este ejemplo presenta un cuadro de diálogo Abrir si no se ha podido encontrar la base de datos
especificada en la propiedad DataBaseName del control Data después de haber terminado el
evento Form_Load.

Private Sub Data1_Error (DataError As Integer, Response As Integer)


Select Case DataError
'Si no se ha encontrado el archivo de base de datos se produce el error 3024
Case 3024
'Presentar un cuadro de diálogo Abrir.
CommonDialog1.ShowOpen
End Select
End Sub

Reposition

Se produce después de que un registro se convierte en el registro actual.

Private Sub Objeto_Reposition()

Donde objeto = Nombre del control Data


Cuando se carga un control Data, El primer registro de su objeto Recordset se convierte en el
registro actual, provocando el evento Reposition. Cuando un usuario haga clic en uno de los
botones del control Data, moviéndose de registro en registro o si se usa uno de los métodos
Move del objeto Recordset asociado al control data, como MoveNext, MoveFirst, MovePrevious,
los métodos Find, como FindFirst, FindNext, o cualquier otra propiedad o método que cambie
el registro el actual, se produce el evento Reposition después de que cada registro se
convierta en el actual.

Este evento se puede usar para realizar cálculos basándose en los datos del registro actual o
para cambiar el formulario en respuesta a los datos del registro actual.

Validate

Se produce antes de que un registro diferente se convierta en el registro actual; antes del
método Update (excepto cuando los datos se guardan con el método UpdateRecord); y de los
métodos Delete, Unload o la operación Close.

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 14


Private Sub objeto_Validate ([ índice As Integer,] acción As Integer, guardar As Integer)

objeto = Nombre del control Data


índice = Indice del control Data dentro de una matriz de controles (Si ha lugar)
acción = Un entero que indica la operación que ha producido el evento, como se describe mas
adelante
guardar = una expresión booleana que especifica si los datos asociados han cambiado, como
se describe mas adelante.

Acción puede tomar estos valores :

0 vbDataActionCancel Cancela la operación cuando se sale del


procedimiento Sub.
1 vbDataActionMoveFirst Método MoveFirst.
2 vbDataActionMovePrevious Método MovePrevious.
3 vbDataActionMoveNext Método MoveNext.
4 vbDataActionMoveLast Método MoveLast.
5 vbDataActionAddNew Método AddNew.
6 vbDataActionUpdate Operación Update (no UpdateRecord).
7 vbDataActionDelete Método Delete.
8 vbDataActionFind Método Find.
9 vbDataActionBookmark La propiedad Bookmark no ha sido definida.
10 vbDataActionClose Método Close.
11 vbDataActionUnload El formulario se va a descargar.

Los valores de guardar son:

True Los datos asociados han cambiado.


False Los datos asociados no han cambiado.

El evento Validate se usa para realizar las últimas comprobaciones sobre los registros que se
van a escribir en la base de datos.

Vea la ayuda de Visual Basic para mayor detalle de este evento.

CONTROLES ENLAZADOS A DATOS

Los controles enlazados a datos son aquellos que pueden presentar datos de una base de
datos, a través de un control Data. Los controles enlazados a datos permiten crear aplicaciones
con acceso a datos con muy poco código, o incluso ninguno. Para utilizar cualquiera de estos
controles enlazados conectables a datos debe incluir uno o más controles Data en un
formulario. El control Data establece un enlace entre la base de datos y los controles enlazados
para la manipulación de los datos. El control Data que sirve de enlace entre la Base de Datos y
los controles enlazados debe estar obligatoriamente en el mismo formulario que los controles.

Los controles asociados a datos tienen todos la propiedad DataSource, que es la propiedad
donde se debe poner el nombre del control Data asociado a ellos. Existen en Visual Basic trece
controles enlazados a datos, además del control Data :

Data Ya comentado, se utiliza para tener acceso a los datos de las bases a través de
controles enlazados de un formulario. Crea y administra los objetos Database y Recordset
para su uso por parte de los controles enlazados. Requerido para su uso con todos los demás
controles enlazados.

DBCombo Se utiliza para obtener una combinación enlazada formada por un cuadro de lista y
un cuadro de texto. La lista puede llenarse automáticamente a partir de un control Data. El

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 15


usuario puede elegir un elemento de la lista o introducir un valor en el cuadro de texto. Puede
utilizarse para proporcionar acceso de lectura / escritura a un campo de texto específico
seleccionado en la lista.

DBList Se usa para mostrar una lista generada a partir de un control Data en la que el usuario
puede elegir un elemento. La lista puede rellenarse automáticamente desde un control Data, y
puede proporcionar acceso de lectura / escritura a un campo de texto específico seleccionado
en ella.

DBGrid Se utiliza para mostrar a la vez todos los registros del recordset del control Data. El
DBGrid se rellena automáticamente con todos los registros, y muestra todos los campos del
recordset de control Data, formando una cuadrícula con filas y columnas. El usuario puede
elegir un elemento de la cuadrícula para variar el valor en ese campo y registro o introducir un
nuevo registro. El hecho de colocarse sobre un determinado registro de la cuadrícula, fuerza a
ese registro a convertirse en el registro actual del control Data al que está asociado.

Label Se usa para el texto que el usuario no debe modificar. Puede utilizarse para ofrecer
acceso de sólo lectura a un campo de texto específico.

TextBox Se utiliza para almacenar texto que el usuario puede introducir o modificar. Puede
utilizarse para proporcionar acceso de lectura / escritura a un campo de texto específico.

CheckBox Se utiliza para crear un cuadro que el usuario puede elegir de forma sencilla para
indicar si algo es verdadero o falso, o para mostrar varias opciones entre las que el usuario
pueda elegir más de una. Puede utilizarse para proporcionar acceso de lectura / escritura a un
campo booleano o de bit específico.

ComboBox Se utiliza para obtener una combinación de un cuadro de lista y un cuadro de


texto. La lista se rellena con el método AddItem. El usuario puede elegir un elemento de la lista
o introducir un valor en el cuadro de texto. Puede utilizarse para proporcionar acceso de lectura
/ escritura a un campo de texto seleccionado en la lista. Consulte el control DBCombo

ListBox Se utiliza para mostrar una lista en la cual el usuario puede elegir un elemento. La lista
se rellena con el método AddItem. Puede usarse para proporcionar acceso de lectura /
escritura a un campo de texto específico seleccionado en la lista. Consulte el control DBList

PictureBox Se usa para mostrar una imagen gráfica de un mapa de bits, un icono o un meta-
archivo en un formulario. Puede utilizarse para proporcionar acceso de lectura / escritura a un
campo de imagen o binario específico.

Image Se utiliza para mostrar una imagen gráfica de un mapa de bits, un icono o un meta-
archivo en un formulario. Las imágenes mostradas en un control Image utilizan menos recursos
que las de los controles PictureBox. Puede usarse para proporcionar acceso de lectura /
escritura a un campo de imagen o binario específico.

MSFlexGrid Es un control enlazado a datos de reciente incorporación. Apareció con la


versión 5 de VB y es un control parecido al DBGrid, pero con algunas ventajas y otros
inconveniente. En este caso, estando asociado a un control Data, el MSFlexGrid solamente
permite leer datos, no podemos variar el contenido de ningún registro. Tampoco se mueve el
registro actual del control Data cuando seleccionamos otra fila del MSFlexGrid.

PROPIEDADES RELACIONADAS CON DATOS COMUNES A ESTOS CONTROLES

Los controles enlazados a datos tienen unas propiedades para el acceso a datos basadas en el
enlace con la base de datos a través del control Data. Las propiedades comunes a todos ellos
son :

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 16


DataSource Fuente de datos. Es el nombre del control Data que lo enlaza con la B.D. Este
control Data es el que determina la Tabla donde están los campos con los datos. Esta Tabla se
determina mediante la propiedad RecordSource del control Data.

DataField Es el nombre del campo, dentro de la Tabla de la base de datos, que se va a


presentar en el control enlazado a datos. Esta propiedad no la tiene el DBGrid ni el
MSFlexGrid debido a que presentan todos los campos de la Tabla de la base de datos
seleccionada en el control Data.
Si se le ha forzado al control Data la propiedad Recordset, los campos que se pueden mostrar
en los controles enlazados a datos son justamente, los del ese Recordset al que se le ha
forzado.

Vamos a estudiar cada uno de los controles enlazados a datos con un poco mas de detalle.
Control Label

Posiblemente el control Label es el control más sencillo para mostrar el contenido de un campo
de una base de datos. Como todos los controles enlazados a datos, el Label permite presentar
los datos e introducirlos en la base a través del control Data. Lo que ocurre con el Label es que
su propiedad Caption no se puede introducir directamente por teclado, y deberá cambiarse por
código. Esto puede ser una ventaja (no hay posibilidad de introducirlo accidentalmente) y un
inconveniente, al tener que escribir código para hacerlo.
El control Label, al poder ser origen (a través del formulario que lo contiene) y destino de un
enlace DDE, esto nos puede resolver muchos problemas de introdución de distintos datos de
otras aplicaciones que no tengan acceso directo a una base de datos.

El control Label, en lo referente al enlace a datos, solamente tiene las propiedades


mencionadas de DataSource y DataField.

Control TextBox

Todo lo dicho del control Label es aplicable al TextBox, que además presenta la particularidad
de que en este control sí se puede escribir directamente desde el teclado. De esta forma
podemos introducir datos o cambiar los existentes en la base de datos.

Control CheckBox

El control CheckBox permite presentar e introducir datos de tipo Booleano. Tiene las
propiedades DataSource y DataField en lo relativo a acceso a datos.

Controles ListBox y ComboBox

Estos controles tienen una característica especial respecto a su comportamiento con el enlace
a la base de datos. La lista no se puede cargar directamente desde la base de datos, sino a
través de un control intermedio, por ejemplo un Label, donde presentaremos un campo de la
base de datos. El texto de la propiedad Caption de este Label se introduce en el ListBox o
ComboBox mediante el método AddItem. Una vez introducidos todos los elementos de ese
campo que nos interesen, cada vez que la base de datos se sitúa sobre el registro
correspondiente a uno de los elementos que está en el ListBox o ComboBox, éste cambia su
ListIndex para seleccionar el elemento correspondiente al registro actual del control Data.

El ListBox puede contener elementos correspondientes a la base de datos y otros ajenos.


Puede emplearse esta característica del ListBox para seleccionar un elemento entre varios
elementos tomados de la BD y otros introducidos por otro procedimiento, con la particularidad
de que el ListIndex de este ListBox irá a posicionarse sobre el elemento de la BD
correspondiente al registro actual del Control Data.

Tienen las propiedades DataSource y DataField en lo relativo a acceso a datos.

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 17


Controles DBList y DBCombo

Para agregar estos controles debe insertar el OCX Microsoft Data Bound List Controls 6.0

Estos controles tienen dos enlaces a controles data. Uno para rellenar la lista, que se lo
debemos indicar en la propiedad RowSource, acompañado del nombre del campo con el que
la va a rellenar, que introduciremos en la propiedad ListField, y otro enlace a otro control Data,
que se lo debemos indicar en la propiedad DataSource. El campo de este segundo control
Data se lo indicaremos en la propiedad DataField. El comportamiento de estos dos controles
es el siguiente: Mediante el enlace a través de la propiedad RowSource se rellena la lista,
utilizando los datos del campo elegido en la propiedad ListField. Imaginemos que la tabla a la
que nos conectamos con estas propiedades es la Tabla A. La tabla a la que enlazamos el
DBList mediante la propiedad DataSource, le llamamos Tabla B. Con este invento vamos a
pasar un dato desde la tabla A a la tabla B. El dato que vamos a pasar está en la tabla A en el
campo señalado en la propiedad BoundColumn del DBList. El registro de la tabla A de donde
cogemos el dato será el seleccionado en el DBList. El registro de la tabla B donde vamos a
meter el dato será el registro actual de ese control data, control actual que habremos
seleccionado mediante cualquier método. El campo de esa tabla B que vamos a variar será el
campo indicado en la propiedad DataField. (Esto se vuelve a explicar mas abajo, pero para
entenderlo no hay mas remedio que realizar una práctica)

Control PictureBox y Control Image

Pueden mostrar una imagen almacenada en una Base de Datos. Mediante el control Data, se
puede introducir la imagen presente en uno de estos controles en la Base de Datos.

El campo que contenga una imagen en una BD debe ser tipo Objeto OLE (Binario Largo en
versiones anteriores de Access), y el tipo de imágenes que se pueden introducir son los mapas
de bits (Archivos con extensión .BMP), los archivos de icono, (Extensión .ICO) y los
metaarchivos. (Metafiles, extensión .WMF)

Para introducir un gráfico en una BD es mas práctico introducirlo mediante un control Data y un
control Picture o Image que creando por código un Recordset. En realidad deberíamos decir
que es el único método práctico de introducir / sacar imágenes de una Base de Datos

Control DBGrid

Es posiblemente el control que más se use para presentar y modificar datos de una B.D. El
control DBGrid presenta todos los registros y todos los campos de la Base de Datos. Por eso,
necesita obligatoriamente un control Data para poder presentar datos. Otros controles (Label,
TextBox, Picture, etc.) que solamente presentan un dato (un campo de un registro) pueden
trabajar sin necesidad de un control data, creando un Recordset mediante código. (Lo veremos
un poco mas adelante). Sin embargo el control DBGrid, al presentar todos los datos de la base
de datos necesita un control Data. Veamos porqué.

Cuando creamos un objeto Recordset mediante la instrucción : (se verá mas adelante)

Set Mirecordset = MiDataBase.Openrecordset (“Select campo1, campo2 from Mitabla”)

lo que estamos haciendo es seleccionar, de todos los campos que pueda tener la tabla llamada
Mitabla, los denominados campo1 y campo2. Cada vez que seleccionemos un registro, es ese
registro solamente el que se mantiene en la memoria del ordenador, (el registro actual) y de ese
registro, solamente metemos los datos del campo1 y campo2.

Cuando creamos un Recordset mediante un control Data, se meten en la memoria TODOS los
registros de la tabla especificada en el control data. Por lo tanto, al permanecer todos los
registros de esa tabla en memoria, podremos presentar sus valores en el control DBGrid. No lo
podremos hacer con un Recordset creado mediante código, que solamente mantiene un

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 18


registro en memoria.

Deberemos explicar qué ocurre cuando se crea un Recordset mediante código, y


posteriormente se fuerza a que el Recordset del control data sea igual a ese Recordset creado.

Con el Recordset creado con la instrucción anterior, podemos forzar a un control Data que su
Recordset sea igual al ya creado mediante la instrucción :

Set Data1.Recordset = MiRecordset

En este caso, el control Data1 tomará todos los registros con los campos campo1 y campo2 de
la base de datos y los meterá en la memoria RAM. Así ya podemos rellenar las cuadrículas del
control DBGrid.

Observe que una aplicación de acceso a datos ocupará mucha mas memoria RAM si
establecemos el enlace con la base de datos mediante un control Data que si lo hacemos
creando Recordsets a medida. Pero si necesitamos presentar los datos en un DBGrid, no
quedará mas remedio que usar un control Data. Si nuestra aplicación no tiene que presentar en
el DBGrid todos los campos de la tabla de la B.D. podemos crear previamente un Recordset
mediante código y a continuación forzar que el Recordset del control Data sea igual al
Recordset creado, utilizando la expresión anterior.

El control DBGrid tendrá tantas columnas como campos tenga el Recordset. El número de filas
será igual al número de registros que tiene la tabla. Si se sobrepasa el espacio físico del
DBGrid para poder presentarlos, aparecerán automáticamente flechas de deslizamiento vertical.
El ancho de las columnas puede cambiarse mediante la propiedad Width del objeto Columns
del DBGrid.

DBGrid1.Columns(n).Width = Valor

Donde n es el número de la columna (la primera es la 0) y el valor debe expresarse según las
unidades de medida (ScaleWidth) del Formulario que lo contiene.

Del control DBGrid podemos destacar estas propiedades :

AllowAddNew

Devuelve o establece un valor que indica si el usuario puede agregar nuevos registros al objeto
Recordset subyacente a un control DBGrid.

La última fila que se muestra en el control DBGrid se deja en blanco para permitir a los usuarios
introducir nuevos registros. Si la propiedad AllowAddNew es False, los usuarios no pueden
establecer el foco en dicha fila.
El Recordset subyacente puede, por otras razones, no permitir inserciones incluso en el caso de
que la propiedad AllowAddNew sea True. En este caso, se producirá un error si el usuario
intenta agregar un registro.

AllowDelete

Devuelve o establece un valor que indica si el usuario puede eliminar registros del objeto
Recordset subyacente a un control DBGrid.

Utilice la propiedad AllowDelete para impedir que los usuarios eliminen registros del conjunto
de registros a través de la interacción con el control DBGrid.
El objeto Recordset subyacente puede, por otras razones, no permitir eliminaciones incluso en
el caso de que la propiedad AllowDelete sea True. En este caso, se producirá un error si el
usuario intenta eliminar un registro.
AllowRowSizing

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 19


Devuelve o establece un valor que indica si un usuario puede modificar el tamaño de las filas
del control DBGrid.

Sintaxis nombre.AllowRowSizing = [True / False]

Si la propiedad AllowSizing es True, el puntero del mouse se convierte en una flecha de doble
cabeza (Size N S) cuando se sitúa sobre el divisor de filas entre selectores de registro, y el
usuario puede modificar el tamaño de las filas mediante arrastre. Cualquier cambio de tamaño
de columna provoca un evento RowResize.

AllowUpdate

Devuelve o establece un valor que indica si un usuario puede modificar datos del control
DBGrid.

Sintaxis nombre.AllowUpdate = [True / False]

Cuando la propiedad AllowUpdate es False, el usuario puede aún desplazarse a través del
control DBGrid y seleccionar datos, pero no puede modificar ninguno de los valores; cualquier
intento de hacerlo se ignora.
Puede también hacer uso de las propiedades del objeto Columns para hacer que columnas
individuales del control DBGrid sean de sólo lectura, pero los valores de la propiedad
AllowUpdate tienen prioridad sobre los valores establecidos para las columnas (sin modificar
éstos).

Nota El objeto Recordset puede no permitir actualizaciones incluso si AllowUpdate es True


para el control DBGrid; en este caso se produce un error interceptable cuando el usuario intenta
cambiar el registro.

ColumnHeaders

Devuelve o establece un valor que indica si los encabezados de columna se muestran en el


control DBGrid.

Sintaxis objeto.ColumnHeaders = [True / False]

Si es True se muestran los encabezados de columna del control DBGrid, y si es False no se


muestran.

DataMode

Establece un valor que especifica si el control DBGrid funciona en modo enlazado o no


enlazado. Esta propiedad no está disponible en tiempo de ejecución.

Los valores que puede tomar la propiedad DataMode son:

0-Bound. El control DBGrid está enlazado con el control Data.


1-Unbound. El control DBGrid no está enlazado directamente al control Data.

Un DBGrid está enlazado cuando se le asigna un control Data en su propiedad DataSource. En


este caso, presenta sin mas los datos del Recordset de ese control Data. Si le especificamos en
la propiedad DataMode que no esté enlazado, utilizaremos código en los procedimientos del
control Data para pasarle los datos cuando nos interese.

DefColWidth

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 20


Devuelve o establece un valor que indica el ancho de columna predeterminado para todas las
columnas del control DBGrid.

Sintaxis objeto.DefColWidth [= valor]

donde valor es un entero basado en el modo de escala del control.

Si se da a la propiedad DefColWidth el valor 0, el control establece automáticamente el tamaño


de todas las columnas en base al ancho del encabezado de columna o al valor de la propiedad
Size del campo subyacente, seleccionando el más largo de los dos.

RecordSelectors

Los selectores de registros aparecen a la izquierda de las filas en el control DBGrid. Cuando el
usuario elige el selector, el registro completo (fila del control DBGrid) se selecciona.

La propiedad RecordSelectors devuelve o establece un valor que indica si se muestran los


selectores de registro en el control DBGrid.

Sintaxis objeto.RecordSelectors = [True / False]

El Objeto Columns aplicado al control DBGrid.

El objeto Columns es un objeto no privativo del control DBGrid, que contiene todas las
columnas y las propiedades de las columnas de un control. Podemos cambiar las propiedades
de cada una de las columnas de un DBGrid mediante las propiedades del objetos Columns
asociado a él. Por ejemplo, el encabezamiento de una columna en un DBGrid es, por defecto, el
nombre del campo que se va a presentar en esa columna. Si queremos poner otro
encabezamiento a una columna, ejecutaremos la expresión :

DBGrid1.Columns(0).Caption = "Cabecera"

donde el 0 entre paréntesis significa que estamos afectando a la columna número 0 (la primera
por la izquierda).

Si queremos cambiar su anchura :

DBGrid1.Columns(3).Width = 1000

En este caso estamos fijando la anchura de la columna cuarta por la izquierda a 1000 unidades
de medida de las del Formulario que contiene al DBGrid.

CONTROLES DBList y DBCombo

Los dos controles DBList y DBCombo se implementan de la misma manera. Las dos únicas
diferencias estriban en la forma en que se presenta la información al usuario y la presencia de
la porción del control DBCombo en el cuadro de texto, que se emplea para introducir valores.

Los controles DBList y DBCombo tienen dos modos que pueden utilizarse individualmente o al
mismo tiempo:

Autollenado: Llena automáticamente la lista con un campo seleccionado de entre todos los
registros administrados por el control Data especificado por la propiedad RowSource del
control DBList o DBCombo.

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 21


Actualización automática: Enlaza el registro seleccionado en el control a un campo específico
del objeto Recordset administrado por el control Data especificado por la propiedad
DataSource.

Esto explicado en otras palabras significa lo siguiente :

En control DBList o DBCombo puede trabajar sobre dos controles Data. Uno para rellenar la
lista. El control Data y el campo que rellena la lista son los especificados en las propiedades
RowSource y ListField del control DBList o DBCombo. Respecto a este control Data estos
controles funcionan solamente como receptores de datos : No pueden cambiar el contenido de
los registros con los que rellenan su lista. (Llamemos a esta base de datos Base A en esta
explicación)

El otro control Data es el que estos controles usan para introducir datos en su BD asociada. El
control Data y el campo de la BD asociados a estos controles DBList y DBCombo, son los
especificados en las propiedades DataSource y DataField. Es sobre esta base de datos y el
campo correspondiente sobre los que estos controles DBList y DBCombo actúan cambiando o
introduciendo datos. (Llamemos a esta otra base de datos Base B)

Basta con seleccionar un elemento de la lista (que pertenece a la base A) y un campo (X) del
registro de la base A al que pertenece ese elemento se colocará en el campo correspondiente
(el indicado en la propiedad DataField del control DBList o DBCombo) de la base B. En el caso
del DBCombo, podemos escribir directamente el dato en su caja de texto en vez de
seleccionarlo de la lista.

Ese campo (X) cuyo dato pasamos de la base A a la base B no tiene porqué ser el elemento
que vemos en la lista. Puede ser otro campo de la base A. Será el que introduzcamos en la
propiedad BoundColumn del DBList o DBCombo. Es la propiedad que viene a continuación.
Léasela con la atención que se merece.

Propiedad BoundColumn

Devuelve o establece el nombre del campo de origen de un objeto Recordset que se utiliza para
suministrar un valor de datos a otro Recordset.

Resumamos. En un DBList o DBCombo presentamos en su lista un determinado campo de una


BD. Esa BD tendrá mas campos. Un poco mas arriba decíamos que ese elemento de la lista
podíamos pasarlo a otra BD (La especificada en la propiedad DataSource, y en su campo
DataField). ¿Podríamos pasar a esa BD, en vez del elemento de la lista, otro campo de esa
BD origen ?. Podríamos, por ejemplo, presentar en la lista el nombre de una persona, nombre
que hemos tomado de un listín telefónico, y en vez de pasar el nombre que es el que figura en
la lista, pasar su número de teléfono, que es otro campo de la misma BD. La respuesta es SI.
Para ello, pongamos en la propiedad BoundColumn del DBList o DBCombo que estamos
usando, el nombre del campo que contiene el número de teléfono. Observe que por defecto,
esa propiedad se rellena con el mismo campo que el especificado en la propiedad ListField.
Eso no quiere decir que no se pueda cambiar. Para cambiarlo, haga click en la flecha vertical
que aparece en la casilla de propiedades, y donde verá que aparecen todos los campos de la
base de datos seleccionada en el control Data asociado a este control. También puede
cambiarlo en tiempo de ejecución con la siguiente sintaxis :

nombredelDBList.BoundColumn = nombredelcampo

Con estas ideas expresadas aquí, puede comenzar a leer el texto de ayuda de esta propiedad.
No se desespere si no entiende algo de lo allí expresado.

BoundText

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 22


Devuelve o establece el valor de la propiedad BoundColumn de un control DBCombo o DBList
pasado desde o hacia la propiedad DataField después de realizar una selección. Es decir, es el
contenido del campo especificado en la propiedad BoundColumn comentada anteriormente.

Esta propiedad está disponible solamente en tiempo de ejecución.

Esta propiedad es de lectura y escritura. Es sencilla de usar para conocer el contenido del
campo especificado en BoundColumn. (lectura del valor)

Cuando la queramos utilizar para forzar el valor de esta propiedad a un valor determinado,
debemos utilizar la siguiente sintaxis :

objeto.BoundText [= valor]

En este caso, el DBList o DBCombo intenta buscar un elemento coincidente en el campo


especificado en la propiedad BoundColumn de todos los registros de la BD asociada. Si
encuentra uno igual , se establece el valor de la propiedad BoundText basándose en el campo
especificado por la propiedad BoundColumn. Si no se encuentra dicha coincidencia, la
propiedad BoundText se establece en el valor Null.

Es decir, si hay coincidencia con algún valor de ese campo, BoundText seguirá con el valor
especificado. Si no la hay, BoundText se pone a Nulo.

MatchWithList

Propiedad solo de lectura. Devuelve True si el contenido actual de la propiedad BoundText


coincide con uno de los registros de la parte de lista del control.

Sintaxis Variable = objeto.MatchWithList

Si Variable = True el contenido de la propiedad BoundText coincide con uno de los registros de
la lista. Si es False, el contenido de la propiedad BoundText no coincide con ninguno de los
registros de la lista.

Cuando introduce un valor en la parte de texto del control DBCombo, la propiedad


MatchWithList se establece como True si el valor introducido es uno de los elementos que
aparecen en la lista. Usando esta propiedad, el código puede interceptar entradas que no están
la lista, o proporcionar código para agregar la nueva entrada a la tabla de origen.

DataChanged

Devuelve o establece un valor que indica que han cambiado los datos del control enlazado por
algún proceso distinto de la recuperación de datos del registro actual. No está disponible en
tiempo de diseño.

Sintaxis objeto.DataChanged [=Variable] ‘establece la propiedad


Variable = objeto.DataChanged ‘lee el valor actual de esta propiedad

Variable puede ser True, indicando que los datos que hay actualmente en el control no son
iguales que los del registro actual, y False (Predeterminado) que indica que los datos que hay
actualmente en el control (si los hay) son iguales que los del registro actual.

Comentarios

Cuando un control Data se mueve de un registro a otro, pasa datos desde los campos del
registro actual a controles enlazados al campo específico o el registro completo. Cuando se

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 23


muestran datos en los controles enlazados, la propiedad DataChanged se establece como
False. Si el usuario o alguna operación cambia el valor del control enlazado, la propiedad
DataChanged se establece como True. Si pasa a otro registro la propiedad DataChanged no se
ve afectada.
Cuando el control Data comienza a mover a otro registro, se produce el evento Validate. Si
DataChanged es True para algún control enlazado, el control Data invoca automáticamente los
métodos Edit y Update para enviar los cambios a la base de datos.

Si no desea guardar los cambios de un control enlazado en la base de datos, puede


establecer la propiedad DataChanged como False en el evento Validate.

MatchEntry

Devuelve o establece un valor que indica cómo el control DBCombo o DBList realiza búsquedas
basándose en la entrada del usuario.

Sintaxis objeto.MatchEntry = valor

Donde valor es una constante o un valor que define el comportamiento de un control cuando
tiene el enfoque y el usuario introduce uno o más caracteres.

0 vbMatchEntrySimple Coincidencia básica: (Predeterminado) El control busca la


siguiente coincidencia del carácter introducido usando la primera letra de entradas de la lista. Al
escribir repetidamente la misma letra se recorren todas las entradas de la lista que comienzan
por esa letra.
1 vbMatchEntryExtended Coincidencia ampliada: El control busca una entrada que
coincida con todos los caracteres introducidos. La búsqueda se realiza a medida que se
escriben los caracteres, refinando progresivamente la búsqueda.

Cuando la propiedad MatchEntry se establece como vbMatchEntryExtended y el usuario


presiona la tecla de retroceso o espera varios segundos, la cadena de coincidencias de
restablece.

SelectedItem (Solo DBCombo)

Devuelve un valor que contiene un marcador para el registro seleccionado en un control


DBCombo.

Sintaxis DBCombo1.SelectedItem

Cuando selecciona un elemento de la parte de lista del control DBCombo, la propiedad


SelectedItem contiene un marcador que puede utilizar para reposicionar el registro
seleccionado en el Recordset como especifica la propiedad RowSource.

SelText

SelText devuelve o establece una cadena con el texto actualmente seleccionado, o es una
cadena de longitud cero () si no hay caracteres seleccionados.

VisibleCount

Devuelve un valor que indica el número de elementos visibles del control DBCombo o DBList.

Sintaxis objeto.VisibleCount

La propiedad VisibleCount devuelve un entero desde 0 al número de elementos visibles del


control. Un elemento se considera visible únicamente si una parte del texto es visible.
VisibleItems

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 24


Devuelve una matriz marcadores, uno para cada elemento visible de la lista del control
DBCombo o DBList.

Sintaxis objeto.VisibleItems

Estos marcadores pueden emplearse para obtener registros individuales del conjunto de
registros empleado para rellenar la lista.

Y aquí se terminan las propiedades de DBList y DBCombo. ¡La lata que dan y lo poco
que se usan!

Controles Picture e Image para acceso a datos a través del control Data.
Merece la pena hablar del almacenamiento de imágenes en una base de datos. Es posible
introducir imágenes en una base de datos Access. El campo debe ser del tipo Objeto OLE y
puede manejarse de dos formas, una de forma sencilla, mediante un control Data, y otra de
forma un poco complicada, mediante los métodos AppendChunk y GetChunk. Estos dos
métodos los veremos un próximo capítulo. Pero adelanto que es complicado usarlos.

Es muy sencillo sin embargo introducir y presentar imágenes residentes en una base de datos
mediante los controles Picture e Image. Estos controles son enlazados a datos y pueden
guardar una imagen o presentarla. Basta para ello poner los valores adecuados en las
propiedades DataSource y DataField para elegir un campo tipo Objeto OLE de la base de datos
y está el problema resuelto. Sobre todo para presentar la imagen, que lo hace
automáticamente. No es lo mismo para introducir los datos, pero también es muy sencillo.

Basta para ello disponer de un CommonDialog, por ejemplo, para buscar una imagen dentro del
disco. El fichero puede ser un BMP, JPG o WMF. Abrimos el CommonDialog (CD1) y
buscamos la imagen deseada. A continuación la cargamos en el Control Picture o Image que
está enlazado a datos mediante el método LoadPicture. Para introducir la imagen en la base de
datos basta con cambiar de registro, o utilizar el método UpdateRecord del control Data.

Para presentar una imagen es preferible usar el control Image con la propiedad Stretch = False
a usar el control Picture. Con el Image y esa propiedad puesta a False, siempre veremos la
imagen con el tamaño diseñado en el formulario. Hacerlo con el control Picture se puede, pero
es algo mas complicado.

Pese a que, como se ha visto, se pueden meter imágenes en la base de datos Access, no es
aconsejable hacerlo debido al volumen tan grande de datos que genera. Es preferible guardar la
imagen en el fichero con la imagen, y meter en la base de datos la dirección completa del
fichero. Para abrirlo no hay mas que leer la dirección del fichero, y presentarlo en el Picture o
Image mediante el método LoadPicture.

Control MSFlexGrid
El control MSFlexGrid es un control similar al DBGrid, pero pensado fundamentalmente para
enlazarlo a datos a través del control Adodc1 (El control similar al Data en ADO). Sin embargo
también funciona con el control Data, aunque con prestaciones reducidas. Estando enlazado al
control Data, muestra los datos solo para lectura. Tampoco permite cambiar el registro actual
del control Data haciendo click sobre una de las líneas del MSFlexGrid. Estas dos condiciones
le hacen el control ideal para presentar todos los datos del control Data para aquellos casos en
los que no se permite cambiarlos al usuario.

Nota final al control Data

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 25


Puede ver en la información de Microsoft palabras como “los antiguos controles Data y Control
de datos remotos (RDC)”. No se desanime. El control Data y DAO tienen mucho que decir
todavía en la programación en Visual Basic. Efectivamente hay controles más modernos
creados mediante la tecnología ActiveX que aportan unas prestaciones mayores que estos dos
controles. Y formas de acceso a datos mucho más modernas y abiertas que el motor Jet. Pero
tienen también su contrapartidas. Estudie bien el control Data y el acceso a través de DAO.
Llevará mucho camino recorrido para estudiar posteriormente ADO.

LSB Visual Basic Guía del Estudiante Capítulo 11 Pág. 26


Visual Basic Guía del estudiante Cap. 12
Objetos DAO
ACCESO A BASES DE DATOS SIN UTILIZAR EL CONTROL DATA

En el capítulo anterior hemos visto los controles capaces de acceder a un Base de Datos,
enlazados mediante un control Data. Se comenzó a exponer que no es necesario usar un
control Data para acceder a leer datos, añadir registros o cambiar su contenido. Y es más.
Comenzaremos ahora a ver que el control Data pese a que puede evitarnos gran cantidad de
líneas de código, nos hace perder el control respecto al programa. Es normal. El control Data se
ha desarrollado para realizar un trabajo muy estándar. Si nuestra aplicación se separa un poco
de lo normal, lo mas probable es que necesitemos realizar las operaciones mediante código.
Esto no quiere decir que el Data haya que dejarlo en desuso. Será necesario en aquellas
aplicaciones en las que se va a usar un control DBGrid, pues como se recordará, mediante el
uso de un control Data metemos en memoria RAM todo el contenido de la base de datos
relativo al Recordset que hemos creado. El control Data será necesario en aquellas
aplicaciones donde utilicemos un DBGrid, un DBList o un DBCombo. Veremos mas
adelante que también será necesario cuando queramos guardar imágenes en una Base de
Datos.

El control Data también permite consultas más rápidas a la BD. El hecho de guardar el
contenido completo del Recordset en la memoria hace que cualquier consulta sea más rápida.
Eso sí, estamos empleando mucha más memoria RAM.

Pero en este capítulo vamos a ver como se pueden manejar bases de datos utilizando otros
objetos de acceso a datos. Concretamente los objetos DAO.- (Data Access Objet).

Los objetos DAO utilizan el Motor de Bases de Datos Jet de Microsoft y trabajan
directamente sobre el fichero que contiene la base de datos. Existen otros objetos de acceso a
datos, como ha podido ver en el capítulo anterior, que no trabajan directamente sobre el fichero,
sino sobre una conexión ODBC que enlaza con la base de datos. Son los objetos RDO y ADO,
cuyo estudio se realizará en capítulos posteriores. Estos últimos tipos son mas modernos, pero
no tienen algunas prestaciones que tienen los DAO, debido precisamente a que no trabajan
directamente sobre el fichero. Centrémonos sobre los objetos DAO

Estos objetos, pese a que no tienen representación en la interface gráfica, son objetos Visual
Basic como los demás, y nos podremos referir a ellos por su nombre como hacíamos con todos
los controles. Eso sí, debemos declararlos como se declaran las variables, y siguen siendo
válidos los criterios de declaración de variables en cuanto al ámbito de aplicación. Si
declaramos un DAO en un procedimiento, no nos podremos referir a él fuera de ese
procedimiento. Si queremos que sea válido en toda la aplicación deberemos declararlo en la
sección de declaraciones de un módulo, o en la sección de declaraciones de un formulario si
fuese suficiente ese ámbito para nuestra aplicación.

La primera sorpresa suele ocurrir a la hora de declarar un objeto. Por ejemplo, para declarar un
objeto tipo DataBase debemos hacerlo con la siguiente declaración:

Dim MiBaseDatos As DataBase

Y al ejecutar el programa puede ocurrirle el siguiente error: Error de compilación. No se ha


definido el tipo definido por el usuario.

Lo que le está ocurriendo es que su programa no conoce el tipo de variable DataBase. Para que
la conozca, debe agregarle una referencia. Vaya a Proyecto | Referencias … de la barra de
menú y seleccione Microsoft DAO 3.51 Objet Library Haga click en Aceptar y ya tiene
agregada esa referencia a su programa. Agregar una referencia significa que le ha dicho a su
programa que puede hacer uso de una colección de DLLs donde podrá encontrar la definición

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 1


del objeto o la variable que no encuentra. Ahora ya no le dará el error anterior, pues en esa DLL
que acaba de agregarle a su programa está la explicación al secreto de lo que es un objeto
DataBase.

Verá que hay mas referencias parecidas a Microsoft DAO 3.51. (Las versiones 2.0, 2.1,
2.5/3.5, y si ha instalado Access2000 tendrá la 3.6) Existen tantas versiones distintas como
versiones de Access. En realidad esta DLL no es mas que un componente de Access que
podemos usar, al igual que lo hace Access, para gestionar una base de datos. Debe elegir la
versión mas alta, pero con cuidado. La versión 3.5 corresponde a la versión de Access 97.
Cuando cree con su programa una base de datos con esta versión, no podrá abrirla con Access
2.0 No se olvide de la teoría de la compatibilidad de Microsoft, que dice que cualquier versión
que Microsoft considere obsoleta no debe reconocer los datos guardados por versiones más
modernas del mismo programa. Piense si es posible que alguien que vaya a abrir una base de
datos guardada con su aplicación dispone de una versión anterior de Access. Por ejemplo,
cuando se está escribiendo este libro, está recién aparecido Access 2000. ¿Cree que es
oportuno en estos momentos, en los que todavía se está introduciendo en muchos usuarios
Access 97 usar una DLL que nos cree bases de datos que solamente puedan ser abiertas por
Access 2000?.

La versión Microsoft DAO 3.6 corresponde a Access 2000. Si ha instalado este programa le
aparecerá esa referencia en la lista de referencias. No se sorprenda si antes de instalar Access
2000 no tenía esa referencia y después de la instalación sí. Si crea una BD con la versión 3.6
no podrá abrirla con Access 97 ¡Esta es la compatibilidad hacia delante de Microsoft!

Objetos DAO de acceso a datos

Son muchos y tienen estructura jerárquica. Es importante resaltar lo de su estructura jerárquica,


ya que como verá, un objeto DAO crea los objetos DAO inmediatamente inferiores en jerarquía.

Hay que señalar que las colecciones de estos objetos DAO son a su vez objetos de acceso a
datos. Esto hay que explicarlo un poco mejor. Por ejemplo, un objeto Database es un objeto
DAO que representa una base de datos abierta. Al objeto que agrupa a todas las bases de
datos abiertas en ese momento le llamamos Objeto Databases. Si tenemos dos bases de
datos abiertas en un determinado momento, el objeto Databases contendrá dos elementos.

Todos los objetos DAO excepto el dbEngine tienen colecciones. Es lógico. El dbEngine, como
verá mas adelante, es precisamente el Motor de Bases de Datos Jet y solamente existe uno.
Comenzaremos precisamente por él la explicación de los objetos DAO.

El dbEngine es el motor Jet. Y como vimos en el capítulo anterior, la versión 3.5 puede trabajar
directamente sobre el fichero de la base de datos o a través de una conexión ODBC. En el
primer caso decimos que está trabajando en el espacio de trabajo Microsoft Jet Si le
hacemos trabajar a través de ODBC decimos que estamos trabajando en el espacio de trabajo
ODBCDirect

Los objetos que emplea en cada uno de los espacios de trabajo pueden verse en las figuras
20.1 y 20.2. Puede observarse que tiene muchos mas objetos en el espacio de trabajo
Microsoft Jet que en el de ODBCDirect. Es lógico. Con el primero nos permite CREAR bases
de datos, y por lo tanto necesita tener objetos tales como el Tabledef, Index o Relation. Lo verá
un poco mas adelante.

El objeto dbEngine tiene los siguientes métodos, propiedades y colecciones


Métodos CreateWorkspace, CompactDatabase, RepairDatabase, Idle, RegisterDatabase
Propiedades DefaultPassword, DefaultUser, IniPath, LoginTimeout, Version
Colecciones Errors, Properties, Workspaces

Veremos estos métodos y propiedades según vayamos avanzando en el capítulo

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 2


Fig. 20.1 Objetos DAO para el espacio de trabajo Microsoft Jet

En esta figura pueden verse los objetos y sus colecciones. Las colecciones llevan el nombre en
plural. Parece un poco complicado, y posiblemente lo será. Lo cierto es que para el trabajo que
se hace normalmente con bases de datos este diagrama queda bastante reducido. No se
extrañe tampoco de ver que objetos como el Fields y el Field existen en varios niveles. Lo verá
mucho mejor mas adelante.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 3


Fig. 20.2 Objetos DAO para el espacio de trabajo ODBCDirect

Este modelo parece un poco mas asequible. La razón es que no hace todo lo que hace el
espacio de trabajo Microsoft Jet.

Objeto Workspace
Un objeto Workspace define una sesión de trabajo para un usuario específico. Una sesión de
trabajo es precisamente eso, una sesión de trabajo en el más puro estilo informático. Pueden
existir varias sesiones de trabajo, pero en la mayoría de los casos eso no es lo normal. Será
necesario crear varias sesiones cuando necesitemos imponer restricciones de acceso a una
base de datos, cuando tengamos que usar Transacciones (*) en un sistema multiusuario, y en
algún caso más. Las sesiones de trabajo tienen dueño (Usuario) y una palabra clave para
acceder a ellas.

Pero lo normal es tener solamente una sesión abierta. Y visual Basic nos facilita este caso
abriendo una sesión de trabajo automáticamente. Cuando se inicia Visual Basic, se crea un
Workspace con palabra clave y nombre de usuario Admin. Este Workspace es precisamente
el que ocupa el número cero de la colección de Workspaces. Es decir, es el Workspaces(0).

No se preocupe de que ahora mismo no lo entienda. Ya lo entenderá. Pero hay que exponerlo
ahora. El objeto Workspace contiene:

Para el espacio de trabajo Microsoft Jet:


Grupos de trabajo, que es un grupo de usuarios de un entorno multiusuario que
comparten datos y el mismo sistema de base de datos.
Grupos de usuarios, que es una colección de cuentas de usuario. Estos objetos, que
no son objetos de acceso a datos, sino de explotación de los recursos del sistema,
están enfocados a la seguridad respecto al acceso a las bases de datos que se trabajan
conjuntamente. No tendría sentido hablar aquí de ellos si no fuese porque encontrará
referencias a estos objetos continuamente en la ayuda de Visual Basic.
Bases de Datos (Databases). Este el objeto que ahora nos interesa del objeto
Workspace. Un objeto Database es una base de datos abierta.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 4


Para el espacio de trabajo ODBCDirect:
Conexión, que representa una conexión con una base de datos a través de ODBC
Bases de Datos (Databases).

Ya podemos comenzar a comprender una diferencia entre ambos espacios de trabajo. En el


Microsoft Jet tenemos Usuarios y Grupos de Usuarios. En el espacio ODBCDirect no los
tenemos, ya que el permiso o denegación de acceso de uno u otro usuario a una base de datos
se establece cuando se crea (en Windows) la conexión ODBC. En el espacio ODBCDirect
tenemos un objeto llamado Connection, objeto que no tenemos en el Microsoft Jet ya que con
este sistema accedemos directamente al fichero de la base de datos. No necesitamos ninguna
conexión establecida previamente.

Al objeto Workspace se le puede dar un nombre definido por el usuario. Ese nombre habrá que
declararlo como nombre de una variable objeto Workspace :

Dim Misesion as Workspace

La declaración de la variable Objeto tiene las mismas características que cualquier variable en
cuanto al ámbito en el que se puede usar. Para que pueda usarse en toda la aplicación
deberemos declararla en un Módulo con la sentencia Public

Public Misesion as Workspace

Esta advertencia es válida para la declaración de todos los objetos DAO.

Una vez declarado el nombre del objeto Workspace, hay que crearlo. En realidad, y tal como
citábamos mas atrás, cada vez que se inicia una sesión de Visual Basic, se crea
automáticamente un Workspace. El número 0 A este Workspace no podemos ponerle ningún
tipo de palabra de acceso, ya que se la ha puesto VB : Admin. Utilicemos este Workspace, el
número 0 de la colección Workspaces, para comenzar a trabajar. Tiempo tendremos mas
adelante de ver como se crea un Workspace. Para hacer que Misesion sea ese Workspace que
crea automáticamente VB basta con ejecutar la siguiente línea de código

Set Misesion = Workspaces(0)

Pero si no queremos aprovechar este Workspace creado automáticamente por Visual Basic, y
queremos usar otro, usemos el método CreateWorkspace. Se verá al final del capítulo.

Creación de Objetos DAO


Para crear un objeto DAO (Cualquiera que sea) debemos usar una forma que se va a repetir a
lo largo de toda su vida profesional, mientras trabaje con Visual Basic y Bases de Datos:

Set ObjetoDAOInferior = ObjetoDAOSuperior.Método ( Aquí .... alguna cosa )

Logicamente el término Aquí .... alguna cosa va a depender de cada método y de lo que Vd.
quiera hacer, pero la estructura Set DAOInferior = DAOSuperior.Método ( - - - - - - - - - - )
se mantendrá en todas las operaciones de creación y manipulación de objetos DAO. Esta
sintaxis es tan simple que un profesor de Visual Basic decía que es como un “juego de niños”
No lo olvide y se le quitará el miedo al manejo de bases de datos mediante código.
Posiblemente hasta ahora le haya parecido muy difícil y haya optado por usar el control Data
para todas sus aplicaciones. Si recuerda este Juego de niños verá que es más sencillo crear
objetos DAO que poner un control Data en un formulario.

Comenzaremos a explicar la operación de bases de datos mediante DAO explicando como se


crean bases de datos Access mediante Visual Basic. ¿Para que se van a crear bases de datos
mediante un programa si puedo hacerlo directamente con Access? . Esta pregunta me la han
hecho los alumnos durante todos mis años de docencia. La única respuesta para ello es que
deseo que Vd. sea programador, no usuario de ofimática.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 5


Objeto Database
Un objeto Database representa una base de datos abierta. Una colección Databases
contiene todos los objetos Database abiertos en un objeto Workspace del motor de bases de
datos Microsoft Jet.

Un objeto Database puede crearse, bien porque hemos creado una base de datos mediante el
procedimiento CreateDataBase, o porque hemos abierto una base de datos existente mediante
el procedimiento OpenDatabase. En cualquiera de los dos casos, el objeto Database existe
hasta que lo cerremos (mediante el método Close) o hasta que cerremos la aplicación.

Al objeto Database se le debe dar un nombre definido por el usuario. Eso sí, hay que declararlo
como una variable objeto Database

Dim MiDataBase As Database

El nombre que le demos al objeto DataBase no tiene nada que ver con el nombre del fichero
que alberga esa base de datos. El objeto DataBase es la base de datos que creamos en la
memoria RAM del ordenador.

Colección Databases Es el conjunto de Objetos Database existentes. La colección Databases


pertenece al Workspace.

Crear una Base de Datos ACCESS. Método CreateDatabase


Para crear una base de datos deberemos utilizar el método CreateDatabase. Previamente
debemos declarar el nombre que queremos dar al objeto DataBase que se va a crear como un
objeto Database :

Dim MiBaseDatos as Database

Si tenemos declarado un Workspace llamado Misesion mediante la declaración :

Dim Misesion as Workspace

Y hacemos que Misesion sea el Workspace creado automáticamente por VB

Set Misesion = Workspaces (0)

podremos usar el método del Workspace CreateDatabase para crear ese objeto Database.
Recuerde que el objeto Database NO es el fichero que va a contener la base de datos sino que
es una estructura de base de datos que está de momento en la memoria RAM del ordenador. El
fichero se creará posteriormente cuando cerremos el objeto Database. El nombre del objeto
Database tampoco tiene porque coincidir con el nombre del fichero que se va a crear. En el
ejemplo que veremos mas adelante, el nombre del objeto Database es MiBaseDatos y el
nombre del fichero es MiBase.Mdb.

La sintaxis del método CreateDataBase es el “juego de niños” citado antes:

Set ObjetoDAOInferior = ObjetoDAOSuperior.Método ( Parámetros )

En nuestro caso el Objeto DAO superior es el Workspace Misesion, y los parámetros que hay
que pasar en este caso son:

Nombre (y Path) del fichero de la base de datos

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 6


Idioma, para permitir la ordenación alfabética de los datos. Para los idiomas español, inglés y
francés debe usar dbLangGeneral.
Opciones, que le permite elegir la versión de la base de datos a crear (Equivalente a la versión
de Access) y si deseamos crear una base de datos cifrada. Si no pone nada en este parámetro
le crea una base de datos sin cifrar, y de la última versión que le permite la referencia elegida
para el motor de bases de datos (Microsoft DAO 3,51, por ejemplo)

Vayamos al ejemplo:

Set MiBaseDatos = Misesion.CreateDatabase (“C:\MiCarpeta\MiBase.MDB”, dbLangGeneral)

Si ahora cierra el programa le creará la Base en el disco. Ejecute Access y abra la BD


C:\MiCarpeta\MiBase.MDB. ¡Ya Existe! Pero observará que está completamente vacía. Es
normal. Una Base de Datos ACCESS tiene tablas. Y de momento no hemos escrito ningún
código para crear esas tablas. Vamos a seguir creando esta base de datos, al tiempo que
explicamos el resto de los procedimientos que hay que usar para ello.

El Método CreateDataBase Crea un nuevo objeto Database, guarda la base de datos en disco
y devuelve un objeto Database abierto.

Vaya a la ayuda de VB. Verá que la sintaxis de este método es:

Set MiBaseDatos = Misesion.CreateDatabase (nombre_base, escenario, opciones)

MiBaseDatos es el nombre del objeto Database por el cual nos referiremos a esa base de
datos, NO el nombre del archivo con el que quedará guardada en el disco.

Misesion es el nombre del objeto Workspace existente que contendrá la base de datos. Si se
omite este argumento, se utilizará el objeto Workspace predeterminado - Workspaces(0) – e
incluso, si no se pone nada, usará ese Workspace predeterminado.

nombre_base es el nombre del archivo de base de datos que se va a crear. Es decir, el


nombre del archivo en el disco. Puede ser una ruta completa y un nombre de archivo, como por
ejemplo "C:\MiCarpeta\MiBase.MDB". Si no se indica una extensión, se agregará .MDB. Si la
red lo admite, también puede especificar una ruta de red, como por ejemplo
"\\MISERVID\MICOMP\MIDIR\MIBD". Con este método sólo pueden crearse archivos de base
de datos .MDB. (ACCESS)

escenario es una expresión de cadena utilizada para especificar dos cosas: el orden alfabético
que se va a usar en esta base de datos, (Obligatorio) que denominaremos inf_local y el
Password o palabra clave que quiere usar para restringir su uso. Este Password es opcional.
Debe especificar el argumento inf_local o se producirá un error. Consulte la tabla de
constantes para inf_local incluida más adelante en este tema.

En el argumento Opciones puede combinar varias opciones, según se especifica a mas


adelante. Puede combinar varias opciones sumando las constantes correspondientes.

Valores de los parámetros

En el argumento inf_local se suministra información de la lengua empleada para especificar la


propiedad CollatingOrder del texto para las comparaciones entre cadenas. Es un argumento
obligatorio. Para los idiomas Inglés, alemán, francés, portugués, italiano y español moderno se
usa la siguiente constante :

dbLangGeneral

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 7


No use dbLangSpanish. pues no hace nada especial respecto a dbLangGeneral

Este parámetro es obligatorio. Piense que una vez creada la Base de Datos, alguna vez le
pedirá que le obtenga un Recordset con los datos ordenados alfabéticamente ( acuérdese de la
sentencia SQL ORDER BY Nombredelcampo )

Si desea introducir una palabra clave para restringir el acceso a la base de datos, debe indicarlo
a continuación. Deberá concatenarlo con la inf_local mediante el signo & y separarlo mediante
punto y coma. Hay que poner pwd antes de la contraseña

dbLangGeneral & ";pwd=NuevaContraseña"

Para el último parámetro, Opciones se pueden usar las siguientes constantes :

Constante Descripción

dbEncrypt Crea una base de datos codificada.


dbVersion10 Crea una base de datos que utiliza la versión 1.0 del motor de base de datos
Microsoft Jet.
dbVersion11 Crea una base de datos que utiliza la versión 1.1 del motor de base de datos
Microsoft Jet.
dbVersion25 Crea una base de datos que utiliza la versión 2.5 del motor de base de datos
Microsoft Jet.
dbVersion30 Crea una base de datos que utiliza la versión 3.0 del motor de base de datos
Microsoft Jet. Esta Versión es compatible con la 3.5

Si se omite la constante de codificación, se creará una base de datos no codificada.


El método CreateDataBase abre esta nueva base de datos y devuelve un objeto Database,
cuya estructura y contenido deberá completar utilizando objetos de acceso a datos adicionales.
Es decir, crea una Base de Datos sin nada que deberá rellenarla posteriormente con tablas.

(Advertencia sobre las bases de datos codificadas. No piense que al codificar la base de
datos va a mantener sus datos confidenciales en secreto. Access se los guardará codificados,
pero se los va a presentar de forma clara. Utilice para ello el Password, ya que no podrá abrir la
base si no se conoce ese Password. Pero tampoco se fíe mucho. Existen infinidad de
craqueadores de contraseñas de Access. El Password vale para proteger la BD de usuarios no
“piratas”. No emplee este procedimiento en aplicaciones en las que necesite verdadera
confidencialidad.

Objetos DAO para introducir en una base de datos

Estos objetos que se pueden añadir son : Objetos TableDef, TableDefs, Field, Fields,
QueryDef, QueryDefs. Para hacer las cosas poco a poco nos fijaremos solamente en las
tablas y los campos. (Objetos Tabledef y Field)

El Objeto TableDef es una tabla de una base de datos ACCESS. El Objeto TableDefs es la
colección que contiene todas las tablas de la base de datos

Un objeto Field representa un campo dentro de una tabla Access. La colección Fields contiene
todos los campos de una tabla. Verá mas adelante que también hay objetos Field en otros
objetos DAO (Index, QueryDef, Recordset, Relation), pero de momento vamos a fijarnos
solamente en las tablas.

Crear una Tabla. Método CreateTableDef.


Crea un objeto Tabledef, que no es ni más ni menos que la estructura de una tabla Access,
pero que de momento está en la memoria RAM del ordenador. Cuando esa estructura se pase
al fichero de la base de datos en el disco, será una Tabla que podemos ver cuando abramos la
BD con Access.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 8


El objeto Tabledef debe crearlo un objeto DataBase. Puede ser perfectamente el objeto
Database creado anteriormente. Pero seguramente lo ha cerrado (cerrando el programa,
simplemente) para poder ver con Access la base de datos que acaba de crear. Puede volver a
crear el objeto DataBase abriendo la base de datos. Aunque se le explicará mas tarde, le
adelanto el método para abrir una base de datos existente en el disco:

Set MiBaseDatos = Misesion.OpenDatabase (“C:\MiCarpeta\MiBase.MDB”)

Declaremos ahora el nombre que quiere ponerle al objeto Tabledef que va a crear: (MiTabla1)

Dim Mitabla1 As Tabledef

Si queremos introducir varias tablas en la BD deberemos declarar tantos objetos Tabledef como
tablas necesitemos:

Dim MiTabla2 as Tabledef, MiTabla3 as Tabledef, ……

y crearemos las tablas necesarias mediante el método CreateTableDef

Si acude a la información de VB para ver los parámetros que hay que pasar en el método
CreateTableDef verá que son muchos: ([nombre[, atributos[, origen[, conexión]]]]) Se explicará
para que sirven todos ellos, pero de momento nos quedamos únicamente con el primero:
Nombre, que es el nombre que podrá ver en Access como nombre de la tabla que va a crear.

Set Mitabla1 = MiBaseDatos.CreateTableDef (Nombre)

Ejemplo: Set Mitabla1 = MiBaseDatos.CreateTableDef (“Alumnos”)

Si queremos crear más Tabladefs:

Set Mitabla2 = MiBaseDatos.CreateTableDef (“Profesores”)


Set Mitabla3 = MiBaseDatos.CreateTableDef (“Asignaturas”)

De momento solamente hemos creado uno o varios objetos Tabledef. Pero como siempre,
vacíos. Una tabla tiene campos. Un objeto Tabledef tiene Fields. Debemos crear objetos Field
(Campos) para poder meterlos en los objetos Tabledef que acabamos de crear.

Crear campos. Método CreateField


Crea un objeto Field, que es la estructura de lo que mas tarde será un Campo de una tabla de
la BD. El objeto Field solamente está en la memoria RAM del ordenador. Cuando pase a formar
parte de una tabla será un campo de esa tabla.

El objeto Field debe crearlo el objeto DAO superior a él: el Tabledef. Previamente declararemos
los nombres de los Objetos Field a introducir.

Dim MiCampo11 as Field, MiCampo121 as Field, MiCampo21 as Field

(El Campo11 es el primer campo que meteremos en el Tabledef Tabla1. El Campo12 el


segundo, el Campo21 será el primer campo del Tabledef Tabla2, etc.

Los parámetros que vamos a pasar en este método son:

Nombre Será el nombre de ese campo. P.e. NombreAlumno, Apellidos, etc


Tipo Tipo de dato, String, numérico, Date, etc
Tamaño Sólo para los campos String. Indicará el número de caracteres de ese campo.

Creamos el objeto Field con la siguiente sintaxis

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 9


Set MiCampo11 = Mitabla1.CreateField ([nombre[, tipo [, tamaño]]])

(Vea el Anexo 1 Propiedades de los campos al final de este capítulo)

Ejemplos
Set MiCampo11 = Mitabla1.CreateField (“ID_Alumno”, dbText, 8)
Set MiCampo12 = Mitabla1.CreateField (“NombreAlumno”, dbText, 20)
Set MiCampo13 = Mitabla1.CreateField (“Apellidos”, dbText, 25)
Set MiCampo14 = Mitabla1.CreateField (“Edad”, dbInteger)
Set MiCampo15 = Mitabla1.CreateField (“Fecha_Ingreso”, dbDate)

Set MiCampo21 = Mitabla2.CreateField (“NombreProfesor”, dbText, 20)

Se crean todos los campos que se quieren introducir en las tablas. Observe que cada objeto
Field debe ser creado por el objeto Tabledef que lo va a contener. (MiTabla1 crea todos sus
campos, MiTabla2 los suyos, etc)

Ya están todos los campos creados, pero todavía no están metidos en las tablas. Tenemos que
añadirlos a la colección de campos de la tabla que los creó. Esa colección de campos es el
Objeto Fields de la tabla. Se añade mediante el método Append.

MiTabla1.Fields.Append Micampo11
MiTabla1.Fields.Append Micampo12
MiTabla1.Fields.Append Micampo13
MiTabla1.Fields.Append Micampo14
MiTabla1.Fields.Append Micampo15

MiTabla2.Fields.Append Micampo21

Ya tenemos campos formando parte de la colección Fields de las tablas. Ahora debemos añadir
las tablas a la colección de tablas de la base de datos. Esa colección de tablas es el objeto
Tabledefs de la base de datos, es decir, del objeto DataBase. Lo haremos también mediante el
método Append

MiBaseDatos.TableDefs.Append Mitabla1
MiBaseDatos.Tabledefs.Append Mitabla2

Si ahora cerramos la base de datos mediante el método Close:

MiBaseDatos.Close

Ya tenemos la base de datos creada en el disco de la misma forma que lo hubiera hecho
Access. Pero puede que le falte algo respecto a una base creada directamente con Access: los
Indices y las Relaciones.

Un índice es una marca que le podemos poner a cada uno de los registros en un campo. Esa
marca puede servir por ejemplo, para ordenar los registros de la BD por ese campo. Puede
servir también para evitar que dos registros tengan el mismo valor para un determinado campo.
En el ejemplo que estamos preparando, el Campo11 (ID_Alumno) queremos que sea un índice,
y además que no se pueda repetir el mismo valor para dos registros distintos, de forma que no
puedan existir dos registros con el mismo valor en ese campo.

Una Relación es una correspondencia entre un campo de una tabla y otro campo de
características similares en otra tabla. Esto nos lleva al concepto de Base de Datos Relacional
que seguramente ya sabe de que se trata. En Access se puede establecer una relación de una
forma muy sencilla. En Visual Basic también. Pero antes de seguir reflexionemos y recordemos
lo que hemos hecho hasta ahora.

Observe que, cada vez que creamos un objetos (DataBase, Tabledef, Field) usamos el
mencionado “juego de niños”. El método correspondiente para crear un objeto DAO pertenece

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 10


al objeto DAO inmediatamente superior en jerarquía, es decir, CreateDatabase es un método
del objeto Workspace, CreateTableDef es un método del objeto Database, CreateField es un
método del objetos TableDef.

Las colecciones pertenecen también al objeto inmediatamente superior en jerarquía al tipo de


objetos que forman la colección. La colección Fields (Objeto Fields) pertenece a un objeto
TableDef, la colección TableDefs (objeto TableDefs) pertenece a un objeto Database, y la
colección Databases (Objeto Databases) pertenece a un objeto Workspace. La colección
Workspaces pertenece al DBEngine, y el DBEngine ya no podemos asignarlo a ningún objeto
DAO. Tendremos que decir que pertenece al sistema.

Recordemos ese “juego de niños” :

Set DAOInferior = DAOSuperior.Método ( - - - - - -)

Hemos visto que después de crear un objeto, debemos añadirlo a la colección a la que debe
pertenecer con el método Append. El procedimiento es siempre el mismo :

Objeto superior.Colección.Append Objeto a añadir

Sigamos ahora perfeccionando la base de datos. Vamos a ver como se crea un Indice.

Crear Indices para los campos. Método CreateIndex


Para crear un índice debe estar creado el campo al que se le va a aplicar el índice. Puede que
le parezca un poco extraño alguno de los métodos que vamos a usar para crear un índice,
como por ejemplo volver a usar el procedimiento CreateField para crear un campo que ya
existe. Son las incongruencias que tiene a veces Visual Basic. Le recomiendo que si no se
acuerda bien de cómo se hace, recurra a la ayuda de VB, que en este caso es exacta y concisa.
O si lo prefiere, al ejemplo que ilustra esta Guía del Estudiante como colofón a este capítulo.

Primer debemos crear el Objeto Index. Se hace mediante el método del objeto Tabledef,
CreateIndex. El índice debe crearlo el Tabledef al que pertenece el campo que queremos que
sea índice. La sintaxis de CreateIndex es:

Set NombreIndice = NombreTabledef.CreateIndex([Nombre])

Donde NombreIndice es el nombre de una variable declarada como tipo de dato objeto Index.
NombreTabledef es el nombre de variable del objeto TableDef que se desea usar para crear el
nuevo objeto Index.
Nombre es una variable de tipo String que da un nombre único al nuevo objeto Index. Este
nombre lo puede ver si abre la base de datos con Access y en la vista de Diseño de la tabla,
abre la función Ver | Indices de la barra de menú.

En nuestro ejemplo:

Declaramos el objeto Index

Dim MiIndice as Index

Creamos el índice

Set MiIndice = MiTabla1.CreateIndex (“Indice1”)

Ya tenemos creado el Objeto Index. Ahora, (y aquí empieza la incongruencia citada) este objeto
Index debe crear el campo que queremos que sea índice. Pero ese campo ya debe existir en el
objeto Tabledef con el que hemos creado el índice (en este caso, en MiTabla1)

Set MiCampo11 = MiIndice.CreateField (“ID_Alumno”, dbText, 8)

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 11


El nombre del campo, tipo y tamaño deben coincidir con los datos que sirvieron para crear el
campo en el objeto Tabledef.

Pero un índice puede tener varios campos. Por ejemplo, piense en el código de un objeto en un
inventario. El código es el número que identifica de forma unívoca a un objeto. Un objeto
inventariable (por ejemplo una mesa) tiene un código de grupo (por ejemplo, el 123) Hay
muchas mesas dentro de un inventario, pero todas ellas tienen un número distinto (una tiene el
001, otra el 002, etc) La combinación de código de grupo más el número del objeto dentro de
ese grupo queremos que sea un índice. Ese índice estará formado entonces por dos campos.
En este caso deberemos crear los dos campos:

Set MiCampo11 = MiIndice.CreateField (“C_Grupo”, dbText, 3)


Set MiCampo12 = MiIndice.CreateField (“Numero”, dbText, 3)

Ya tenemos el campo o los campos creados por el índice. Ahora debemos añadirlo (o
añadirlos) a la colección Fields del objeto Index recién creado. Lo hacemos mediante el
método Append

MiIndice.Fields.Append MiCampo11

Si fuesen dos los campos

MiIndice.Fields.Append MiCampo11
MiIndice.Fields.Append MiCampo12

No crea que ya hemos terminado. Un objeto Index tiene propiedades. Una de ellas ya la hemos
visto sin querer, la propiedad Name (nombre del índice, en nuestro ejemplo, Indice1). Otras
propiedades son:

Primary - El objeto Index representa la clave primaria de la tabla.


Unique - No permite repetición de valores en ese campo
Required - Indica que todos los campos del objeto Index deben rellenarse.
IgnoreNulls - Indica si permite valores Nulos en los campos del índice.

(Existen además las propiedades Clustered, Foreign, DistinctCount que no se explican para
no complicar mas el tema. Cuando los necesite no tendrá inconveniente en estudiarlos
partiendo de la ayuda de VB)

Para introducir el valor de una de estas propiedades se procede con la siguiente sintaxis:

MiIndice.Uniuqe = True
MiIndice.Primary = True

Ya está creado el índice y tiene ya metido uno o mas campos y todas sus propiedades. Ahora
debemos añadir ese índice a la colección Indexes del Objeto Tabledef.

MiTabla1.Indexes.Append MiIndice

Lo confieso. Cada vez que hago esto en la vida real tengo que volver a leer este procedimiento
en la Guía del Estudiante. Es complicado, pero alguna vez se terminará aprendiendo.

Ya tenemos la base de datos completamente creada. Sin embargo alguien dirá que le falta algo:
Relacionar dos tablas

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 12


Relaciones entre tablas Método CreateRelation
Una Relación es una asociación establecida entre dos campos del mismo tipo ubicados en dos
tablas distintas. Se pueden establecer relaciones uno a uno ó uno a varios. Para relacionar un
campo con otros, ese campo debe ser clave primaria. A la tabla que contiene a este campo se
le llama Tabla Principal. A la tabla que contiene el campo (o los campos) relacionados se le
llama Tabla Relacionada.

Para crear una relación, usaremos un nuevo objeto DAO : El objeto Relation. Este objeto forma
parte de una colección, que es a su ves otro objeto DAO : el objeto Relations.

Para crear una relación usaremos el Método CreateRelation, que es un método del objeto
Database. (Lógico, una relación se establece entre dos tablas. Por lo tanto, la relación debe
pertenecer al objeto DAO superior jerárquicamente a las tablas: el Objeto Database. Como para
cualquier otro objeto DAO, es necesario declararlo :

Dim MiRelacion as Relation

Para crear la relación deberemos usar el método CreateRelation

Set MiRelacion = MiBaseDatos.CreateRelation ("RelacionUno")

Una relación se hace entre dos campos. Una relación debe tener campos. Por lo tanto,
deberemos hacer una cosa similar a la que hacíamos para el método CreateIndex, crear los
campos mediante el Objeto Relation que acabamos de crear. Pero esos campos ya deben
estar creados en las tablas que se van a relacionar.

Supongamos que queremos crear una relación en la base de datos creada en el ejemplo
anterior, y queremos relacionar el campo Campo11 que está en MiTabla1 y que lo habíamos
hecho clave primaria, con el campo Campo21 de MiTabla2. MiTabla1 y MiTabla2 son los
nombres reales de las tablas, NO los nombres de los objetos Tabledef.

El ejemplo que trae la ayuda de VB puede ser muy aclaratorio, pero le advertimos lo mismo que
para los índices, paciencia. Una vez creada la relación, podrá comprobarlo visualizándola con
el visor de relaciones del Access

Suponemos que la base de datos está abierta. Si no lo está, la abrimos.

Set MiBaseDatos = Workspaces(0).OpenDatabase("MIBD.MDB")

Creamos el objeto Relation, que tendrá por nombre RelacionUno, pero este nombre NO debe
confundirse con el nombre del objeto DAO Relation, que es MiRelacion

Set MiRelacion = MiBaseDatos.CreateRelation ("RelacionUno")

Una vez creada, le decimos a MiRelacion cual es la Tabla principal

MiRelación.Table = "MiTabla1" 'Nombre de la tabla principal.

Le decimos cual es el nombre de la tabla relacionada

MiRelación.ForeignTable = "MiTabla2" ‘Nombre de la tabla relacionada

Le ponemos los atributos a la relación. En este caso dbRelationUpdateCascade, para que, si


hacemos un cambio en el valor del campo de la tabla principal, ese cambio se refleje en el
campo o los campos relacionados con el.

MiRelación.Attributes = dbRelationUpdateCascade

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 13


Le decimos cual es el nombre del campo de la tabla principal que vamos a relacionar, mediante
el método CreateField. Deberemos declarar el nombre del objeto Field que vamos a crear para
la relación

Dim MiCampo as Field

Set MiCampo = MiRelación.CreateField("Campo11")

Le recordamos lo de antes. Campo11 debe estar ya creado en la tabla Tabla1. Parece un poco
ilógico usar el método CreateField para un campo que ya está creado.

Le decimos ahora cual es el nombre del campo en la tabla relacionada

MiCampo.ForeignName = "Campo21"

Añadimos el campo creado a la colección Fields del objeto Relation

MiRelación.Fields.Append MiCampo

Y ahora añadimos el objeto Relation recién creado a la colección Relations del objeto Database

MiBaseDatos.Relations.Append MiRelación

Solamente nos falta ver que valores puede tener la propiedad Attributes del objeto Relation

dbRelationUnique La relación es uno a uno.


dbRelationDontEnforce La relación no es impuesta (no hay integridad referencial).
dbRelationInherited La relación existe en una base de datos no activa que contiene
las dos tablas vinculadas.
dbRelationUpdateCascade Las actualizaciones se realizarán en cascada.
dbRelationDeleteCascade Las eliminaciones se realizarán en cascada.

Ahora ya casi podemos decir que tenemos la base de datos creada. Puede que sea así o que le
falte alguna cosa. Puede faltarle una o varias consultas. Las consultas también se pueden crear
mediante objetos DAO. Precisamente con un objeto QueryDef

Consultas. El Objeto QueryDef


Pero habrá observado que una base de datos ACCESS puede contener, además de tablas,
CONSULTAS. Las consultas no contienen datos. Contienen una referencia a los registros de
las tablas que los contienen. Una consulta podríamos decir que son conjuntos de registros
tomados de una o varias tablas (en este último caso, esas tablas deben estar relacionadas) que
cumplen unas determinadas condiciones. Pero aunque podemos ver esos registros como tales,
con sus datos exactamente igual que si se tratase de los registros de una tabla, las consultas
no contienen el dato, sino el número del registro dentro de la tabla que lo contiene. A la hora de
presentar los datos de una consulta, lo que estamos presentando son los datos almacenados
en la tabla o las tablas que componen esa consulta.

Crear una consulta. Método CreateQueryDef


Un objeto QueryDef representa una consulta de la base de datos. El objeto QueryDefs es la
colección de objetos QueryDef. La diferencia entre una consulta (Un QueryDef) y una tabla (Un
TableDef) es que la Tabla tiene dentro de sí los datos. La consulta tiene dentro una referencia
al lugar de las tablas donde se encuentran los datos.

Antes de utilizar el método CreateQueryDef debe declarar el nombre de los objetos a crear,
declarándolos como Variables Objeto tipo QueryDef . El ámbito es igual que para cualquier
variable:

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 14


Public MiConsulta1 as QueryDef
Public MiConsulta2 as QueryDef

Ahora podemos utilizar el método CreateQueryDef para crear el nuevo objeto QueryDef en la
base de datos.

Sintaxis Con la fórmula de siempre :

Set MiConsulta1 = MiBaseDatos.CreateQueryDef ([Nombre][, Texto_sql])

Donde

MiConsulta1 es una variable del tipo QueryDef que previamente se ha declarado como tal.
Será el nombre por el que llamemos al Objeto QueryDef en el código de nuestra aplicación.
MiBaseDatos es el nombre del objeto Database abierto en el que vamos a introducir el nuevo
objeto QueryDef.
Nombre es una expresión de cadena que representa el nombre de la nueva consulta que
vamos a crear. Este nombre será el que veamos al abrir la base de datos con Access en la
pestaña Consultas. Puede omitirlo a la hora de crear la consulta, pero deberá añadirselo
posteriormente.
Texto_sql es una expresión de cadena (instrucción SQL válida) que define el objeto QueryDef.
Lógicamente una consulta nos debe suministrar una serie de datos de una o mas tablas. Esos
datos no tienen porqué ser todos los datos de las tablas. Texto_sql es precisamente el filtro de
esos datos (expresado mediante una cláusula SQL).

Una vez creado el objeto QueryDef, no es necesario añadirlo a la colección QueryDefs de la


Base de Datos, excepto que hayamos creado el objeto QueryDef sin nombre. (Sin haber puesto
el parámetro Nombre, según se comentó mas atrás). Para añadirlo a la colección QueryDefs :

MiBaseDatos.QueryDefs.Append MiConsulta1

Como caso práctico de creación de una consulta, podemos tener

Set MiConsulta1 = MiBaseDatos.CreateQueryDef (“Fernandez”, “Select Nombre,


Apellido1, Apellido2 From Alumnos Where Apellido1 = ‘Fernandez’ )

Ahora ya tenemos la base de datos creada con todas las posibilidades. Ha llegado el momento
de crear una base real para comprobar todo lo expuesto.

Ejemplo práctico de creación de una base de datos. El famoso


ejercicio del Videoclub
Vayamos a un ejemplo típico en cualquier curso de Visual Basic: el famoso Videoclub. Un
videoclub tiene una base de datos en la que tenemos una tabla, de nombre Clientes donde
figuran los nombres y dirección de los clientes, así como el número de su cuenta bancaria.
Tiene un campo (ID_Cliente) que es el que define al cliente. Será un campo tipo texto, que
albergará un número que se incrementará en 1 cada vez que se hace un nuevo cliente. Cada
cliente tiene un ID_Cliente y ese ID_Cliente es único para él. (Este campo podría ser un
autonumérico, pero personalmente no me gusta usar autonuméricos. Un autonumérico es un
Long –numérico- y quiero ser coherente con lo expuesto en el capítulo 1 donde se decía que
solamente se usarían campos numéricos en aquellos datos con los que se hagan operaciones
matemáticas) El campo ID_Cliente será clave primaria, ya que no pueden existir dos clientes
con el mismo ID_Cliente.

Otra tabla necesaria será la tabla Peliculas, donde introduciremos todos los datos relativos a
las películas (existentes o no en el videoclub), tal como título, director, artistas, resumen,
calificación, precio, etc. Tendrá un campo, ID_Pelicula que identificará a esa película. Pero
puede haber versiones en varios idiomas, por lo tanto, existirá otro campo Idioma de tipo texto,

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 15


para introducir ese dato. Por lo tanto, una película deberemos definirla por el conjunto formado
por su ID_Pelicula y por su Idioma. El conjunto de esos dos campos será la clave primaria. (Si
cree que hay campos que no tienen sentido en esta tabla (Idioma), piense que esto es un
ejemplo para poder explicar de la forma más didáctica todas las posibles variaciones de una
instrucción)

Existe otra tabla denominada Cintas, donde figurarán todas las cintas existentes en el
videoclub. Para poder relacionarla con la tabla Peliculas, le ponemos un campo llamado
ID_Pelicula que en esta tabla no será clave primaria. También le pondremos el campo Idioma,
sobre el que no haremos ningún tipo de relación. Tendrá un campo ID_Cinta que será la
combinación de varios datos, uno que nos indique la película que tiene grabada esa cinta (Será
la combinación de los campos ID_Pelicula e Idioma) y de un número secuencial que indicará el
número de la copia. Si le pone imaginación y este conjunto de datos puede meterse en un
código de barras, le facilitará la operación de alquiler y devolución. En este ejercicio haremos
que sea así, dándole a este campo un tamaño de 13 dígitos para poder meterlo en un código
EAN-13. Podemos añadirle mas campos a nivel administrativo, como fecha de alta, fecha de
baja, precio de esta copia, etc.

Existirá una tercera tabla, Alquileres, que relacionará al cliente con la cinta que ha alquilado.
Tendrá un campo llamado ID_Cliente y otro ID_Cinta. Aparte tendrá otros dos campos, fecha de
alquiler y fecha de devolución.

La base de datos deberá tener dos relaciones, una, entre el campo ID_Cliente de la tabla
Clientes y el campo ID_Clientes de la tabla alquileres (Será uno a infinito) y otra relación, entre
el campo ID_Cinta de la tabla Cintas y el campo ID_Cinta de la tabla Alquileres (Relación 1 a 1
ya que solamente existe una cinta con esa ID_Cinta). Para darle más alegría al ejercicio le
pondremos una relación entre los campos ID_Pelicula e Idioma de las tablas Peliculas y Cintas.
(Se ha puesto el nombre de Pelicula al campo relacionado con ID_Pelicula para que se vea que
dos campos relacionados no tienen porqué tener el mismo nombre. Eso sí, deben tener las
mismas características)
Como colofón a todo esto, crearemos una consulta en la que utilizaremos todas las relaciones.

Para llevar a cabo este ejercicio se ha partido de una interface gráfica en la que pueden verse
tres botones (Borrar la base de datos, crearla y salir) y un TextBox donde se ha puesto el
nombre del fichero de la base de datos en su propiedad Text. Veamos el código de cada uno de
los botones (por orden inverso de complejidad del código)

Fig. 20.3 Interface gráfica de la parte de crear bases de datos para la aplicación del Videoclub

CODIGO

Private Sub BSalir_Click()


Unload Me
End Sub

Private Sub BBorrar_Click()


On Error GoTo RutErr
Dim HayDir As String
HayDir = Dir(TBNombreBase)
If HayDir <> "" Then
Kill TBNombreBase
End If

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 16


RutErr:
If Err = 75 Then
MsgBox "Tiene la Base de Datos abierta por otro programa"
End If
End Sub

Creación de la base de datos

Private Sub BCrear_Click()


On Error GoTo RutErr

Dim HayDir As String ‘Se comprueba que existe la BD y se invita a borrarla


HayDir = Dir(TBNombreBase)
If HayDir <> "" Then
MsgBox "Ya existe el fichero con la base de datos. Debe borrarlo previamente"
Exit Sub
End If

‘ Se declaran todas las variables tipo objeto


Dim MiBaseDatos As Database
Dim MiTabla1 As TableDef, MiTabla2 As TableDef, MiTabla3 As TableDef
Dim MiTabla4 As TableDef
Dim MiCampo11 As Field, MiCampo12 As Field, MiCampo13 As Field
Dim MiCampo14 As Field, MiCampo15 As Field, MiCampo21 As Field
Dim MiCampo22 As Field, MiCampo23 As Field, MiCampo24 As Field
Dim MiCampo25 As Field, MiCampo31 As Field, MiCampo32 As Field
Dim MiCampo33 As Field, MiCampo34 As Field, MiCampo35 As Field
Dim MiCampo36 As Field, MiCampo41 As Field, MiCampo42 As Field
Dim MiCampo43 As Field, MiCampo44 As Field

‘Se crea el Objeto DataBase (Se toma el nombre del fichero del TextBox TBNombreBase
Set MiBaseDatos = Workspaces(0).CreateDatabase(TBNombreBase, dbLangGeneral)

‘Se crean los Objetos Tabledef


Set MiTabla1 = MiBaseDatos.CreateTableDef("Clientes")
Set MiTabla2 = MiBaseDatos.CreateTableDef("Peliculas")
Set MiTabla3 = MiBaseDatos.CreateTableDef("Cintas")
Set MiTabla4 = MiBaseDatos.CreateTableDef("Alquileres")

‘Cada Tabledef crea sus propios Objetos Field


Set MiCampo11 = MiTabla1.CreateField("ID_Cliente", dbText, 8)
Set MiCampo12 = MiTabla1.CreateField("Nombre", dbText, 20)
Set MiCampo13 = MiTabla1.CreateField("Apellidos", dbText, 50)
Set MiCampo14 = MiTabla1.CreateField("Direccion", dbText, 50)
Set MiCampo15 = MiTabla1.CreateField("Telefono", dbText, 15)

Set MiCampo21 = MiTabla2.CreateField("ID_Pelicula", dbText, 8)


Set MiCampo22 = MiTabla2.CreateField("Titulo", dbText, 20)
Set MiCampo23 = MiTabla2.CreateField("Idioma", dbText, 1)
Set MiCampo24 = MiTabla2.CreateField("Director", dbText, 25)
Set MiCampo25 = MiTabla2.CreateField("Resumen", dbText, 255)

Set MiCampo31 = MiTabla3.CreateField("ID_Cinta", dbText, 13)


Set MiCampo32 = MiTabla3.CreateField("Pelicula", dbText, 20)
Set MiCampo33 = MiTabla3.CreateField("Idioma", dbText, 1)
Set MiCampo34 = MiTabla3.CreateField("Precio", dbSingle)
Set MiCampo35 = MiTabla3.CreateField("Fecha_Alta", dbDate)
Set MiCampo36 = MiTabla3.CreateField("Fecha_Baja", dbDate)

Set MiCampo41 = MiTabla4.CreateField("ID_Cliente", dbText, 8)


Set MiCampo42 = MiTabla4.CreateField("ID_Cinta", dbText, 13)

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 17


Set MiCampo43 = MiTabla4.CreateField("Fecha_Alq", dbDate)
Set MiCampo44 = MiTabla4.CreateField("Fecha_Dev", dbDate)

‘Una vez creados los campos se les ponen las peopiedades que se estime oportuno
‘En este caso, se ha puesto la propiedad AllowZeroLength (Permitir valores nulos en ese
‘campo) a lo que interesa en cada uno de los campos. Nota Tenga presente que por defecto le
‘va a dejar el campo que NO permite valores nulos, circunstancia que le va a crear problemas.

MiCampo12.AllowZeroLength = True
MiCampo13.AllowZeroLength = False
MiCampo14.AllowZeroLength = True
MiCampo15.AllowZeroLength = True

‘Se añaden los campos a la colección Fields de las tablas


MiTabla1.Fields.Append MiCampo11
MiTabla1.Fields.Append MiCampo12
MiTabla1.Fields.Append MiCampo13
MiTabla1.Fields.Append MiCampo14
MiTabla1.Fields.Append MiCampo15

MiTabla2.Fields.Append MiCampo21
MiTabla2.Fields.Append MiCampo22
MiTabla2.Fields.Append MiCampo23
MiTabla2.Fields.Append MiCampo24
MiTabla2.Fields.Append MiCampo25

MiTabla3.Fields.Append MiCampo31
MiTabla3.Fields.Append MiCampo32
MiTabla3.Fields.Append MiCampo33
MiTabla3.Fields.Append MiCampo34
MiTabla3.Fields.Append MiCampo35
MiTabla3.Fields.Append MiCampo36

MiTabla4.Fields.Append MiCampo41
MiTabla4.Fields.Append MiCampo42
MiTabla4.Fields.Append MiCampo43
MiTabla4.Fields.Append MiCampo44

‘Se añaden las tablas a la colección Tabledefs del objeto Database


MiBaseDatos.TableDefs.Append MiTabla1
MiBaseDatos.TableDefs.Append MiTabla2
MiBaseDatos.TableDefs.Append MiTabla3
MiBaseDatos.TableDefs.Append MiTabla4

‘Se declaran las variables tipo objeto Index y tipo objeto Field para crear los índices
Dim MiIndice1 As Index, MiIndice2 As Index, MiIndice3 As Index
Dim CampoIndiceA As Field
Dim CampoIndiceB As Field

‘Se crea el primer objeto Index


Set MiIndice1 = MiTabla1.CreateIndex("IndiceCliente")
‘Este objeto Index crea el campo que va a ser índice, con los mismos datos que el
‘campo MiCampo11
Set CampoIndiceA = MiIndice1.CreateField("ID_Cliente", dbText, 8)
‘Se añade el campo a la colección Fields del Index
MiIndice1.Fields.Append CampoIndiceA
‘Se le dice que es un índice primario (Clave primaria)
MiIndice1.Primary = True
‘Se añade el objeto Index recién creado a la colección Index del objeto tabledef
MiTabla1.Indexes.Append MiIndice1

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 18


‘Se procede de igual forma con el segundo objeto Index
Set MiIndice2 = MiTabla2.CreateIndex("IndicePeliculas")
‘Aquí se meten dos campos en el mismo índice
Set CampoIndiceA = MiIndice2.CreateField("ID_Pelicula", dbText, 10)
Set CampoIndiceB = MiIndice2.CreateField("Idioma", dbText, 1)
MiIndice2.Fields.Append CampoIndiceA
MiIndice2.Fields.Append CampoIndiceB
MiIndice2.Primary = True
MiTabla2.Indexes.Append MiIndice2

Set MiIndice3 = MiTabla3.CreateIndex("IndiceCintas")


Set CampoIndiceA = MiIndice3.CreateField("ID_Cinta", dbText, 13)
MiIndice3.Fields.Append CampoIndiceA
MiIndice3.Primary = True
MiTabla3.Indexes.Append MiIndice3

‘Se declaran los objetos Relation y un par de objetos Field para crear las relaciones. Por
‘claridad se han declarado objetos Field distintos para la creación de los índices y de las
‘relaciones, pero podrían haber sido los mismos
Dim MiRelacion1 As Relation, MiRelacion2 As Relation, MiRelacion3 As Relation
Dim CampoRelacionA As Field
Dim CampoRelacionB As Field

‘Se crea la primera relación entre el campo ID_Clientes de la tabla Clientes (Tabla
‘primaria) y el campo ID_Cliente de la tabla Alquileres (Tabla relacionada)
Set MiRelacion1 = MiBaseDatos.CreateRelation("RelClientes", "Clientes", "Alquileres")
Set CampoRelacionA = MiRelacion1.CreateField("ID_Cliente", dbText, 8)
CampoRelacionA.ForeignName = "ID_Cliente"
MiRelacion1.Fields.Append CampoRelacionA
MiBaseDatos.Relations.Append MiRelacion1

‘Se crea la segunda relación


Set MiRelacion2 = MiBaseDatos.CreateRelation("RelCintas", "Cintas", "Alquileres")
MiRelacion2.Attributes = dbRelationUnique
Set CampoRelacionA = MiRelacion1.CreateField("ID_Cinta", dbText, 13)
CampoRelacionA.ForeignName = "ID_Cinta"
MiRelacion2.Fields.Append CampoRelacionA
MiBaseDatos.Relations.Append MiRelacion2

‘La tercera relación “relaciona” dos campos, Película e Idioma


Set MiRelacion3 = MiBaseDatos.CreateRelation("RelCintasPelis", "Peliculas", "Cintas")
Set CampoRelacionA = MiRelacion1.CreateField("ID_Pelicula", dbText, 8)
Set CampoRelacionB = MiRelacion1.CreateField("Idioma", dbText, 8)
CampoRelacionA.ForeignName = "Pelicula"
CampoRelacionB.ForeignName = "Idioma"
MiRelacion3.Fields.Append CampoRelacionA
MiRelacion3.Fields.Append CampoRelacionB
MiBaseDatos.Relations.Append MiRelacion3

‘Se comienza a crear una consulta (La sentencia SQL está cortada dado que no cabe en
‘una línea. El signo à indica que esa línea continúa en la siguiente
Dim MiConsulta1 As QueryDef
Set MiConsulta1 = MiBaseDatos.CreateQueryDef("Pelis", "SELECT Clientes.Nombre, à
Clientes.Apellidos, Clientes.Telefono, Peliculas.Titulo, Alquileres.ID_Cinta " & _
" FROM Peliculas INNER JOIN (Clientes INNER JOIN (Cintas INNER JOIN Alquileres ON à
Cintas.ID_Cinta = Alquileres.ID_Cinta) " & _
" ON Clientes.ID_Cliente = Alquileres.ID_Cliente) ON (Peliculas.Idioma = Cintas.Idioma) AND à
(Peliculas.ID_Pelicula = Cintas.Pelicula)" & _

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 19


" WHERE (((Alquileres.ID_Cinta)='0000000000001'));")

‘Se cierra la el objeto database. En este momento es cuando se crea el fichero.


MiBaseDatos.Close

‘se comunica al usuario la buena nueva de que la base ha sido creada.


MsgBox "La base de datos se ha creado con éxito"

‘Aquí comienza la rutina de error


Exit Sub
RutErr:
MsgBox "Ha ocurrido el error " & Err & ". " & Err.Description

End Sub

Nota acerca de la sentencia SQL para crear la consulta.


Se puede ser muy experto en SQL y tener miedo a crear una consulta SQL debido a la
complejidad que puede tener. No crea que el autor ha escrito la sentencia SQL que ha visto. Ha
utilizado el truco de crear primero la consulta con Access, de la forma gráfica que seguro que
Vd. conoce, ha comprobado que era eso lo que quería, pasó a Vista SQL y la copió. Es muy
bueno hacer prácticas con SQL, para que no se olvide. Pero en algunos casos es preferible
acudir a los trucos que nos proporcionan nuestras herramientas.

El resultado de todo esto podemos verlo si abrimos la base de datos con Access

Fig. 20.4 Tablas de la BD de Videoclub creada con el código descrito

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 20


Fig. 20.5 Y la consulta

Fig. 20.6 Clave Primaria formada con los dos campos de la tabla Películas

Fig. 20.7 Propiedades de esa clave primaria

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 21


Fig. 20.8 Las relaciones creadas

Crear bases de datos con contraseña


Imagínese que quiere que su base de datos no se pueda abrir mediante Access. Lo que debe
hacer es crearla con una contraseña (Password) de forma que cuando la quiera abrir, le pida el
Password. Si no lo sabe, no se puede abrir. Si crea una base de datos con estas
características, y no comunica el Password a nadie, solamente la podrá abrir mediante el
programa. (Eso sí, el programa para abrirla, deberá introducir en su instrucción de apertura el
Password con el que se creó.)

Si volvemos a la línea donde creabamos la base de datos del videoclub:

Set MiBaseDatos = Workspaces(0).CreateDatabase(TBNombreBase, dbLangGeneral)

Basta con añadirle ";pwd=PaswordElegido" concatenándolo tras el parámetro que especifica la


lengua. En el ejemplo siguiente hemos usado como Password las iniciales LSB

Set MiBaseDatos =
= Workspaces(0).CreateDatabase(TBNombreBase, dbLangGeneral & ";pwd=LSB")

Cuando lleguemos a la parte de abrir bases de datos, explicaremos cómo se abre una base de
datos con contraseña. Y no crea que ha conseguido la confidencialidad total de sus datos.
Existen programas que puede bajarse de Internet que le leen la contraseña con la que ha
protegido su base. No es una protección total, pero sí suficiente para que un usuario “normal”
no se la pueda abrir.

Crear bases de datos encriptada


Puede encriptar el fichero de su base de datos. Solamente le será útil para que no puedan ver
el contenido del fichero .MDB, ya que si se abre con Access, le presentará los datos de forma
correcta. Para encriptar una base de datos basta con añadir la palabra dbEncrypt en la
instrucción donde ha creado la BD

Set MiBaseDatos = Workspaces(0).CreateDatabase(TBNombreBase,dbLangGeneral & ";pwd=LSB", dbEncrypt)

Ha merecido la pena el trabajo. Hemos creado la base de datos haciendo click en un botón de
la aplicación. No ha sido necesario venderle al cliente Access, ni enviar una base de datos
vacía con los discos de distribución. Además hemos controlado todos los parámetros de los
campos de nuestra BD. Merece la pena crearse las bases de datos por programa.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 22


Anexo1
Propiedades de los campos
Ha visto mas atrás que puede ser necesario cambiar las propiedades de los campos una vez
creados (Por ejemplo, MiCampo13.AllowZeroLength = False) Alargaríamos demasiado este ya
largo capítulo si se explican todos los las propiedades que puede tener un campo. Añada un
poco de esfuerzo a su estudio y vea las propiedades de los objetos Field en la ayuda. Le reseño
aquí las que he considerado mas importantes

AllowZeroLength Si/NO Si es Si permite que ese campo tenga valores nulos


DataUpdatable Si/No Si es Si permite modificar el dato de ese campo. No tiene aplicación a la
hora de crear un campo. Sí puede cambiar el valor de esta propiedad por ejemplo, cuando crea
un recordset.

DefaultValue Es el valor que le pone a ese campo si no introduce ninguno. Puede indicar un
valor a la hora de crear el campo:

Campo14.DefaultValue = “Madrid”

Required Si/No Indica si el dato es requerido. En caso de que tome el valor SI (True) es
necesario introducir un dato en ese campo

Value Es justamente el dato que almacena en ese campo. Es la propiedad por defecto del
objeto Field.

Propiedades Type, Attributes y Size referidas a los campos

En el método CreateField debe introducir el tipo del campo que desea crear. (Como puede ver
mas atrás, con esta sintaxis p.e.: CreateField("Fecha_Alq", dbDate) Ese tipo coincide con la
propiedad Type aplicada a los campos. La propiedad Size solamente tendrá que aplicarla
cuando vaya a crear un campo tipo Texto.

Puede ver la ayuda de VB para mas detalles. Le enumero los mas usuales

Propiedad Type

Constante Descripción Constante Descripción

dbBoolean Campo SI/NO dbByte Campo tipo Byte


dbCurrency Tipo moneda dbDate Tipo Date/Time
dbDouble Numérico Doble dbInteger Numérico Integer
dbLong Entero Long dbMemo Campo Memo
dbLongBinary Binario largo (Objeto OLE)
dbSingle Numérico Single dbText CampoTexto

Propiedad Attributes

Constante Descripción

dbFixedField El tamaño del campo es fijo (predeterminado en campos numéricos).


dbVariableField El tamaño del campo es variable (Sólo campos de texto).
dbAutoIncrField El valor del campo en los registros nuevos es incrementado
automáticamente a un valor Long integer único que no puede ser
modificado. Sólo aceptado en tablas bases de datos Jet.
dbUpdatableField El valor del campo no puede ser modificado.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 23


dbDescending El campo está ordenado de forma descendente (Z-A o 100-0) (sólo se
aplica a objetos Field de una colección Fields de un objeto Index). Si se
omite esta constante, el campo se ordena ascendentemente (A-Z o 0-
100) (predeterminado).

dbAutoIncrField es la constante a utilizar cuando queremos crear un campo que se vaya


incrementando cada vez que se introduce un nuevo registro (Campo Contador). Por ejemplo,
si hemos creado un campo denominado ID que será el contador de una serie de registros, y
queremos que se incremente en 1 cada vez que añadamos un registro, debemos usar la
propiedad Attributes ANTES de añadir ese campo al objeto TableDef correspondiente, de la
siguiente forma :

Set micampo1N = mitabla01.CreateField("ID", 4) ‘ Creamos el campo ID


micampo1N.Required = True ‘ La propiedad Required la veremos
micampo1N.Attributes = dbAutoIncrField ‘ Le damos atributo de contador
mitabla01.Fields.Append micampo11 ‘ Añadimos el campo a la tabla

Propiedad Size

Devuelve o establece un valor que indica el tamaño máximo, en bytes, de un objeto Field que
contiene texto o el tamaño fijo de un objeto Field que contiene texto o valores numéricos

Esta propiedad se le debe suministrar en la sintaxis de CreateField solamente cuando creamos


un campo tipo texto - CreateField("ID_Cinta", dbText, 13). El tamaño de un campo texto
puede ser desde 1 a 255 caracteres. Para el resto de los tipos de datos, el tamaño va implícito
en el tipo de dato. Puede consultar el tamaño ocupado por cualquier campo, leyendo la
propiedad Size de un campo:

Variable = Micampo11.Size

Abrir una Base de Datos ya existente mediante DAO.


Método OpenDatabase
Hasta ahora hemos visto como crear una base de datos. No es lo más usual. Lo normal es
tener la base de datos creada y abrirla cuando queremos extraer datos o introducir datos.
Vamos a ver como se abre una base de datos mediante DAO, usando el espacio de trabajo
Microsoft JET. Veremos luego como se puede crear un Recordset, que es en realidad sobre el
que se leen y escriben datos, como se pueden añadir registros, borrarlos etc.

Para abrir una base de datos existente deberemos usar el método OpenDatabase. Pero
previamente deberemos declarar el nombre que se le va a dar a ese objeto Database mediante
la instrucción Dim si queremos que el ámbito de ese Database sea un formulario, o Global o
Public, (en la sección de declaraciones de un Módulo o Formulario) si queremos que el ámbito
sea toda la aplicación.

Por ejemplo, si queremos abrir una base de datos y poder referirnos a ella en toda la aplicación,
debemos declararla de esta forma en la sección de declaraciones de un módulo :

Public MiBaseDatos as Database

Método OpenDatabase
Abre la base de datos existente. La base de datos abierta se agrega automáticamente a la
colección Databases.

Sintaxis Recuerde la expresión general: Set DAOInferior = DAOSuperior.Método ( - - - - - -)

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 24


Set MiBaseDatos = Misesion.OpenDatabase(nombre_bd[, exclusivo[, sólo-lectura[, origen]]])

La sintaxis del método OpenDatabase consta de las siguientes partes:

MiBaseDatos Variable de tipo de dato objeto Database que representa el objeto DAO
Database que se va a abrir.
Misesion Variable de tipo de dato objeto Workspace que representa el objeto
Workspace existente que va a contener a la base de datos.
nombre_bd Expresión de cadena con el nombre de un archivo (y su Path) de una base de
datos existente. Si el nombre de archivo tiene extensión, es necesario
especificarla. Si la red lo admite, también puede especificar una ruta de red,
como por ejemplo "\\MISERVID\MICOMP\MIDIR\MIBD.MDB". nombre_bd
también puede ser un origen de datos OBDC. Lo veremos en otro capítulo.

Al especificar nombre_bd hay que tener en cuenta algunas consideraciones:

Si se refiere a una base de datos ya abierta por otro usuario con acceso
exclusivo, se producirá un error.

Si no se refiere a una base de datos existente o a un origen de datos ODBC


válido, se producirá un error.

Si es una cadena de longitud cero ("") y origen es "ODBC;", aparecerá un


cuadro de diálogo con todos los nombres de orígenes de datos ODBC
registrados, en el que el usuario podrá elegir una base de datos.

exclusivo Valor de tipo Boolean que es True si la base de datos se va a abrir con acceso
exclusivo (no compartido) o False si se va a abrir con acceso compartido. Si se
omite este argumento, la base se abrirá con acceso compartido.
sólo_lectura Valor de tipo Boolean que es True si la base de datos se va a abrir con acceso
de sólo lectura o False si se va a abrir con acceso de lectura/escritura. Si se
omite este argumento, la base se abrirá para lectura/escritura.

origen Expresión de cadena utilizada para abrir la base de datos. Esta cadena
constituye los argumentos de conexión ODBC. Para especificar una cadena de
origen deberá especificar también los argumentos exclusivo y sólo_lectura.
Consulte la sintaxis en la propiedad Connect.

p.e. Set MiBaseDatos = Misesion.OpenDatabase (“C:\Guia_Est\Videoclub.MDB”)

abre la base de datos cuyo fichero está en C :\Guia_Est y se llama Videoclub.MDB. Al no


expresarle mas parámetros la abre de modo no exclusivo, y de lectura y escritura. Al no
especificar nada en el parámetro origen entiende que la base es ACCESS

Nota para todo este capítulo. No es necesario cambiar el nombre del Workspace. Si Misesion
= Workspaces (0), la sentencia anterior podemos ponerla también :

Set MiBaseDatos = Workspaces(0).OpenDatabase (“C:\Guia_Est\Videoclub.MDB”)

El hecho de poner siempre un nombre al Workspace es solamente a efectos didácticos

Ya tenemos la base de datos abierta. Pero no crea que nuestro programa ha hecho trabajo. Se
ha limitado a ver si existía el fichero indicado y a “apuntar” el nombre y path de ese fichero que
contiene la base de datos. El trabajo comienza cuando cree el recordset.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 25


EL OBJETO RECORDSET
(O la mitad de lo que Vd. necesita saber de Bases de Datos)
Un objeto Recordset contiene los registros de una tabla o de una consulta. Puede ser que no
los contenga todos, si al crear ese recordset le hemos impuesto que los registros cumplan una
determinada condición. En resumen, un recordset es un objeto de acceso a datos que contiene
una colección de registros tomados, bien de una tabla, bien de un conjunto de tablas (a través
de una consulta)

También hay una colección Recordsets. La colección Recordsets contiene todos los objetos
Recordset abiertos de un objeto Database.

Al utilizar objetos de acceso a datos, casi toda la interacción con los datos se produce a través
de objetos Recordset. Todos los objetos Recordset están formados por registros (filas) y
campos (columnas). Existen tres tipos de objetos Recordset:

Recordset de tipo tabla: Representación en código de una tabla base de datos que puede
utilizarse para agregar, modificar o eliminar registros de una sola tabla de base de datos. Un
Recordset tipo Tabla contiene todos los campos de una tabla y no puede contener campos que
no pertenezcan a esa tabla.

Recordset de tipo hoja de respuestas dinámica: Resultado de una consulta que puede tener
registros actualizables. Un Recordset de tipo hoja de respuestas dinámica es un conjunto
dinámico de registros que puede utilizarse para agregar, modificar o eliminar registros de una o
más tablas de una base de datos subyacente. Este tipo de objeto Recordset puede contener
campos de una o más tablas de una base de datos.

Recordset de tipo instantánea: Copia estática de un conjunto de registros que puede


utilizarse para buscar datos o generar informes. Los objetos Recordset de tipo instantánea
pueden contener campos de una o más tablas de una base de datos, pero no pueden
actualizarse. Un recordset de tipo instantánea (Snapshot) es una fotografía que se hace a la
tabla o tablas que lo componen. Los datos que tiene el recordset son los que existían cuando se
realizó la fotografía. Cualquier actualización posterior no se puede ver.

Resumiendo, un Recordset es un conjunto de registros. Recuerde cuando explicábamos en


control Data se decía que este control creaba un Recordset a partir de sus propiedades
DatabaseName y RecordSource. De esta forma, el conjunto de registros que tiene ese control
Data es la totalidad de los registros de la tabla (o consulta) que poníamos en la propiedad
RecordSource. Pero siempre podemos asignar a la propiedad Recordset de ese control Data un
Recordset ya creado mediante código. Y en ese caso, solamente contendrá los campos que a
nosotros nos interese, incluso campos de distintas tablas, cosa que viene muy bien algunas
veces.

Un Recordset lo crearemos con el método OpenRecordset que estamos estudiando. El objeto


Recordset se abre desde un objeto DataBase (que es lo normal). Pero si acude a la información
de VB verá que también se puede abrir desde un TableDef, un QueryDef y desde otro
Recordset. No se complique la vida. Abra directamente los Recordsets desde la base de datos.
A lo mejor, tenemos oportunidad de ver que también se puede abrir desde otro recordset, pero
que en este caso solamente podemos abrirlo para cambiar alguna de sus propiedades.

Como cualquier objeto DAO, debemos declararlo como variable tipo objeto.

Public Mirecordset As Recordset

Una vez declarado, para abrirlo basta con ejecutar la sentencia :

Set Mirecordset = base_datos.OpenRecordset (origen[, tipo[, opciones]])

Al crear un nuevo objeto Recordset se agrega automáticamente a la colección Recordsets.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 26


base_datos es el nombre del objeto Database que va a crear el recordset. (La base de datos
que acaba de abrir)

Origen en la primera expresión es una variable de tipo String que especifica el origen de los
registros del nuevo objeto Recordset. El origen puede ser un nombre de tabla, un nombre de
consulta o una instrucción SQL que devuelva registros. En el caso de los objetos Recordset de
tipo tabla, el origen sólo puede ser un nombre de tabla.

Tipo es el tipo de Recordset que se quiere crear. Si no se especifica un tipo, OpenRecordset


creará un objeto Recordset de tipo tabla cuando sea posible. (Cuando especifica como Origen
el nombre de una Tabla) Si se especifica una consulta o una tabla adjunta, OpenRecordset
creará un objeto Recordset de tipo hoja de respuestas dinámica. El tipo del nuevo objeto
Recordset se define mediante una de las siguientes constantes :

dbOpenTable para abrir un objeto Recordset de tipo tabla.


dbOpenDynaset para abrir un objeto Recordset de tipo hoja de respuestas dinámica.
dbOpenSnapshot para abrir un objeto Recordset de tipo instantánea.

El parámetro opciones permite especificar las características del nuevo objeto Recordset tales
como las restricciones de edición y consulta para otros usuarios. Vea la Ayuda de VB para
mayor detalle.

Los objetos Recordset se eliminan automáticamente de la colección Recordsets al cerrarlos con


el método Close. También se eliminan automáticamente cuando creamos otro recordset con el
mismo nombre.

Ejemplo de creación de un Objeto Recordset

Decíamos que se puede crear un Recordset con la sentencia :

Recuerde la Fórmula general Set DAOinf = DAOsup.Método ( - - - - - - - )

Set Mirecordset = base_datos.OpenRecordset (origen[, tipo[, opciones]])

Si tenemos abierta una base de datos llamada MiBaseDatos, podemos crear el objeto
MiRecordset eligiendo de la tabla MiTabla de esa base de datos los campos Campo1, Campo2
y Campo3, y que sea del tipo de hoja de respuestas dinámica, de la siguiente forma :

Set Mirecordset = MiBaseDatos.OpenRecordset (“SELECT Campo1, Campo2, Campo3 _


FROM MiTabla”, dbOpenDynaset)

Si deseamos que el Recordset contenga todos los campos de esa misma tabla :

Set Mirecordset=MiBaseDatos.OpenRecordset (“SELECT * FROM MiTabla”, dbOpenDynaset)

o simplemente sin utilizar la sentencia SQL :

Set Mirecordset = MiBaseDatos.OpenRecordset (“MiTabla”, dbOpenDynaset)

En los ejemplos anteriores no se ha establecido ningún parámetro en Opciones.

Veamos lo que decíamos antes. Crear un Recordset desde otro recordset. Se puede usar
solamente para variar sus propiedades. Si desde el Recordset anterior, queremos crear un
nuevo Recordset denominado MiRecordset1, que tenga la condición de que sea solo lectura,
usaremos la sentencia :

Set Mirecordset1 = Mirecordset.OpenRecordset (dbReadOnly)

Este nuevo Recordset contendrá los mismos campos que el Recordset origen, pero no
podremos cambiar datos en él.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 27


Pueden crearse tantos Recordsets como se necesiten. Estos Recordsets pueden tener campos
comunes. Es más, podríamos crear dos Recordsets exactamente iguales.

Pero en la mayoría de los casos, necesitaremos crear un Recordset donde se elijan varios
campos de una o varias tablas, seleccionando de esos campos unos determinados valores. Por
ejemplo, en una base con las direcciones de los clientes, a lo mejor queremos seleccionar
todas aquellas direcciones en las cuales el código postal sea el 28700 (San Sebastián de los
Reyes). Imaginemos que hemos abierto la base de datos con el nombre CLIENTES (Recuerde
que este es el nombre del objeto DAO usado para abrir la B.D., no el nombre que pueda tener
esa B.D. en el disco), y esta base de datos tiene una tabla llamada DIRECCIONES (Este sí es
el nombre real de la tabla dentro de la B.D.) Vamos a abrir un Recordset con todos los clientes
de San Sebastián de los Reyes :

Set Mirecordset2 = CLIENTES.OpenRecordset (“SELECT * FROM DIRECCIONES WHERE


COD_POSTAL = 28700“, dbOpenDynaset)

El Recordset Mirecordset2 contiene todos los campos de todos los registros de la tabla
DIRECCIONES que cumplan la condición de que el código postal (campo COD_POSTAL en el
ejemplo) sea igual a 28700.

Observe en esta y anteriores expresiones, que la sentencia SQL está entre doble comilla.

Podemos introducir cualquier sentencia SQL para determinar qué registros introducimos en el
Recordset. Por ejemplo, si queremos seleccionar todos los clientes de Madrid (su código postal
comenzará necesariamente por 28 y le seguirán tres cifras) :

Set Mirecordset2 = CLIENTES.OpenRecordset (“SELECT * FROM DIRECCIONES WHERE


COD_POSTAL LIKE 28???“, dbOpenDynaset)

Tipo de recordset más práctico ¿Dynaset, Table?


A la hora de crear un recordset podemos pensar que tipo es el más adecuado. Todo dependerá
de lo que necesitemos de nuestro recordset y de cómo nos queramos mover por él. Cuando
decimos movernos por él queremos decir cambiar de un registro a otro, buscar registros, etc.

Vamos a prescindir del recordset tipo Snapshot si lo que queremos es leer y escribir datos. Un
recordset Snapshot solamente sirve para realizar informes (leer) de los datos en un instante
determinado. Veamos la elección entre Dynaset y Table

Si queremos seleccionar parte de los registros de una tabla, o ver registros de varias tablas al
mismo tiempo (lo que podemos ver en Access en una consulta), debemos elegir directamente
el tipo Dynaset, ya que el tipo Table debe contener TODOS los registros de una UNICA TABLA.

Si estamos en ese caso es el único en el que tendremos dudas respecto al tipo elegido.

Si creamos un recordset tipo Table se nos puede complicar un poco el código a la hora de
movernos a lo largo del recordset, ya que no podemos usar ciertos métodos como los Find
(FindFirst, FindLast, etc.) debiendo utilizar para realizar la misma función los métodos Move
(MoveFirst, MoveLast, MovePrevious, MoveNext), o el método Seek, un poco más complicado y
que exige un índice. (Lo que ganamos con la complicación del Seek es velocidad). Los
desplazamientos a lo largo de un recordset tipo tabla son mucho más rápidos que sobre un
recordset tipo Dynaset. Esa rapidez se nota fundamentalmente cuando va a manejar miles de
registros, en cuyo caso es indispensable usar recordsets tipo tabla y moverse sobre un índice.
Si no va a manejar miles de registros, no apreciará mucha diferencia entre uno y otro. Y si usa
Dynaset dispone de más recursos, sobre todo de búsqueda. Veremos casos de uno y otro tipo.

Métodos y Propiedades del recordset que va a necesitar inmediatamente


Propiedad RecordCount

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 28


Devuelve el número de registros accedidos en un objeto Recordset. El valor de esta propiedad
es de sólo lectura

Sintaxis NombredeMiRecordset.RecordCount

Donde NombredeMiRecordset es un objeto Recordset. El valor devuelto por la propiedad


RecordCount es un dato numérico Long

(NombredeMiRecordset puede ser del tipo Dynaset, Snapshot Table. Pero en el caso de que
sea Dynaset se va a encontrar con una sorpresa. Si le pide ese dato a un recordset tipo
Dynaset recién creado, le devolverá el valor 1. ¡Parece que solamente tiene un registro! No es
así. Un recordset tipo Dynaset tiene la ventaja (y el inconveniente) de que solamente guarda en
memoria un registro. Por lo tanto no sabe cuantos registros tiene realmente hasta que no los
recorre todos. Para que el método RecordCount le devuelva el número de registros existentes,
tiene que acceder previamente al primero y al último. Para ello basta con ejecutar estas dos
líneas de código:

NombredeMiRecordset.MoveLast
NombredeMiRecordset.MoveFirst

A partir de ese momento, ya le indicará el número correcto de registros existentes.

Método AddNew

Crea un nuevo registro en un objeto Recordset de tipo Table o Dynaset.

Sintaxis MiRecordset.AddNew

El método AddNew crea un nuevo registro donde puede introducir nuevos datos, y
posteriormente agregarlo al conjunto de registros del objeto Recordset. Este método establece
en los campos el valor Null (predeterminado para los objetos Recordset de tipo tabla) o los
valores predeterminados, si existen. El registro creado queda en la memoria, y ahí se puede
modificar simplemente asignando a cada campo el valor deseado. Para asignar un valor a un
campo simplemente tenemos que poner la expresión :

MiRecordset ! MiCampo1 = “Dato tipo string”


MiRecordset ! MiCampo2 = Dato tipo numérico

Una vez que se hayan introducido los datos en el nuevo registro, debe utilizar el método Update
para guardar los cambios y agregarlo al conjunto de registros. No se modificará la base de
datos hasta que se utilice el método Update.

La posición del nuevo registro depende del tipo de objeto Recordset:

En un objeto Recordset de tipo hoja de respuestas dinámica, (Dynaset) los registros se insertan
al final del conjunto, independientemente de las reglas de ordenación que pueda haber en vigor
al abrir el conjunto de registros. En un objeto Recordset de tipo tabla cuya propiedad Index esté
definida, los registros se agregan en el lugar correspondiente al orden. Si no se ha establecido
la propiedad Index, los nuevos registros se agregan al final del conjunto.

El registro que era actual antes de utilizar el método AddNew continúa siéndolo después. Esto
puede comprobarlo asignando a un Label el contenido de un campo, añadir un registro con un
valor para ese campo distinto al que está presente en el Label y comprobar que el contenido del
Label no se ve afectado por haber introducido un registro nuevo. Si desea hacer que el nuevo
registro sea el actual, puede establecer en la propiedad Bookmark el marcador identificado por
el valor de la propiedad LastModified. En la práctica anterior observará tras este proceso que
se cambia el contenido del Label al nuevo valor.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 29


Vea la propiedad LastModified un poco mas adelante.

Método Edit

Copia el registro actual de un objeto Recordset de tipo hoja de respuestas dinámica o tabla en
el búfer de copia para su edición.

Sintaxis MiRecordset.Edit

Donde MiRecordset representa el nombre de un objeto Recordset abierto y actualizable que


contiene el registro a editar.

Una vez invocado el método Edit, los cambios efectuados en los campos del registro actual se
copian en el búfer de copia. Al terminar de realizar los cambios deseados, utilice el método
Update para guardarlos. Como en el caso del método AddNew este registro modificado está en
la memoria y es necesario introducirlo en la BD.

El registro actual después de utilizar Edit es precisamente el registro que acabamos de editar.
Para poder usar Edit debe existir un registro actual. Si no es así o si MiRecordset no se refiere a
un objeto Recordset de tipo tabla u hoja de respuestas dinámica, a un objeto Table o a un
objeto Dynaset abierto, se producirá un error.

El uso de Edit producirá un error en las condiciones siguientes:

No hay registro actual.


La base de datos o el conjunto de registros es de sólo lectura.
Ningún campo del registro es actualizable.
Otro usuario ha abierto la base de datos o el conjunto de registros para uso exclusivo.
Otro usuario ha bloqueado la página que contiene el registro.

Una vez añadido el registro, o cambiados los datos de un registro, debemos utilizar el Método
Update para guardar los datos en la BD.

Método Update

Guarda el contenido del búfer de copia en un objeto Recordset de tipo hoja de respuestas
dinámica o tabla especificado.

Es decir, mete en la Base de Datos el contenido del registro que estaba en la memoria, bien por
haber utilizado el método Update, bien por haber utilizado el método Edit.

Sintaxis MiRecordset.Update

Donde MiRecordset representa el nombre de un objeto Recordset de tipo hoja de respuestas


dinámica o tabla, abierto y actualizable.

Los cambios en el registro actual se perderán en las siguientes situaciones:

Uso del método Edit o AddNew y desplazamiento a otro registro sin utilizar antes Update.
Uso de Edit o AddNew y utilización de nuevo de Edit o AddNew sin especificar antes Update.
Establecimiento de otro registro en la propiedad Bookmark.
Cierre del conjunto de registros indicado en MiRecordset sin utilizar antes Update.

Cada vez que se crea o edita un registro se cambia el valor de la propiedad LastModified, que
tomará el marcador de ese registro creado o editado.

Método CancelUpdate

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 30


Cancela todas las actualizaciones pendientes del objeto Recordset.

Sintaxis recordset.CancelUpdateTipo

Tipo puede tomar los siguientes valores

dbUpdateRegular Cancela los cambios pendientes que no están en la memoria caché.


dbUpdateBatch Cancela los cambios pendientes en la memoria cache actualizada.
Comentarios

El método CancelUpdate cancela todas las actualizaciones pendientes a causa de una


operación Edit o AddNew. La utilización del método CancelUpdate tiene el mismo efecto que
moverse a otro registro sin utilizar el método Update, salvo que el registro activo no cambia y
algunas propiedades, como BOF y EOF, no se actualizan.

Método Delete

Este método elimina el registro actual de un objeto Recordset de tipo hoja de respuestas
dinámica o tabla. Para eliminar un registro, debe haber un registro actual en el Recordset antes
de utilizar Delete, pues de lo contrario se producirá un error interceptable. Una vez eliminado,
este registro sigue siendo el registro actual. Puede observar, que si a continuación de Delete
utiliza AbsolutePosition para conocer en que registro está, la respuesta será -1, prueba de que
está sobre un registro inexistente.

Propiedad Bookmark

Devuelve o establece un marcador que identifica de forma única el registro actual de un objeto
Recordset o define el registro actual de un Recordset como marcador válido.

Esto merece una pequeña aclaración. Bookmark en inglés significa ese papel que introducimos
en un libro para saber en qué página hemos dejado la lectura. En Visual Basic, significa el
registro en el que estamos actualmente (registro actual) Podemos conocer en que registro
estamos mediante la siguiente expresión:
Variable = MiRecordset.Bookmark

Pero tenemos que tener en cuenta que Variable es una variable tipo String (Sí, string, aunque
parezca que para conocer la posición de un registro debería ser un numérico, pero es así). Por
lo tanto deberíamos haber declarado la variable previamente como una variable tipo String

Dim Variable As String

Pero esta propiedad sirve para colocarnos en el registro que deseemos. Eso sí, previamente
deberíamos haber obtenido el Bookmark de ese registro. Imagínese que se está moviendo a lo
largo del recordset y hemos visto un registro donde tenemos un dato importante (por ejemplo,
un máximo del valor de un campo) No sabemos si habrá otro registro que tenga un valor mayor
que este. Deberemos seguir buscando, pero antes anotamos el Bookmark de ese registro

Variable = MiRecordset.Bookmark

Seguimos buscando moviéndonos por todo el recordset, y comprobamos que no hay otro
registro con un valor mayor. Queremos volver a aquel registro. Para ello forzamos a que el
registro cuyo Bookmark sea igual a Variable se convierta en registro actual:

MiRecordset.BookMark = Variable

Y se colocará en el registro deseado.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 31


Solamente se puede ver la propiedad Bookmark en aquellos recordsets que tengan la
propiedad Bookmarkable a True. En un Recordset basado completamente en tablas del motor
de base de datos Microsoft Jet, el valor de la propiedad Bookmarkable es True y pueden
usarse marcadores. Sin embargo, otros productos de bases de datos pueden no aceptar los
marcadores. Por ejemplo, no se pueden usar marcadores en un Recordset basado en una tabla
anexa Paradox que no tiene clave principal.

La propiedad Bookmark se almacena internamente como matriz de Byte. Por esta razón, si se
intenta usar la propiedad Bookmark en una operación de comparación, se producirá un error
interceptable. Antes de tener acceso a la propiedad Bookmark, copie los valores de los
marcadores a variables cadena y efectúe las comparaciones usando dichas variables cadena.
Por ejemplo, el siguiente código compara marcadores en dos objetos Recordset:

Dim Marca1 as String, Marca2 as String


Dim Rs1 as Recordset, Rs2 as Recordset
Set Rs1 = Db.OpenRecordset("Títulos")
Set Rs2 = Rs1.Clone()
Marca1 = Rs1.Bookmark
Marca2 = Rs2.Bookmark
If Marca1 = Marca2 Then Print "Esta comparación es válida "

No intente realizar la siguiente comparación, aunque a primera vista parezca igual :

If Rs1.Bookmark = Rs2.Bookmark Then ..... Porque dará error.

No hay límite en el número de marcadores que pueden establecerse. Para crear un marcador
para otro registro distinto del registro actual, muévase al registro deseado y asigne el valor de la
propiedad Bookmark a una variable String que identificará el registro.
Para asegurarse de que el Recordset acepta marcadores, inspeccione el valor de su propiedad
Bookmarkable antes de usar la propiedad Bookmark. Si Bookmarkable es False, el Recordset
no acepta marcadores, y el uso de la propiedad Bookmark produce un error interceptable.

Si la propiedad Bookmark se establece a un valor que corresponda a un registro eliminado, se


produce un error interceptable.

Propiedad LastModified

Devuelve un marcador que indica el registro más recientemente agregado o modificado.

Sintaxis NombreRecordset.LastModified

El valor devuelto por esta propiedad es un tipo de datos Variant o String. (Similar al devuelto
por Bookmark) LastModified se puede usar para colocarse en el registro más recientemente
agregado o actualizado.

Esta propiedad puede usarse para volver al último registro que ha sido modificado. Basta para
ello igualar la propiedad Bookmark a la propiedad LastModified :

NombreRecordset.Bookmark = NombreRecordset.LastModified

Métodos MoveFirst, MoveLast, MoveNext, MovePrevious


Estos métodos son aplicables a todos los tipos de recordset.

Se sitúan en el primer, el último, el siguiente o el anterior registro del objeto Recordset


especificado y lo convierten en el registro actual.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 32


Sintaxis MiRecordset.{MoveFirst | MoveLast | MoveNext | MovePrevious}

Puede utilizar los métodos Move para desplazarse de un registro a otro sin aplicar una
condición.

Al abrir el conjunto de registros indicado en Recordset, el primer registro pasa a ser el registro
actual y en la propiedad BOF se establece False. Si el conjunto no contiene ningún registro, se
establecerá en BOF el valor True y no habrá registro actual.

Si el primer o el último registro ya es el actual al utilizar MoveFirst o MoveLast, el registro


actual no varía.
Si utiliza MovePrevious cuando el registro actual sea el primero, en la propiedad BOF se
establecerá True y no habrá registro actual. Si utiliza de nuevo MovePrevious, se producirá un
error y BOF continuará con el valor True.
Si utiliza MoveNext cuando el registro actual sea el último, en la propiedad EOF se establecerá
True y no habrá registro actual. Si utiliza de nuevo MoveNext, se producirá un error y EOF
continuará con el valor True.
Si Recordset hace referencia a un objeto Recordset de tipo tabla o a un objeto Table, el
movimiento se hará según el índice actual de la tabla. Para establecer el índice actual puede
usar la propiedad Index. Si no establece un índice actual, el orden de los registros devueltos no
estará definido.
Si utiliza MoveLast en un objeto Recordset basado en una consulta SQL o QueryDef, se
forzará la terminación de la consulta, poblando completamente el objeto Recordset.

No es posible utilizar los métodos MoveFirst ni MovePrevious en los Recordset tipo snapshot
de desplazamiento hacia delante.

Para desplazar la posición del registro actual en un objeto Recordset un número de registros
determinado hacia adelante o hacia atrás, utilice el método Move.

Método Move
Desplaza la posición del registro actual en un objeto Recordset.

Sintaxis MiRecordset.Move filas[, inicio]

Donde :
filas es un valor de tipo Long con signo que especifica el número de filas (de registros) que se
desplaza la posición. Si filas es mayor que 0, la posición se desplaza hacia adelante (hacia el
final del archivo). Si es menor que 0, la posición se desplaza hacia atrás (hacia el principio del
archivo).

Inicio (opcional) es un valor de tipo String que identifica un marcador. Si se especifica inicio, el
desplazamiento será relativo al marcador indicado. Si se omite, Move comenzará por el registro
actual. El marcador que debe utilizarse para definir el registro Inicio debe ser un Bookmark o
similar (LastModified, por ejemplo)

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 33


Si se especifica una posición anterior al primer registro, la posición del registro actual se situará
al principio del archivo (BOF). Si se especifica una posición posterior al último registro, la
posición del registro actual se situará al final del archivo (EOF).

Si el objeto Recordset no contiene registros y el valor de su propiedad BOF es True, el uso de


este método para desplazarse hacia atrás producirá un error interceptable en tiempo de
ejecución. Lo mismo ocurrirá si el valor de la propiedad EOF es True y pretende desplazarse
hacia adelante. Si las propiedades BOF o EOF tienen el valor True y se intenta usar el método
Move sin un marcador válido, se generará un error interceptable.
Si el objeto Recordset está basado en una consulta, la operación forzará la ejecución de la
consulta en el número de filas especificado..

Métodos FindFirst, FindLast, FindNext, FindPrevious

Estos métodos no se pueden aplicar a un recordset tipo Tabla

Buscan el primer, el último, el siguiente o el anterior registro de un objeto Recordset de tipo


instantánea u hoja de respuestas dinámica, que satisfaga el criterio especificado y lo convierte
en el registro actual.

Sintaxis MiRecordset.{FindFirst | FindLast | FindNext | FindPrevious} criterio

MiRecordset es el nombre de un objeto Recordset.


Criterio es una expresión de cadena (como la cláusula WHERE de una instrucción SQL, sin la
palabra WHERE) que se utiliza para buscar un registro.

Si no se encuentra ningún registro que satisfaga el criterio, el puntero de registro actual se


situará en el primer registro del objeto Recordset y se establecerá en la propiedad NoMatch el
valor True. Si Recordset contiene más de un registro que satisfaga el criterio, FindFirst hallará
el primero de ellos, FindNext el siguiente y así sucesivamente. La propiedad NoMatch tomará
en este caso el valor False.

Compruebe siempre el valor de la propiedad NoMatch para determinar si la operación de


búsqueda ha tenido éxito. Si la búsqueda ha tenido éxito, NoMatch se establece a False. Si ha
fracasado, NoMatch se establece a True y el registro actual pasa a ser el primero del objeto
Recordset. Por ejemplo:

Dim Estabaaqui as String


Estabaaqui = Recordset.Bookmark

Recordset.FindFirst "Nombre = 'Luis' " ' Busca un nombre. Recuerde siempre las
comillas dobles para la expresión de búsqueda
y las comillas simples si se trata de un dato
string.

If Recordset.NoMatch = True Then 'Si no se ha encontrado

Recordset.Bookmark = Estabaaqui ' Si no se ha encontrado, vuelve al que era el


‘registro actual.

Else ' Sí se ha encontrado.

. Aquí las instrucciones adecuadas


.
End If

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 34


No es posible utilizar estos métodos en un objeto Recordset de tipo snapshot de
desplazamiento hacia delante.

Al buscar campos que contengan fechas, deberá utilizar el formato de fecha de los Estados
Unidos (mes-día-año), incluso cuando no utilice la versión para este país del motor de base de
datos Jet, pues de lo contrario es posible que no se encuentren los datos buscados. Puede
utilizar la función Format para convertir la fecha. Por ejemplo:

Mirecordset.FindFirst "fecha > #" & Format(mifecha, "mm/dd/yyyy" ) & "#"

Observe que las fechas, aparte de ponerlas en americano, hay que presentarlas entre
almohadillas (#). Observe lo dicho mas atrás para las comillas dobles en la expresión de
búsqueda.

Método Seek
Este método solo se puede usar con recordsets tipo Tabla

Si no podemos usar los métodos Find en un recordset tipo Tabla, ¿Qué podemos hacer para
buscar un dato en un recordset de este tipo? Usar el método Seek

El método Seek busca el primer registro de un objeto Recordset indexado de tipo Table que
cumple el criterio especificado para el índice activo y lo convierte en el registro activo. Sólo
funciona en espacios de trabajo Microsoft Jet.

Sintaxis MiRecordset.Seek comparación, clave1, clave2...clave13

Donde MiRecordset es un recordset de tipo Table que tiene definido un índice en el campo por
el que se va a realizar la búsqueda. Como podemos tener varios índices en una tabla,
deberemos indicarle cual es el índice de búsqueda. Una vez que se lo indiquemos, ese índice
será el Indice activo.

comparación Es una de esta expresiones de cadena: <, <=, =, >=, >.

clave1, clave2...clave13 Son uno o más valores que corresponden a los campos en el índice
activo del objeto Recordset. Puede utilizar un argumento de hasta 13 claves.

Antes de usar Seek se debe establecer el índice activo. Todo índice tiene un nombre.
Habíamos visto cuando creábamos un índice que debía tener un nombre. Recuerde el ejemplo:

Set MiIndice2 = MiTabla2.CreateIndex("IndicePeliculas")

Puede ver el nombre de ese índice en la Fig. 20.7 En este caso habíamos creado el índice
mediante código y hemos podido controlar su nombre. Si lo hubiésemos creado directamente
en Access, el nombre que le pone por defecto es el mismo que el nombre del campo.

Ese nombre del índice es el que debemos usar para crear el índice activo. Por ejemplo, si
quisiéramos que el índice activo fuese el IndicePeliculas lo haríamos índice activo mediante la
siguiente instrucción:

MiRecordset.Index = "IndicePelículas"

A partir de ahora, el campo (o campos) de ese índice será sobre el que realizaremos la
búsqueda mediante Seek. Para encontrar el registro que tenga por valor 00000012 usaremos
la expresión

MiRecordset.Seek "=", "00000012"

Ese registro será ahora el registro actual. Si hubiese mas de un registro con ese valor, el
registro actual será el primero que cumpla esa condición

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 35


En el ejemplo hemos utilizado el comparador = para buscar un registro cuyo valor en el campo
indicado por el índice activo sea igual al indicado en el siguiente parámetro (00000012). Si
quisiésemos encontrar un registro cuyo valor sea superior a 00000012 usaríamos la expresión

MiRecordset.Seek ">", "00000012"

Pero observe ahora que el 0000012 no es un número, es una cadena de caracteres. No se


preocupe. Seek puede comparar el contenido de un campo numérico, de un campo texto, de un
campo Fecha/Hora, etc. Eso sí, debe compararlo con un valor del mismo tipo, es decir, si el
contenido del campo es numérico, en el parámetro Clave1 deberemos pasarle un campo
numérico, si el campo es texto, deberemos pasarle un dato tipo texto, etc.

El método Seek busca en los campos clave especificados y localiza el primer registro que
cumpla el criterio especificado por comparación y clave1. Cuando lo encuentra, convierte ese
registro en activo y la propiedad NoMatch se establece en False. Si el método Seek no
consigue localizar ninguna coincidencia, la propiedad NoMatch se establece en True y el
registro activo es indefinido.

Si comparación es igual (=),mayor o igual (>=) o mayor que (>), Seek empezará al principio del
índice y buscará hacia adelante.
Si comparación es menor que (<) o mayor o igual que (<=), Seek empezará al final del índice y
buscará hacia atrás, a menos que haya entradas de índice duplicadas al final. En tal caso, Seek
empezará en una entrada cualquiera entre las entradas duplicadas existentes al final del índice.

Debe especificar valores para todos los campos definidos en el índice. Si utiliza Seek con un
índice de múltiples columnas y no especifica un valor de comparación para cada campo del
índice, no podrá usar el operador de igual (=) en la comparación. Esto se debe a que algunos
de los campos de criterio(clave2, clave3, etc) estarán predeterminados en Null, lo que
posiblemente no concordará. Por tanto, el operador de igual sólo funcionará correctamente si
tiene un registro que sea Null en su totalidad, excepto la clave que está buscando. Es
aconsejable usar el operador mayor que o igual en su lugar.

En el ejemplo siguiente se toman los nombres de las calles y otros datos de una tabla llamada
Calles_Nombre, cuyo campo NombreVia esta indexado. El índice tiene el mismo nombre que el
campo porque se creó directamente con Access. El procedimiento BBuscaCalle_Click busca la
primera calle cuyo nombre coincida con las letras tecleadas en el TextBox TBBuscaCalle

Set BaseDatos = OpenDatabase("C:\Callejero\Calles.mdb")


Set RsCalles = BaseDatos.OpenRecordset("Calles_Nombre", dbOpenTable)

Private Sub BBuscaCalle_Click()


RsCalles.Index = "NombreVia"
RsCalles.Seek ">=", TBBuscaCalle
If RsCalles.NoMatch = False Then
TBNombreCalle = RsCalles!nombrevia
Else
TBNombreCalle = "No se encontró la calle"
End If
End Sub

Método Clone
En muchas ocasiones es necesario crear un Recordset que sea copia exacta de otro. Las
ocasiones en las que es necesario hacer esto pueden ser variadas, pero vamos a destacar
una : crear un Recordset idéntico al Recordset de un control Data, para trabajarlo con código
durante una parte de la ejecución del programa. Otras aplicaciones pueden ser copiar el
Recordset de otra máquina a través de la Red de Area Local, ... y donde podamos llegar con
nuestra imaginación.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 36


La sintaxis de Clone es la siguiente :

Sintaxis Set Duplicado = Original.Clone

Donde Duplicado es una variable tipo Recordset, y Original es el Recordset que se va a


duplicar.

Con el método Clone puede crear múltiples Recordsets. Cada uno de ellos puede tener su
propio registro actual. El uso de Clone no modifica los datos de los registros. Puede modificar
un registro desde cualquier Recordset, bien desde el que sirvió de original, bien desde
cualquiera de sus copias, pero debe hacerlo invocando los métodos Edit - Update. Puede
compartir marcadores entre dos o más Recordsets creados de esta forma.

Puede utilizar el método Clone cuando desee realizar en un conjunto de registros una operación
que requiera varios registros actuales. Este método es más rápido y eficiente que crear un
nuevo Recordset.

Inicialmente, un Recordset creado con Clone carece de registro actual. Para hacer que un
registro sea el actual antes de utilizar el Recordset copia, puede utilizar cualquiera de los
métodos Move, Find o Seek (solo para Recordsets tipo Tabla), o establecer su propiedad
Bookmark

El hecho de cerrar el Recordset original no afecta al duplicado y viceversa.

Nota No es posible utilizar este método con snapshots de desplazamiento hacia delante
(objetos Recordset de tipo instantánea con la opción dbForwardOnly activada).

Método Requery
El método Requery actualiza los datos de un objeto Recordset, volviendo a ejecutar la consulta
con la que se ha creado ese Recordset. Este método debe usarse cada vez que se sospeche
que los datos de la Base de datos han cambiado, y se quieran presentar los datos actualizados.
Es un método típico de una BD que se está usando desde varios puestos a través de una Red
de Area Local.

Sintaxis NombreRecordset.Requery [NuevoQueryDef]

Donde NombreRecordset es el nombre del Recordset, y NuevoQueryDef (opcional) es una


consulta almacenada

No es posible utilizar el método Requery en objetos Recordset tipo Snapshot o en los Dynaset
que tengan la propiedad Restartable a False, ni tampoco en los objetos Recordset de tipo
Tabla.

Si los valores de las propiedades BOF y EOF del objeto Recordset son ambos True después
de utilizar el método Requery, la consulta no habrá devuelto ningún registro y el objeto
Recordset no contendrá datos.

Transacciones

Métodos BeginTrans, CommitTrans y Rollback


Estos métodos son métodos del Objeto Workspace

Veamos estos tres métodos que, dadas sus funciones, deben estudiarse conjuntamente.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 37


Supongamos un Banco. Debe hacer una transferencia entre dos cuentas corrientes que están
en la misma base de datos. La operación es sencilla : Busca la cuenta origen y crea un nuevo
registro. Apunta en el campo OPERACIÓN una T de Transferencia, en el campo IMPORTE
apunta el valor del dinero a transferir, y en el campo SALDO pone la diferencia entre lo que
había en ese campo en la última operación, menos el importe del dinero transferido.

A continuación hace un proceso similar con la cuenta destino, pero en este caso, sumándole el
importe de la transferencia. No hay problemas. Pero que pasa si, una vez sacado el dinero de la
cuenta origen, no se puede ingresar en la cuenta destino, por la razón que sea (cuenta
bloqueada, no existe esa cuenta, fallo de la red de área local) Obviamente la operación no se
ha completado, y hay que devolver el dinero a la cuenta origen. Podría hacerse un apunte,
metiendo la misma cantidad de dinero que se ha extraído anteriormente, y su saldo no se verá
afectado. Pero no sé lo que pensaría el cliente cuando vea un estadillo de su cuenta, en la que
le han sacado una cantidad de dinero, aunque en el siguiente apunte se lo hayan vuelto a
introducir.

Para evitar estas situaciones usamos lo que se denomina una Transacción, que es una
combinación de estos tres métodos. Con el método BeginTrans iniciamos la Transacción. Con
CommitTrans terminamos la transacción y se guardan los cambios realizados (En ambas
cuentas a la vez, en el caso del ejemplo). Con Rollback se termina la transacción sin llegar a
guardar los cambios, quedando el Objeto Workspace afectado por las operaciones internas a
esa transacción tal y como estaba antes de comenzar dicha operación.

Dado que una transacción pertenece a un Workspace, deberemos aplicar estos métodos al
Workspace que ese usuario tenga abierto. Es decir, en un sistema con varios usuarios que
están trabajando simultáneamente sobre una Base de Datos, un determinado usuario deberá
entrar con un Workspace propio (una sesión de trabajo solo para él). En estas condiciones
podemos crear una transacción. Y aquí comenzamos a ver la necesidad de crear Workspaces
distintos para distintos usuarios. Veremos un poco más adelante como se crean los
Workspaces.

Sintaxis MiSesión.BeginTrans
MiSesión.CommitTrans
MiSesión.Rollback

Dentro de un objeto Workspace, las transacciones son siempre globales y no se limitan sólo a
la base de datos o al conjunto de registros. Si realiza operaciones en más de una base de datos
o conjunto de registros durante una transacción en un objeto Workspace, el método Rollback
deshará todas las operaciones en todos ellos. Quiere esto decir que una transacción debe
iniciarse al comenzar una determinada operación, realizar esa operación sin realizar ninguna
otra durante ese tiempo, terminar la operación y finalizar la transacción, bien con CommitTrans
o con Rollback.
Si desea tener transacciones simultáneas, lo mas indicado es crear varios objetos Workspace
para usar uno con cada transacción.

Puede anidar transacciones. Es posible tener hasta cinco niveles de transacciones abiertos a
un tiempo en un mismo objeto Workspace utilizando múltiples combinaciones anidadas de
BeginTrans y CommitTrans o Rollback. En este caso, el orden de finalización de una
transacción debe ser siempre de menor a mayor nivel jerárquico, es decir, se deberá cerrar
primero la transacción que esté mas interior dentro del anidamiento, y así sucesivamente. Si
cierra una transacción anidada mediante CommitTrans, y posteriormente cierra una transacción
que abarque a esta última con Rollback, los cambios de la primera transacción NO quedarán
guardados.

(Cuando se utilizan bases de datos SQL ODBC externas no es posible anidar las
transacciones).

Si cierra un objeto Workspace sin guardar o deshacer las transacciones pendientes, éstas se
desharán automáticamente.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 38


Algunas bases de datos pueden no admitir las transacciones. En este caso la propiedad
Transactions del objeto Database o Recordset tendrá el valor False. Lea detenidamente la
Ayuda de estos métodos antes de trabajar con ellos.

El hecho de usar transacciones, aparte de lo que significa para asegurar la integridad de los
datos, ahorra accesos al disco (Importantísimo en algunas redes LAN y WAN), ya que los
cambios a introducir se van almacenando en un búfer en la memoria, y se vuelcan al disco
solamente en el momento de terminar la transacción de modo afirmativo con CommitTrans.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 39


La protección de accesos a una base de datos Access. Usuarios,
Workspaces, Grupos de Trabajo, Grupos de Usuarios. La base de datos
de sistema.
Acabamos de ver que es necesario poder crear Workspaces para cada usuario. Hasta ahora, y
para no complicar el estudio de las bases de datos, habíamos usado solamente el
Workspaces(0) que VB crea automáticamente. Vamos a entrar ahora en la creación de
Usuarios (Users) y Workspaces. El método para crear Workspaces es el CreateWorkspace,
método del dbEngine. Comencemos con una mirada a este objeto desde el punto de vista de
DAO. No olvide que el dbEngine es el motor de bases de datos Jet.

El dbEngine. Visión desde DAO


El objeto dbEngine es el objeto de nivel más alto en el modelo de objeto DAO. Es el encargado
de contener y controlar todos los objetos DAO. Hay un solo objeto dbEngine, inherente a la
aplicación, y no se pueden crear más.

Tiene como cualquier objeto DAO sus propiedades y métodos. Vamos a ver alguna propiedad,
en orden ascendente de importancia práctica.

Propiedad Version

Devuelve la versión actual de DAO en uso. El tipo de datos es String (p.e., "3.5" )

Propiedad DefaultType

Establece o devuelve un valor que indica qué tipo de espacio de trabajo (Microsoft Jet u
ODBCDirect) utilizará el próximo objeto Workspace que se cree. Puede tomar los valores:

dbUseJet Crea objetos Workspace conectados al motor de base de datos Microsoft Jet.
dbUseODBC Crea objetos Workspace conectados a un origen de datos ODBC.

Propiedad DefaultUser. Establece el nombre de usuario utilizado para crear el Workspace


predeterminado cuando se inicializa.

Propiedad DefaultPassword. Establece la contraseña utilizada para crear el Workspace


predeterminado cuando se inicializa.

El DefaultUser es un tipo de datos String, que puede tener entre 1 y 20 caracteres de longitud
en espacios de trabajo Microsoft Jet y cualquier longitud en espacios de trabajo ODBCDirect.

El DefaultPassword es un tipo de datos String que puede tener hasta 14 caracteres de longitud
en bases de datos Microsoft Jet y cualquier longitud en conexiones ODBCDirect. Puede
contener cualquier carácter excepto 0 ASCII.

De modo predeterminado, la propiedad DefaultUser se establece a "administrador" y la


propiedad DefaultPassword se establece a una cadena de longitud cero ("").

Para que estas propiedades tenga efecto, debe establecerla antes de llamar a cualquier método
DAO.

Propiedad LoginTimeout. Establece o devuelve el número de segundos que se esperará


antes de que se genere un error cuando se intenta conectar a una base de datos de ODBC.
Tiene como valor predeterminado, 20 segundos.

Propiedad IniPath. Devuelve la ubicación de la información de Registro de Windows de


Microsoft Jet. El método SetOption le permite sobrescribir los valores del Registro de Windows
para el motor de base de datos Microsoft Jet. (Recuerde que cualquier operación indebida
sobre el registro de Windows puede hacerle perder toda la información de su PC)

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 40


Propiedad SystemDB (Muy importante)
Establece o devuelve la ruta de acceso del archivo de información del grupo de trabajo (sólo
espacios de trabajo Microsoft Jet). Este archivo es una base de datos Access, que
normalmente se llama System.Mdw (Observe que la extensión es distinta a la .Mdb a la que
nos tiene acostumbrados Access) Access usa este fichero y lo guarda generalmente en
C:\Windows\System. Pero puede copiar esta base con otro nombre, y colocarla en el directorio
que quiera. Lo único que tendrá que hacer es indicarle al dbEngine su nombre y ubicación
mediante esta propiedad SystemDB En esa base de datos se guarda la información de los
usuarios. Se guarda su nombre y su contraseña. Lógicamente no se puede leer con Access,
aunque la abre como si se tratase de una base de datos ordinaria, pero cuando pretende abrir
una tabla, no la visualiza.
(NOTA. - La ayuda dice que el nombre predeterminado es System.Mda. Ese era el nombre para
versiones antiguas del Motor Jet. En mi PC, con W98 y VB6, y con Access98 solamente
encuentro System.Mdw)

Creación de nuevos usuarios Método CreateUser


(Sólo espacios de trabajo Microsoft Jet). Crea un nuevo Usuario, e introduce sus datos en el
archivo de información del grupo de trabajo (Base de Datos System.Mdw o la especificada en la
propiedad SystemDB) El método CreateUser corresponde al Workspace o al Objeto Group.

Para crear un nuevo usuario deberemos suministrar la siguiente información:

Nombre del usuario, PID y contraseña. La sintaxis de CreateUser es:

Set User = Objeto.CreateUser (Nombre, PID, contraseña)

Donde User es la variable tipo objeto User que desea crear. Debe declararse como User)
Objeto El nombre del Workspace (o del objeto objeto Group) que quiere utilizar para crear el
nuevo objeto User.
Nombre Nombre del nuevo usuario
PID. Identificador de Usuario. Debe contener de 4 a 20 caracteres alfanuméricos
Contraseñal. Contraseña para el nuevo usuario. La contraseña puede tener hasta 14
caracteres de longitud y puede incluir cualquier carácter excepto el carácter ASCII 0

Esto merece algún comentario. El nuevo usuario debe crearlo un Workspace (o un Group, pero
de eso no nos vamos a ocupar por ahora) Lo normal es crear el nuevo usuario con el
Workspaces(0) que como sabe, lo crea automáticamente Visual Basic.

Recuerde que antes de crear un nuevo usuario, debe indicar donde está la base de datos con la
información del systema, mediante la propiedad SystemDB

DBEngine.SystemDB = "C:\Windows\System\System.Mdw")

Con las siguientes instrucciones se crea un nuevo usuario

Dim NuevoUser As User


Set NuevoUser = Workspaces(0).CreateUser("Luis", "EsteesmiPID", "MiContraseña")
Workspaces(0).Users.Append NuevoUser

Podemos saber cuantos usuarios tiene el Workspaces(0) y su nombre. Con las siguientes
instrucciones vamos a introducir los nombres de los usuarios en la lista ListUsers

ListUsers.Clear
For I = 0 To Workspaces(0).Users.Count - 1
NomUsuario = Workspaces(0).Users(I).Name
ListUsers.AddItem NomUsuario
Next I

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 41


Creación de nuevos Workspaces. Método CreateWorkspace
Podemos crear cuantos Workspaces necesitemos. Recuerde que un Workspace es una sesión
de trabajo. Y una sesión de trabajo se abre para que trabaje un usuario. Por eso, a la hora de
crear un Workspace debemos indicarle para que usuario, y la contraseña de ese usuario. Como
el objeto Workspace pertenece al dbEngine, es este objeto el que debe crearlo.

La sintaxis es la siguiente:

Set NuevoWorkSpace = DBEngine.CreateWorkspace (Nombre, Usuario, Contraseña, Tipo)

NuevoWorkSpace es el Workspace que queremos crear, que habremos declarado como


variable tipo objeto Workspace.
Nombre es el nombre del Workspace (P.e., MiSesion)
Usuario Nombre de un usuario registrado en la base de datos del sistema (Que lo habremos
creado con CreateUser) que será el propietario del nuevo objeto Workspace.
Contraseña La contraseña del Usuario propietario del Workspace.
Tipo (Opcional). Indica el tipo de espacio de trabajo. Puede tomar los valores dbUseJet para
crear un espacio de trabajo Microsoft Jet, o dbUseODBC para crear un espacio de trabajo
ODBCDirect. Si omite tipo, la propiedad DefaultType del objeto DBEngine determinará a qué
tipo de origen de datos está conectado el Workspace
No es necesario añadir el nuevo Workspace a la colección Workspaces

Veamos un ejemplo de cómo crear un Workspace para el usuario Luis creado anteriormente:

Dim NewWS as Workspace


Set NewWS = DBEngine.CreateWorkspace("SesiondeLuis", "Luis", "MiContraseña")
DBEngine.Workspaces.Append NewWS

Podemos ver todos los Workspaces existentes. En las siguientes instrucciones podemos ver el
código para listarlos en ListWS

ListWS.Clear
For I = 0 To DBEngine.Workspaces.Count - 1
NomWS = DBEngine.Workspaces(I).Name
ListWS.AddItem NomWS
Next I

Debe tenerse en cuenta que el objeto Workspace es un objeto que solamente existe mientras
está ejecutándose la aplicación. Cuando salimos de la aplicación, ese Workspace desaparece.
No ocurre lo mismo con el Usuario, que queda en la base de datos del sistema, es decir, es un
objeto persistente.

Las partes de código expuestas se han sacado de un ejemplo creado para ver el número y
nombre de los usuarios existentes, Workspaces y DataBases. Es un ejemplo para explicar
estos conceptos. No tiene otra finalidad.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 42


Fig. 20.9 Aspecto de la interface gráfica del ejercicio para crear Users y Workspaces

Código de este ejercicio

General/Declaraciones
Option Explicit
Dim VarDrag As String
Dim NuevoWS() As Workspace

Private Sub BAnadirUser_Click()


On Error GoTo RutErr
Dim NomUsuario As String, I As Integer
If BAnadirUser.Caption = "Añadir" Then
TBNuevoUserName.Visible = True
TBNuvoUsePID.Visible = True
TBNuevoUserPw.Visible = True
LNUserName.Visible = True
LNuevoUserPID.Visible = True
LNuevoUserPw.Visible = True
BAnularUser.Left = 3480
BAnularUser.Visible = True
BBorrarUser.Visible = False
BAnadirUser.Caption = "O.K."
Exit Sub
End If
If BAnadirUser.Caption = "O.K." Then
Dim NuevoUser As User
Set NuevoUser = Workspaces(0).CreateUser(TBNuevoUserName, TBNuvoUsePID,
TBNuevoUserPw)
Workspaces(0).Users.Append NuevoUser
TBNuevoUserName.Visible = False
TBNuvoUsePID.Visible = False
TBNuevoUserPw.Visible = False
LNUserName.Visible = False
LNuevoUserPID.Visible = False
LNuevoUserPw.Visible = False
BAnularUser.Visible = False
BBorrarUser.Visible = True

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 43


BAnadirUser.Caption = "Añadir"
ListUsers.Clear
For I = 0 To Workspaces(0).Users.Count - 1
NomUsuario = Workspaces(0).Users(I).Name
ListUsers.AddItem NomUsuario
Next I
BAnularUser.Visible = False
BAnadirUser.Visible = True
End If
RutErr:
If Err = 3304 Then
MsgBox "Debe introducir el PID (Mínimo 5 caracteres, máximo 20 caracteres)"
Exit Sub
Else
If Err > 0 Then MsgBox "Ha ocurrido el error " & Err & "."
End If
End Sub

Private Sub BAnadirWs_Click()


On Error GoTo RutErr
If BAnadirWs.Caption = "Añadir" Then
TBNuevoWorkspace.Visible = True
TBNombreUser.Visible = True
TBNuevoWSPw.Visible = True
LNWSName.Visible = True
LNombreUsuario.Visible = True
LUserPw.Visible = True
BAnularWS.Left = 5520
BAnularWS.Visible = True
BEliminarWs.Visible = False
BAnadirWs.Caption = "O.K."
Exit Sub
End If
If BAnadirWs.Caption = "O.K." Then
Dim NumWS As Integer
NumWS = Workspaces.Count
ReDim Preserve NuevoWS(NumWS)
Dim I As Integer, NomWS As String
Set NuevoWS(NumWS) = DBEngine.CreateWorkspace(TBNuevoWorkspace, TBNombreUser,
TBNuevoWSPw)
DBEngine.Workspaces.Append NuevoWS(NumWS)
ListWS.Clear
For I = 0 To DBEngine.Workspaces.Count - 1
NomWS = DBEngine.Workspaces(I).Name
ListWS.AddItem NomWS
Next I
BAnadirWs.Caption = "Añadir"
TBNuevoWorkspace = ""
TBNombreUser = ""
TBNuevoWSPw = ""
TBNuevoWorkspace.Visible = False
TBNombreUser.Visible = False
TBNuevoWSPw.Visible = False
LNWSName.Visible = False
LNombreUsuario.Visible = False
LUserPw.Visible = False
BAnularWS.Visible = False
BEliminarWs.Visible = True
End If
RutErr:

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 44


If Err = 3029 Then
MsgBox "El Password usado no coincide con el de ese Usuario (User)"
Exit Sub
End If
End Sub

Private Sub BAnularUser_Click()


If BAnadirUser.Caption = "O.K." Then
TBNuevoUserName.Visible = False
TBNuvoUsePID.Visible = False
TBNuevoUserPw.Visible = False
LNUserName.Visible = False
LNuevoUserPID.Visible = False
LNuevoUserPw.Visible = False
BAnularUser.Visible = False
BBorrarUser.Visible = True
BAnadirUser.Caption = "Añadir"
End If
If BBorrarUser.Enabled = True Then
BBorrarUser.Enabled = False
BAnadirUser.Visible = True
BAnularUser.Visible = False
ListUsers.ListIndex = -1
End If
End Sub

Private Sub BAnularWS_Click()


If BAnadirWs.Caption = "O.K." Then
BAnadirWs.Caption = "Añadir"
TBNuevoWorkspace = ""
TBNombreUser = ""
TBNuevoWSPw = ""
TBNuevoWorkspace.Visible = False
TBNombreUser.Visible = False
TBNuevoWSPw.Visible = False
LNWSName.Visible = False
LNombreUsuario.Visible = False
LUserPw.Visible = False
BAnularWS.Visible = False
BEliminarWs.Visible = True
End If
If BEliminarWs.Enabled = True Then
BEliminarWs.Enabled = False
BAnadirWs.Visible = True
BAnularWS.Visible = False
End If
End Sub

Private Sub BBorrarUser_Click()


Dim NomUsuario As String, I As Integer
Workspaces(0).Users.Delete ListUsers.Text
ListUsers.Clear
For I = 0 To Workspaces(0).Users.Count - 1
NomUsuario = Workspaces(0).Users(I).Name
ListUsers.AddItem NomUsuario
Next I
BAnularUser.Visible = False
BAnadirUser.Visible = True
End Sub

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 45


Private Sub BEliminarWs_Click()
Dim I As Integer, NomWS As String, NumWS As Integer
For I = 0 To DBEngine.Workspaces.Count - 1
NomWS = DBEngine.Workspaces(I).Name
If NomWS = ListWS.Text Then NumWS = I
Next I
Workspaces(NumWS).Close
ListWS.Clear
For I = 0 To DBEngine.Workspaces.Count - 1
NomWS = DBEngine.Workspaces(I).Name
ListWS.AddItem NomWS
Next I
BEliminarWs.Enabled = False
BAnularWS.Visible = False
BAnadirWs.Visible = True
End Sub

Private Sub BSalir_Click()


End
End Sub

Private Sub BVerIni_Click()


Shell "Notepad.exe " & App.Path & "\Cap20Usr.INI", vbNormalFocus
End Sub

Private Sub Form_Activate()


On Error GoTo RutErr
Dim LineaEntr As String
Dim LineaEntr8 As String
Dim I As Integer, NomUsuario As String
Dim PathFichero As String
Open App.Path & "\Cap20Usr.INI" For Input As #1
Do Until EOF(1)
Line Input #1, LineaEntr
LineaEntr8 = ""
LineaEntr8 = Left(LineaEntr, 8)
If UCase(LineaEntr8) = "PROYCAPT" Then Me.Caption = Right(LineaEntr, Len(LineaEntr) - 9)
If UCase(LineaEntr8) = "DBENGINI" Then PathFichero = Trim(Right(LineaEntr, Len(LineaEntr) -
9))
Loop
Close #1
LBDSys = PathFichero
TBTextINI = PathFichero
DBEngine.SystemDB = PathFichero
For I = 0 To Workspaces(0).Users.Count - 1
NomUsuario = Workspaces(0).Users(I).Name
ListUsers.AddItem NomUsuario
Next I
For I = 0 To DBEngine.Workspaces.Count - 1
NomUsuario = Workspaces(I).Name
ListWS.AddItem NomUsuario
Next I

RutErr:
If Err = 3028 Then
MsgBox "No se puede abrir la base de datos del sistema. Compruebe que su Path y nombre
son correctos. Vealo en Ver Ini"
End If
End Sub

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 46


Private Sub ListUsers_Click()
BAnadirUser.Visible = False
BBorrarUser.Enabled = True
BAnularUser.Left = 4560
BAnularUser.Visible = True
End Sub

Private Sub ListWS_Click()


BEliminarWs.Enabled = True
BAnadirWs.Visible = False
BAnularWS.Left = 6600
BAnularWS.Visible = True
End Sub

Private Sub Text1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As


Single)
If Shift = 1 And Button = 1 Then
VarDrag = Text1.Text
Text1.Drag
End If
End Sub

El fichero Cap20Usr.INI que debe estar necesariamente en la misma carpeta que el programa,
en el caso del PC del autor tiene esta forma

REM Visual Basic - Guía del Estudiante. Cap. 20. Creación de Usuarios y WorkSpaces
DBEngINI=C:\WinNT\System32\System.mdw

(Deberá cambiar el Path del fichero System.Mdw de acuerdo a como lo tenga en su ordenador.)

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 47


Mantenimiento y Copia de Bases de Datos.
Vamos a ver dos métodos del Objeto DBEngine para el mantenimiento y copia de Bases de
Datos ACCESS.

En una Base de Datos ACCESS, cuando borramos un dato en realidad no lo estamos borrando,
sino marcándolo como borrado. (No intente recuperar un dato marcado y no borrado porque no
se puede.) Por lo tanto, verá que tras sucesivas operaciones de escritura / borrado en una BD,
esta va aumentando su tamaño. Se necesita un método que limpie todos los datos inservibles
de la BD para disminuir su tamaño. Este método también deberá reorganizar los índices y
marcadores internos a esa BD. El objeto DAO que debe hacer estas cosas es el Motor de
Bases de Datos. Es decir, el Objeto DBEngine. Los métodos son CompactDatabase, que hace
una copia de la base de datos (no borra la BD original) sin copiar los datos inútiles, y
RepairDatabase, que intenta (no siempre lo consigue) reparar los datos internos de una BD
que presente datos corruptos (Se generan con bastante facilidad cuando apagamos el
ordenador con la base abierta)

Método CompactDatabase

Copia, compacta y da la opción de modificar la versión, el orden de intercalado y la codificación


de una base de datos cerrada.

Sintaxis

DBEngine.CompactDatabase BaseDatosAnt, BaseDatosNva [, inf_local [, opciones]]

BaseDatosAnt es el nombre del fichero de la base de datos a compactar. Debe expresar el


Path completo y el nombre del fichero (C :\MiCarpeta\MiBase.MDB) Si el nombre de archivo
tiene extensión, deberá especificarla. Si la red lo admite, también puede especificar una ruta de
red, como por ejemplo "\\MISERVID\MIDIR\MiBase.MDB".

BaseDatosNva es el nombre del fichero (con su Path completo) de la base de datos nueva,
creada al copiar la BaseDatosAnt, ya compactada. No es posible especificar en el argumento
BaseDatosNva el mismo archivo de base de datos que en BaseDatosAnt.

inf_local es una expresión de cadena utilizada para especificar el alfabeto usado a la hora de
ordenar datos de esa Base de Datos. El parámetro a introducir es el mismo que para el
argumento similar usado en la creación de la Base de Datos (dbLangGeneral para el caso de
España). Este argumento es opcional. Si se omite, la información local de BaseDatosNva será
la misma que la de BaseDatosAnt.

Opciones nos permite cambiar alguna característica de la Base de Datos. Puede elegirse entre
cifrarla o no cifrarla y cambiar la versión del motor de bases de datos que va a usar la nueva
Base de Datos.

dbEncrypt Codifica la base de datos durante la compactación.


dbDecrypt Descodifica la base de datos durante la compactación.
dbVersion10 Crea una base de datos que utiliza la versión 1.0 del motor Jet
dbVersion11 Crea una base de datos que utiliza la versión 1.1 del motor Jet
dbVersion25 Crea una base de datos que utiliza la versión 2.5 del motor Jet
dbVersion30 Crea una base de datos que utiliza la versión 3.0 del motor Jet

Se puede usar una constante (solamente) de encriptación y una (solamente) de Versión. Sólo
se puede compactar BaseDatosNva con una versión igual o posterior a la de BaseDatosAnt.

Lea detenidamente la ayuda en línea de este Método.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 48


Método RepairDatabase
Intenta reparar una base de datos dañada que accede al motor de base de datos Microsoft Jet.

Sintaxis DBEngine.RepairDatabase NombreBase

Donde NombreBase es el nombre (Y path) del fichero que contiene la Base de Datos a reparar.
Puede especificar una ruta de red. P.e. : "\\MISERVID\ MIDIR\NombreBase.MDB".

Para poder reparar la base debe estar Cerrada. Recuerde, si está en un entorno multiusuario,
que los demás usuarios tampoco pueden tenerla abierta mientras la repara.

El método RepairDatabase también intenta validar todas las tablas del sistema y todos los
índices. Los datos que no puedan repararse se pierden. Si la base de datos no puede
repararse, se producirá un error interceptable.

Sugerencia Después de reparar una base de datos, es aconsejable compactarla con el método
CompactDatabase para desfragmentar el archivo y recuperar espacio en disco.

METODOS DEL OBJETO DataBase

Método Execute
Este Método es para el Objeto DataBase y para el Objeto QueryDef.

Ejecuta una consulta de acciones o una instrucción SQL en el objeto Database especificado.

Sintaxis Para un objeto DataBase NombreBD.Execute origen[, opciones]

Donde NombreBD es el nombre del objeto DataBase


Origen es una instrucción SQL
Opciones es un entero o constante que determina las características de integridad de
datos de la consulta, según se especifica mas adelante.

Para un objeto QueryDef NombreQuerydef.Execute [opciones]

Donde NombreQuerydef es el nombre del objeto QueryDef cuya propiedad SQL especifica la
instrucción SQL a ejecutar.
Opciones igual que para el Objeto Database.

En opciones puede utilizar las siguientes constantes:

dbDenyWrite Deniega el permiso de escritura a los demás usuarios.


dbInconsistent (Predeterminado) Actualizaciones inconsistentes.
dbConsistent Actualizaciones consistentes.
dbSQLPassThrough Paso a través de SQL. Hace que se pase la instrucción SQL a una
base de datos ODBC para su procesamiento.
dbFailOnError Deshace las actualizaciones en caso de error.
dbSeeChanges Genera un error en tiempo de ejecución si otro usuario modifica los
datos que se están editando.

El método Execute sólo es válido para las consultas de acciones. Si utiliza Execute con otro tipo
de consultas, se producirá un error. Debido a que las consultas de acciones no devuelven
registros, Execute no devuelve un conjunto de registros.

Ejemplo. En el siguiente ejemplo, usamos EXECUTE para cambiar el campo Nombre en una
tabla llamada CLIENTES de una Base de Datos abierta, cuyo Objeto DataBase se llama

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 49


BaseDatos. Para poder “jugar” con el nombre a cambiar y el nombre cambiado, se introduce el
nombre que queremos cambiar en TBNombre2 y el nuevo nombre en TBNombre1

Dim RegistrosCambiados As Long


Dim MiSQL As String

MiSQL = "UPDATE CLIENTES SET NOMBRE = '" & TBNombre2 & "' WHERE NOMBRE= '" &
TBNombre1 & "'"

BaseDatos.Execute MiSQL, dbFailOnError


RegistrosCambiados = BaseDatos.RecordsAffected
MsgBox RegistrosCambiados

Dada una instrucción SQL sintácticamente correcta y teniendo los permisos adecuados, el
método Execute no fallará, aún cuando no pueda modificarse ni eliminarse una línea. Por lo
tanto, debe especificar siempre la opción dbFailOnError cuando utilice el método Execute para
ejecutar una consulta de actualización o eliminación. Esta opción generará un error
interceptable y deshará todos los cambios realizados con éxito cuando alguno de los registros
afectados se encuentre bloqueado y no pueda actualizarse o eliminarse.

Propiedad RecordsAffected
Para determinar el número de registros afectado por el último método Execute, puede utilizar la
propiedad RecordsAffected del objeto Database o Querydef. Por ejemplo, RecordsAffected
contienen el número de registros eliminados, actualizados o insertados al ejecutar una consulta
de acciones. Al utilizar el método Execute para ejecutar un objeto Querydef, en la propiedad
RecordsAffected del Querydef se establece el número de registros afectados.

Para obtener el mejor rendimiento, especialmente en un entorno multiusuario, puede anidar el


método Execute dentro de una transacción: Utilice el método BeginTrans en el objeto
Workspace actual, use luego el método Execute y complete la transacción con el método
CommitTrans en el objeto Workspace. De esta forma se guardarán los cambios en el disco y se
liberarán los bloqueos que se hayan podido producir durante la ejecución de la consulta.

IMÁGENES EN UNA BASE DE DATOS ACCESS

Una imagen (la fotografía de una persona por ejemplo) puede guardarse en una base de datos
tipo ACCESS y presentarse en un control Picture. ¡¡ Imagine una aplicación que sea una
agenda de teléfonos y pueda insertar la foto de la persona !!

Para introducir una imagen en una BD, el campo de esa BD donde se va a introducir la imagen
debe ser LongBinary ( si esa versión de ACCESS lo tiene) u Objeto OLE.

Introducir y presentar un bit-map en una base de datos es necesario hacerlo mediante un


Control Data. Un bit-map puede presentarse en un control Picture o en un control Image.
Ambos son controles enlazados a datos. Si introducimos un Control Data y un Control Picture
o Control Image en el Formulario, asociamos el Control Data a la Base de Datos, y el campo
que contiene el gráfico a el Control Picture (o Control Image) mediante sus propiedades
DataSource = Nombre del Control data, DataField = Nombre del Campo, tenemos el problema
resuelto. Para meter un gráfico en la BD basta con introducir ese gráfico en el Picture (o Image)
mediante LoadPicture, por ejemplo, y guardar los datos en la BD, bien cambiando el registro
actual del Control data, bien mediante el método UpdateRecord de dicho Control Data.

La asociación de la Base de datos al Control Data puede hacerse, bien mediante sus
propiedades DatabaseName y RecordSource, bien creando un Recordset con código e
igualando la propiedad Recordset del Control Data a ese Recordset.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 50


Es posible que se pueda introducir y presentar un bit-map en un control Picture o Image de otra
forma, sin usar el control Data. Eso sí, complicando el código. No merece la pena liarse con
esto. Lo mismo que decíamos que necesitamos un Control Data cuando vamos a usar un
DBGrid, debemos usar un Control Data cuando vayamos a presentar una imagen.

LSB Visual Basic - Guía del Estudiante Capítulo 12 Página 51


Visual Basic - Guía del Estudiante Cap. 13
Acceso a Bases de Datos remotas mediante el motor Jet
ODBCDirect
Acceso a Bases de Datos remotas mediante objetos RDO

Acceso a Bases de Datos remotas mediante el motor Jet


ODBCDirect

Hasta ahora todos los accesos realizados a una base de datos los hemos realizado
directamente a través del Motor de bases de Datos Microsoft JET. Este motor de bases de
datos abre, lee y graba el fichero .MDB (o el dBase, FoxPro, Paradox, etc.) de la misma forma
que un editor de textos puede abrir, leer o escribir un fichero creado por el mismo o por otros
editores conocidos.

Las bases de datos (las buenas) tienen unas herramientas comunes para manejarlas. Estas
herramientas son, por una parte el lenguaje SQL que puede dar instrucciones para leer o
escribir una base abierta, mediante un lenguaje común para todas las bases, y por otra, la
herramienta que abre esa base de datos y nos hace verla, desde el exterior, bajo una forma
única para todas las bases: el ODBC.

El ODBC es una herramienta que nos permite ver a todas las bases de una forma única. No es
un lenguaje común a todas las Bases de datos. Ese es el SQL. Es la interface que adapta a una
base de datos para que nos podamos entender con ella en SQL. Por lo tanto es fácil pensar
que esa interface deberá fabricarla el mismo fabricante que ha realizado la base de datos. El
lenguaje SQL es conocido por todo el mundo, pero la forma interna de trabajar una base de
datos solamente la conoce su fabricante. Por eso, el Driver ODBC que es el que nos permite
adaptar las particularidades de esa base de datos al lenguaje común, deberá suministrarlo el
fabricante de la base.

Microsoft desarrolló varios drivers para otras tantas bases de datos y hojas de cálculo. Entre
ellas para Access y Excel, dBase y FoxPro. También lo desarrolló para bases de datos tan
populares como Oracle. Ese driver hay que instalarlo en el ordenador, aunque Windows instala
algunos por defecto.

Veamos ahora otro elemento fundamental para el trabajo con ODBC: la conexión. La conexión
ODBC es el conjunto de datos que hay que aportarle a Windows para que pueda enlazar
nuestra aplicación con la base de datos. Estos datos son, al menos:

El nombre de la conexión, por el cual la podremos nombrar para referirnos a ella.


El driver que debe utilizar para entenderse con la base de datos
El nombre (y Path) de la base de datos que queremos manejar con esa conexión.

La conexión ODBC no la realiza Visual Basic. La realizará Windows. Veamos como podemos
establecerla.

Vaya a Inicio | Configuración | Panel de Control | ODBC de 32 Bits. Haga doble click y le
aparecerá un cuadro como el de la figura 13-1. En este cuadro figuran todos los enlaces que
están establecidos. Estos enlaces puede establecerlos para un usuario (DSN de usuario), de
sistema o de archivo. La elección de uno u otro dependerá de los permisos de acceso que
quiera establecer (y eso es, de momento, para nota). En cualquier caso, todas los enlaces
ODBC que establezca funcionarán del mismo modo, exceptuando que puede otorgar unas
prerrogativas distintas de uso, dependiendo de como lo haya abierto.

Observe uno que figura en la lista: Luki. En esa línea figura otro dato: Microsoft Access
Driver.(*.mdb) Esto significa que el enlace de nombre Luki está usando el driver ODBC de
Access. Y significa también que si queremos llamar a esa conexión deberemos llamarla por su
nombre : Luki

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 1


Fig. 13-1 Creación de un enlace ODBC. Muestra las conexiones existentes (una vez creada la
conexión Luki)

Sigamos con la creación del enlace ODBC. Para crear uno nuevo, haga click en el botón
Agregar de la figura 13-1. Le aparecerá un cuadro donde le pide el driver que quiere utilizar.

Fig. 13 – 2 Elección del driver ODBC

Haciendo click en Finalizar, le pedirá el nombre del nuevo enlace, un comentario, (no es
necesario introducirlo), y la base de datos con la que quiere enlazar

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 2


Fig. 13-3 Introducción del nombre del enlace, comentario (descripción) y base de datos
asociada al enlace ODBC

Veamos los datos que hemos introducido en nuestra conexión “Luki”

Nombre del Origen de datos. Luki


Descripción (Opcional) Conexión ODBC Cap. 21

Haciendo click en Base de Datos | Seleccionar nos muestra un cuadro de diálogo donde
`podemos buscar la base de datos. Se elige la base de datos deseada. Hacemos click en
ACEPTAR y ya está creada la nueva conexión.

La base de datos del sistema deberá elegirla para poder introducir usuarios con distintas
atribuciones de acceso a la base de datos. Si no introduce esta base de datos de sistema,
deberá trabajar sin restricción de acceso.

Una vez creada la conexión podemos utilizarla para conectar nuestra aplicación con la base de
datos. El proceso para ello consiste en algo parecido a lo que hacíamos trabajando con el motor
Jet en el espacio de trabajo Microsoft Jet, pero de distinta forma. En ese entorno se manejaba
la base de datos creando un objeto Database, que manipulaba el fichero de la base de datos
directamente. En este caso, la base de datos se maneja mediante un objeto Connection.

El trabajar sobre una conexión nos aporta mayor versatilidad a las aplicaciones. Piense por
ejemplo un caso en el que se emplea una base de datos Access. Si quisiésemos ampliar las
prestaciones de la base de datos de esa aplicación posiblemente pensaríamos en migrar la BD
a Oracle o SQLServer. Si atacamos a la base de datos a través de ODBC solamente
deberíamos cambiar la conexión, tal como vimos más atrás. Nuestro programa seguiría
llamando a la misma conexión ODBC, pero esta conexión, ahora, abriría una base Oracle o
SQLServer en vez de la Access que abría originalmente. No necesitaríamos realizar ninguna
modificación en nuestro programa.

Este razonamiento es válido para cualquier sistema de acceso a bases de datos a través de
ODBC. (RDO ó ADO) Sin embargo el ODBCDirect tiene una ventaja `para los que trabajamos
normalmente con DAO: usa los mismos nombres para casi todos los métodos y funciones, por
lo que el cambio de código es mínimo. El cambio se limita prácticamente a crear el objeto
Connection en vez del objeto Database. Comencemos a ver esto con u ejemplo. Es un ejemplo
uy simple, en el que abrimos una base de datos Access llamada Alumnos.Mdb que tiene una
tabla llamada Personas. Creamos la conexión Luki tal como se describió mas atrás. La tabla

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 3


personas tiene solamente tres campos: ID_Alumno, Nombre y Apellidos. Creamos una
interface gráfica sencilla

Fig. 13-4 Nuestra primera aplicación con ODBCDirect

Mediante esta sencilla aplicación queremos visualizar los datos existentes, añadir nuevos
registros y borrar el registro actual. Veamos el código con los comentarios oportunos.

General/Declaraciones
Option Explicit 'Declaramos las variables tipo objeto
Dim MiSesion As Workspace
Dim MiConexion As Connection
Dim RsODBC As Recordset

Private Sub BCrearConexion_Click()


'Se le dice al DBEngine que debe trabajar en el espacio de trabajo ODBCDirect
DBEngine.DefaultType = dbUseODBC
Set MiSesion = Workspaces(0)
'Se crea el objeto conexión
Set MiConexion = MiSesion.OpenConnection("Conexion1", dbDriverNoPrompt, False,
"ODBC;DSN=Luki")
´Se crea el objeto Recordset
Set RsODBC = MiConexion.OpenRecordset("Personal", dbOpenDynamic, dbRunAsync,
dbPessimistic)
'Es necesario recorrer el recordset para conocer cuantos registros tiene (Es Dynaset)
RsODBC.MoveLast
RsODBC.MoveFirst
If RsODBC.AbsolutePosition <> -1 Then
LNumRegs = RsODBC.RecordCount
LNumReg = RsODBC.AbsolutePosition + 1
PresentaDatos
Else
MsgBox "La base de datos no tiene ningún registro"
End If
End Sub

Public Sub PresentaDatos()


TB_ID = "": TB_Nombre = "" : TB_Apellido = ""
TB_ID = RsODBC!ID_Alumno
TB_Nombre = RsODBC!Nombre

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 4


TB_Apellido = RsODBC!Apellidos
LNumReg = RsODBC.AbsolutePosition + 1
End Sub
Private Sub BEliminar_Click()
RsODBC.Delete
LNumRegs = RsODBC.RecordCount
LNumReg = RsODBC.AbsolutePosition + 1
If RsODBC.AbsolutePosition <> -1 Then
RsODBC.MoveFirst
PresentaDatos
End If
End Sub

Private Sub BGuardarDatos_Click()


RsODBC.AddNew
RsODBC!ID_Alumno = TB_ID
RsODBC!Nombre = TB_Nombre
RsODBC!Apellidos = TB_Apellido
RsODBC.Update
LNumRegs = RsODBC.RecordCount
LNumReg = RsODBC.AbsolutePosition + 1
End Sub

Private Sub BMas_Click()


If RsODBC.AbsolutePosition <> -1 Then
RsODBC.MoveNext
If RsODBC.AbsolutePosition <> -1 Then
PresentaDatos
Else
RsODBC.MoveLast
PresentaDatos
End If
End If
End Sub

Private Sub BMenos_Click()


If RsODBC.AbsolutePosition <> -1 Then
RsODBC.MovePrevious
If RsODBC.AbsolutePosition <> -1 Then
PresentaDatos
Else
RsODBC.MoveFirst
PresentaDatos
End If
End If
End Sub

Private Sub BMMas_Click()


If RsODBC.AbsolutePosition <> -1 Then
RsODBC.MoveLast
PresentaDatos
End If
End Sub

Private Sub BMMenos_Click()


If RsODBC.AbsolutePosition <> -1 Then
RsODBC.MoveFirst
PresentaDatos
End If
End Sub

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 5


Private Sub BNuevoReg_Click()
Limpia
End Sub
Public Sub Limpia()
TB_ID = ""
TB_Nombre = ""
TB_Apellido = ""
End Sub

Observe que casi todo el código es igual que el que escribiríamos si hubiésemos utilizado el
espacio de trabajo Microsoft Jet. Solamente hemos utilizado código distinto el procedimiento
BCrearConexion_Click. Vamos a analizar las instrucciones de ese procedimiento que son
distintas a las que estamos acostumbrados a manejar

DBEngine.DefaultType = dbUseODBC
Vea la propiedad DefaultType en el Capítulo 20. Tenga en cuenta que el ODBCDirect lo ejecuta
el motor Jet (que como recordará es el objeto DBEngiine). La propiedad DefaulType debemos
igualarla a dbUseODBC para que trabaje en el espacio de trabajo ODBCDirect. Si no le
diésemos ningún valor a esa propiedad, tomaría el otro valor posible (dbUseJet) que es su valor
por defecto. Por eso, cuando utilizábamos los métodos CreateDataBase u OpenDatabase no
necesitábamos darle ningún valor a esa propiedad.

Set MiConexion = MiSesion.OpenConnection("Conexion1", dbDriverNoPrompt, False,


"ODBC;DSN=Luki")

Vea mas abajo la información de OpenConnection para ver los parámetros que hay que pasarle
a este método.

Set RsODBC = MiConexion.OpenRecordset("Personal", dbOpenDynamic, dbRunAsync,


dbPessimistic)

Vea mas abajo una ampliación del método OpenRecordset

Método OpenConnection
Es un método del Workspace que solamente es aplicable cuando el DBEngine está trabajando
en el espacio de trabajo ODBCDirect. Abre un objeto Connection usando un origen de datos
ODBC ya creado.

El objeto Connection sería el equivalente en DAO al objeto Database. Debemos declararlo


antes de usarlo

Dim MiConexion as Connection

Si MiSesion es el Workspace que queremos usar, la sintaxis de OpenConnection es la


siguiente:

Set MiConexion = MiSesion.OpenConnection (Nombre, Opciones, Sólolectura y Conectar)

En el ejemplo:
Set MiConexion = MiSesion.OpenConnection("Conexion1", dbDriverNoPrompt, False,
"ODBC;DSN=Luki")

Veamos que son los parámetros Nombre, Opciones, Sólolectura y Conectar

Nombre es el nombre de la conexión (no se debe confundir con el nombre del objeto
Connection que es MiConexion, y que es el nombre por el que nos tendremos que referir a esa
conexión en toda la aplicación. Nombre no lo usará normalmente)

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 6


El parámetros Nombre puede ser una cadena cualquiera, o el nombre del enlace ODBC
establecido en Windows (que en nuestro ejemplo sería Luki). Si opta por poner una cadena
cualquiera (como hicimos en el ejemplo, Conexión1) deberá poner el nombre del enlace ODBC
en el parámetro Conectar. Si opta por poner el nombre del enlace ODBC, Visual Basic
interpreta que debe conectar a través de ese enlace y ya no necesita poner ningún valor al
parámetro Conectar.

Opciones Este parámetro es para definir que tipo de respuesta va a dar el administrador del
controlador de ODBC para solicitar al usuario información sobre la conexión (Nombre del origen
de datos (DSN), nombre del usuario y contraseña). Puede tomar uno de los siguientes valores:

DbDriverNoPrompt El administrador del controlador de ODBC toma los datos de los


parámetros Nombre y Conectar para saber cual es el enlace ODBC que debe usar. Si
no proporciona suficiente información, se producirá un error de tiempo de ejecución.

DbDriverPrompt El administrador del controlador de ODBC muestra el cuadro de


diálogo de ODBC, que muestra todos los enlaces ODBC existentes. La conexión se
hace con el DSN que selecciona el usuario en ese cuadro de diálogo.

Fig. 13.5 Cuadro de diálogo de ODBC

Una vez seleccionada la conexión, aparecerá otro cuadro solicitando el nombre de inicio de
sesión y la contraseña. En resumen, con este parámetro DbDriverPrompt forzamos al
programa a que utilice los recursos Windows para seleccionar el enlace ODBC

DbDriverComplete (Este es el valor predeterminado). Se comporta (aparentemente)


como si se pone DbDriverNoPrompt

DbDriverCompleteRequired Al igual que la anterior, esta opción se comporta


(aparentemente) como si se pone DbDriverNoPrompt

Sólolectura (Opcional). True si la conexión se va a abrir con acceso de sólo lectura y False si
la conexión se va a abrir para acceso de lectura/escritura (predeterminado)

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 7


Conectar (Opcional si se ha puesto el nombre del enlace en el parámetro Nombre). Este
parámetro está formado por varias partes. Una, obligatoria, que contiene la expresión "ODBC;"
Otra parte obligatoria, si no ha puesto en el parámetro Nombre el nombre del enlace ODBC es
"DSN = NombredelaConexión;" Si desea especificar el usuario propietario de esa conexión
debe añadir "UID = usuario;" y como ese usuario tendrá una contraseña, deberá añadirla
también "PWD = contraseña;" También puede indicar cuanto tiempo debe esperar el
administrador del controlador de ODBC para generar un error en caso de que no conteste el
sistema a la petición ODBC. Este tiempo deberá introducirlo con la expresión "LOGINTIMEOUT
= segundos;" Observe que cada una de estas partes lleva un identificador y un dato, ambos
separados por un signo =, y siempre terminan con el signo punto y coma (;)

Si omite los parámetros UID y/o el PWD, estos datos se obtendrán de las propiedades
UserName y Password del objeto Workspace.

Método OpenRecordset
Este método ya se estudió en el capítulo anterior, pero se van a ver ciertas peculiaridades que
tiene cuando se abre un recordset en el espacio de trabajo ODBCDirect

En este caso es el objeto Connection quien abre el recordset.:

Set MiRecordset =
= MiConexion.OpenRecordset (Origen, Tipo, Opciones, Bloquearmodificaciones)

Origen Puede ser un nombre de tabla, de una consulta o una instrucción SQL que devuelva
registros.
Tipo Indica el tipo de recordset que queremos crear. El espacio de trabajo ODBCDirect no
permite recordsets tipo Tabla. Los tipos que se pueden elegir son:

DbOpenDynamic Abre un objeto Recordset de tipo Dynamic, que es parecido a un


cursor dinámico ODBC
DbOpenDynaset Abre un objeto Recordset de tipo Dynaset, similar al estudiado en el
capítulo 20 para el espacio de trabajo Microsoft Jet
DbOpenSnapshot Abre un objeto Recordset de tipo Snapshot,
dbOpenForwardOnly Abre un objeto Recordset de tipo Forward-only, que tiene la
particularidad de que no permite movernos en el recordset de adelante hacia atrás.
Este es el tipo que creará por defecto si no se especifica nada en el parámetro Tipo.

Opciones Debe indicar uno de estos dos valores (si no pone alguno de ellos da error):

DbRunAsync Ejecuta una consulta asíncrona, que es la forma normal de trabajar del
ODBC. Esto permite a su aplicación seguir procesando otras instrucciones mientras se
ejecuta la consulta en segundo plano (Vea mas adelante la propiedad StillExecuting
dbExecDirect Ejecuta una consulta saltando el método SQLPrepare y llamando
directamente al método SQLExecDirect. Utilice esta opción sólo cuando no se abra un
objeto Recordset basándose en una consulta de parámetros. Para obtener más
información, consulte la "Referencia del programador de Microsoft ODBC 3.0."

Bloquearmodificaciones Este parámetro es fundamental si quiere escribir en la base de


datos, pues si lo omite le pone por defecto que la base es de solo lectura. Mediante este
parámetro va a determinar el tipo de bloqueo de la base de datos para entornos de trabajo
multiusuario. Puede poner uno de estos valores:

DbReadOnly (Predeterminado) No permite que los usuarios hagan cambios en los


registros del Recordset
DbPessimistic Permite cambiar datos y añadir registros en el recordset, utilizando el
criterio de bloqueo pesimista. Esto significa que bloquea la página donde se encuentra
el registros desde que se ejecuta el método Edit hasta que se ejecuta el Update. Es el

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 8


criterio mas seguro de bloqueo de datos, pero debe tener en cuenta que tiene la base
bloqueada desde el Edit hasta el Update. Si hace bloqueo pesimista, procure que las
instrucciones entre uno y otro no tengan ningún tiempo de espera, por ejemplo a que el
usuario introduzca un dato. (El tamaño de una página depende de la base de datos que
esté usando. En Access es de 2048 Bytes. Esto significa que solamente tendrá
bloqueada una parte relativamente pequeña de la base de datos, pudiendo modificar
otros registros que estén fuera de ese segmento de 2 Kbytes. Lógicamente este
bloqueo solamente tendrá efecto cuando esté trabajando en un entorno multiusuario.

DbOptimistic Permite cambiar datos y añadir registros en el recordset, utilizando el


criterio de bloqueo optimista. El bloqueo optimista significa que solamente estará
bloqueada la página que contiene el registro mientras se ejecuta el método Update.
Esto puede ocasionarle que, si están dos usuario trabajando sobre el mismo registro,
se introduzca un dato erróneo. Parece así en principio que no se debe usar, pero todo
va a depender de la aplicación, de sus datos, y de la probabilidad de que ocurra esa
colisión. La ventaja que tiene es que tiene menos tiempo bloqueada la página de la
base de datos.

dbOptimisticValue Utiliza la concurrencia optimista basándose en valores de fila.


Funciona de forma similar al dbOptimistic.

dbOptimisticBatch Activa la actualización optimista por lotes.

Actualización por lotes. Modelo de cursor para clientes que trabajan con cursores, pero no
mantienen bloqueos en el servidor o ejecutan actualizaciones por fila. En su lugar, el cliente
actualiza muchas filas que están almacenadas en el búfer local y después ejecuta una
actualización por lotes. Este modelo de cursor también permite al cliente cancelar la conexión
con el servidor y volverla a establecerla con el mismo servidor o con otro diferente.

Para utilizar la actualización por lotes en DAO 3.5, debe utilizar un espacio de trabajo de
ODBCDirect, la propiedad DefaultCursorDriver se debe establecer a dbUseClientBatchCursor
en el momento de abrir la conexión y se debe abrir el Recordset con el argumento de tipo de
bloqueo del método OpenRecordset establecido a dbOptimisticBatch.

Propiedad StillExecuting
Cuando abrimos una conexión mediante OpenConnection, un QueryDef o creamos un
recordset y le ponemos en Opciones DbRunAsync, la operación se realiza de forma asíncrona,
por lo tanto no sabemos cuando tendremos disponible el objeto a crear o los datos de la
consulta. Para poder controlar si la operación se está realizando todavía leeremos la propiedad
StillExecuting, que devolverá True si todavía se está ejecutando, y False si ha terminado.
Basta con hacer un bucle del tipo

Do While MiConexion.StillExecuting = True


DoEvents
Loop

Mientras la propiedad StillExecuting sea True, no se puede tener acceso a ningún objeto
devuelto. Por ejemplo, no pretenda crear un recordset con MiConexion Mientras que
StillExecuting sea True, pues MiConexión no existe aún.

Esta propiedad puede ser muy útil cuando tiene consultas encadenadas y necesita esperar a
que termine una para comenzar con la siguiente.

StillExecuting se utiliza con los objetos y para las operaciones siguientes:

Objeto Connection, para controlar que aún se está ejecutando uno de los métodos Execute u
OpenConnection

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 9


Objeto QueryDef, para comprobar su método Execute
Recordset, donde podrá comprobar si aún se están realizando los métodos Move,
NextRecordset u OpenRecordset

Para ver el valor que tiene la propiedad StillExecuting deberá poner el nombre del objeto que
quiere comprobar (Connection, QueryDef o Recordset) después de haber iniciado uno de los
métodos citados anteriormente. Por ejemplo, para esperar a que se haya creado el objeto
Connection MiConexion, haremos un bucle de la siguiente forma

Set MiConexion = MiSesion.OpenConnection("Luki1", dbDriverNoPrompt)


Do While MiConexion.StillExecuting = True
Aquí las instrucciones que quiera
Loop

Método Cancel
Cancela la ejecución de un método asícrono de llamada. Sólo funciona espacios de trabajo
ODBCDirect.

Sintaxis objeto.Cancel

La sintaxis del método Cancel consta de las siguientes partes:

Objeto puede ser:


Connection para cancelar el método Execute u OpenConnection
QueryDef, para cancelar el método Execute
Recordset para cancelar el método OpenRecordset

El método Cancel solamente sirve para cancelar la ejecución de una llamada asíncrona de los
métodos Execute, OpenConnection u OpenRecordset que se hayan invocado con la opción
dbRunAsync. Cancel devolverá un error de tiempo de ejecución si en el método que está
intentando finalizar no se utilizó dbRunAsync.

Objetos Database y QueryDef en el espacio de trabajo ODBCDirect


Repasemos la estructura jerárquica de los objetos de acceso a datos en el espacio de trabajo
ODBCDirect. Podemos ver que siguen existiendo, aparte de los ya estudiados en este capítulo,
dos objetos que ya nos son conocidos: el QueryDef y el Database. Veamos cada uno de ellos.

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 10


Fig. 13-6 Estructura jerárquica de los objetos de acceso a datos en el espacio ODBCDirect

Objetos QueryDef en el espacio de trabajo ODBCDirect


Habíamos visto en el capítulo 20 que un QueryDef era una consulta cuando todavía no estaba
guardada en el disco. Es decir, un QueryDef es una consulta en memoria RAM. Ese QueryDef
se transforma en una consulta de la base de datos una vez que se cierra el objeto Database.

En el espacio de trabajo ODBCDirect no se pueden crear bases de datos. Se pueden crear


objetos QueryDef, que en este caso serán objetos efímeros, que solamente existirán en la
memoria RAM, desapareciendo en el momento que cerremos ese QueryDef o cerremos la
aplicación.
Puede crear un QueryDef para crear posteriormente a partir de él un Recordset con el que
puede presentar o escribir el contenido de los registros. En el siguiente ejemplo hemos abierto
la conexión, y como paso previo a la creación del recordset hemos creado un QueryDef con
todos aquellos registros cuyo campo Apellidos sea igual a Alvarez Pérez. Una vez creado ese
QueryDef, hemos creado un recordset a partir de él. No tiene mucho sentido hacer esto ya que
podríamos crear directamente el recordset imponiendo esa condición en el campo Apellidos. Se
expone aquí con fines didácticos, no prácticos.

DBEngine.DefaultType = dbUseODBC
Set MiSesion = Workspaces(0)
Set MiConexion = MiSesion.OpenConnection("Conexion1", dbDriverNoPrompt, False,
"ODBC;DSN=Luki")
Set MiConsulta = MiConexion.CreateQueryDef ("Pepito", "Select * From Personal Where
Apellidos = "Alvarez Pérez")
Set RsODBC = MiConsulta.OpenRecordset(dbOpenDynaset, dbRunAsync, dbOptimistic)
If RsODBC.AbsolutePosition <> -1 Then
RsODBC.MoveLast
RsODBC.MoveFirst
LNumRegs = RsODBC.RecordCount
LNumReg = RsODBC.AbsolutePosition + 1
PresentaDatos
Else
MsgBox "El recordset no tienen ningún registro"
End If

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 11


Puede apreciar en la fig. 13-6 otro objeto que está jerárquicamente debajo del QueryDef. El
Objeto Parameter. Este objeto sirve para cambiar los parámetros que se le pasan al QueryDef
para crearlo. Le remito a la ayuda de VB para mayor explicación de este objeto.

El objeto Database en el espacio de trabajo ODBCDirect


En el espacio ODBCDirect puede también abrir un objeto Database en vez de un objeto
Connection. La diferencia a la hora de crear un objeto Database (abrir una base d e datos) entre
el espacio de trabajo Microsoft Jet y ODBCDirect es que en el primero abrimos directamente el
fichero de la base de datos, y en el segundo, abrimos el fichero que indique el enlace ODBC.
Deberemos suministrarle información del enlace ODBC que debe usar. La sintaxis sigue siendo
igual que en el espacio de trabajo Microsoft Jet:

Set MiBaseDatos = MiSesion.OpenDatabase (Nombre, Opciones, Sólolectura, Conexión)

Para indicarle el enlace ODBC que debe usar puede hacerlo de las dos formas que venimos
viendo para los parámetros Nombre y Conexión. Si indica el nombre del enlace en el parámetro
Nombre lo aceptará y será necesario poner el parámetro Conexión. Si `pone un nombre
cualquiera en el parámetro Nombre deberá indicar el nombre del enlace en el parámetro
Conexión.

Esta posibilidad de crear un objeto Database nos aproxima aún más al código empleado en el
espacio de trabajo Microsoft Jet. Por lo tanto puede ser muy útil usar este objeto en aquellos
casos en los que ya se había escrito el código, y pasamos posteriormente a usar ODBC.

DBEngine.DefaultType = dbUseODBC
Set MiSesion = Workspaces(0)
'En la siguiente línea le pasamos el nombre del enlace ODBC en el parámetro Nombre
Set MiBaseDatos = MiSesion.OpenDatabase("Luki", dbDriverNoPrompt)
'Pero podríamos haberselo pasado en el parámetro Conexión y ponerle como parámetro
'nombre cualquier cadena de caracteres
Set MiBaseDatos =
MiSesion.OpenDatabase("BaseDatos1", dbDriverNoPrompt, False, "ODBC;DSN=Luki")
'Ahora creamos el recordset, como en los otros casos
Set RsODBC = MiBaseDatos.OpenRecordset("Personal", dbOpenDynaset, dbRunAsync,
dbOptimistic)
If RsODBC.AbsolutePosition <> -1 Then
RsODBC.MoveLast
RsODBC.MoveFirst
LNumRegs = RsODBC.RecordCount
LNumReg = RsODBC.AbsolutePosition + 1
PresentaDatos
Else
MsgBox "La base de datos no tiene ningún registro"
End If

Mediante los ejemplos expuestos en este capítulo espero que el alumno comprenda como
trabaja DAO a través de ODBC, mediante el ODBCDirect.
No olvide que sigue tratándose de DAO, y que por lo tanto deberá poner la misma referencia
(En Proyecto | referencia) que en el caso del DAO trabajando en el espacio de trabajo Microsoft
Jet. En la siguiente parte de este capítulo se estudiarán los objetos RDO, objetos que trabajan
exclusivamente a través de ODBC. Con las ideas captadas hasta aquí verá que es sencillo
abordar estos nuevos objetos.
Visual Basic - Guía del Estudiante Cap. 13 Continuación
Acceso a Bases de Datos remotas mediante objetos RDO

En la primera parte de esta capítulo hemos visto como acceder a bases de datos a través de
ODBC usando el motor JET. El acceso se realizaba mediante ODBCDirect, modo de
operación del motor JET, y podíamos usar la misma sintaxis y objetos que habíamos visto con

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 12


los objetos DAO. También vimos como crear un enlace ODBC, enlace que vamos a utilizar en
este capítulo. Como ya se explicó en el capítulo anterior, damos por supuesto que el alumno
conoce como crear ese enlace.

Los objetos RDO se crearon para cubrir el hueco que tenía VB para conectar con bases de
datos distintas a las que trabaja el motor JET. (Access, dBase, FoxPro, etc.). Esta forma de
trabajar nos permite enlazar con bases de datos tipo Oracle o SQLServer, pero también nos
permite trabajar con Access, dBase o FoxPro, que también tienen su propio driver ODBC.

Lo primero que nos encontramos al trabajar con RDO es que es más lento que DAO. Si
creamos dos aplicaciones que trabajen sobre una base Access, una directamente a través de
DAO y otra a través de RDO, observaremos que la primera accede a la BD con una rapidez
mayor que la segunda. Normal, no es lo mismo abrir un fichero y leerlo (que es lo que hace
DAO) que pasar unos parámetros a otro programa (Driver ODBC de Access) para que este
abra el fichero, obtenga los datos y nos los pase. Lo mismo podemos decir cuando tenemos
que contar registros, movernos de un registro a otro, editar o añadir nuevos registros. Esa falta
de rapidez es el coste de la tecnología de bases abiertas.

Lo segundo que nos va a llamar la atención es el nombre de los objetos de acceso a datos. Una
vez que nos habíamos familiarizado con palabras como Recordset, DataBase o Dynaset, nos
las cambian por rdoResultset, rdoConnection o Keyset respectivamente. Y lo peor no es
solamente tener que aprender sus nombres, sino que en una aplicación hecha en DAO que sea
necesaria cambiarla a RDO, nos vemos obligados a retocar la mayor parte de las líneas de
código (Cosa que no ocurría con ODBCDirect)

Y lo tercero, RDO no tiene la posibilidad de crear bases de datos como hacíamos en DAO.
Normal, ya que en este caso no trabajamos directamente sobre la BD sino sobre la conexión
ODBC que Windows realizó a una base de datos. Podemos añadir mas desventajas de RDO:
no puede contar los registros que tiene, tiene un comportamiento muy irregular con la propiedad
AbsolutePosition, y varios detalles que procuraremos explicar en este capítulo para ahorrar al
alumno el trabajo de tener que experimentarlos por sí mismo. (Aunque, consejo de viejo
profesor, es la forma más segura de aprenderlos).

Tras estos inconvenientes parece lógico encontrar alguna contrapartida positiva. Por ejemplo
poder conectar con cualquier tipo de base de datos, pudiendo incluso realizar la aplicación
atacando una base Access, para luego trabajar con una base SQLServer u Oracle sin variar ni
una línea de código. Esa debería ser la gran ventaja de RDO. Pero lamentablemente, y en
contra de toda teoría de ODBC, no es cierto. Si preparamos una aplicación en RDO trabajando
con una base Access y pretendemos cambiar la base por otra SQLServer, observaremos que lo
que funciona perfectamente en la primera no funciona en la segunda. (Y esto no es teoría. Es
simplemente experiencia del autor). ¡Y Access y SQLServer son del mismo fabricante!. La
razón está en que los drivers de una base y otra no trabajan exactamente igual. Tampoco son
iguales las protecciones y los permisos de acceso. Consejo de viejo profesor: Si va a trabajar
con una determinada base de datos a través de RDO comience el proyecto usando esa base de
datos. Y puestos a dar consejos, si piensa usar SQLServer u Oracle y si la aplicación va a
escribir datos en la base no use RDO. Si solamente los va a leer no tendrá problemas. Y si
tiene problemas nadie se los va a resolver, argumentando que deje RDO y use ADO. De hecho
RDO ya se ha quedado obsoleto al nacer ADO. Pero eso será objeto de otro capítulo de esta
Guía del Estudiante y hoy nos toca aprender RDO. Comencemos.

RDO y DAO. Comparación de sus objetos. El control RemoteData

Al igual que DAO, RDO tiene objetos de acceso a datos, que deberemos declarar y crear.
Mediante estos objetos podemos leer y escribir datos en una BD mediante código. También, al
igual que en DAO existía el Control Data, con el que podíamos acceder a la base de datos sin
escribir ni una línea de código, en RDO existe un control similar: el Control RemoteData. El
funcionamiento es similar, pero las propiedades son distintas y tienen distintos nombres.
Mediante el control RemoteData podemos enlazar una base de datos a los típicos controles
enlazados a datos (Label, TextBox, DBGrid), pero en este caso se enlazan a través de una
conexión ODBC, por lo que es fácil pensar que las propiedades de este control y los valores

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 13


que deben tomar son distintas a los del control Data. Como es mucho más sencillo (sencillo no
quiere decir mejor) usar el control RemoteData que trabajarse con código los objetos de acceso
a datos, vamos a comenzar estudiando este control.

Pero antes vamos adelantar la equivalencia entre los objetos DAO y los objetos RDO. La lista
siguiente está copiada literalmente de la información de Microsoft MSDN Library Visual Studio,
información que merece la pena instalarla en su ordenador pese a lo que ocupa.

Objetos de datos remotos y los objetos de DAO/Jet equivalentes


Objeto de RDO Objeto de DAO/Jet equivalente
rdoEngine DBEngine
rdoError Error
rdoEnvironment Workspace
rdoConnection Database
rdoTable TableDef
No está implementado Index
rdoResultset Recordset
No implementado Tipo Table
Tipo Keyset Tipo Dynaset
Tipo static Tipo Snapshot
Tipo dynamic (ninguno)
Tipo forward-only Tipo forward-only
No implementado (*) User
RdoColumn Field
rdoQuery QueryDef
rdoParameter Parameter
No implementado (**) Relation
No implementado (*) Group
Control RemoteData Control Data

(*) En RDO, los usuarios y grupos de usuarios son precisamente los que lleve implícitos la
conexión ODBC.
(**) Al no trabajar directamente sobre la base de datos, no se pueden crear relaciones en ella.

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 14


El control RemoteData
Este control nos permite crear una aplicación de acceso a datos completa sin utilizar código.
Eso sí, será necesario tener una conexión ODBC hecha, ya que el control RemoteData no abre
un fichero de BD sino una conexión ya establecida.
No está normalmente en la caja de herramientas, por lo que habrá que añadirlo en Proyecto |
Componentes introduciendo el Microsoft Remote Data Control 6.0 El control Remote Data
tiene un aspecto similar al control Data, tanto en la caja de herramientas como en el formulario:

El control RemoteData toma por defecto el nombre MSRDCx.

Algunas Propiedades del Control RemoteData

DatasourceName

Devuelve o establece el nombre del origen de datos (DSN). El DSN No es más que el nombre
de la conexión ODBC.

Esta propiedad se puede dejar en blanco si la propiedad Connect del control identifica un
nombre de origen de datos (DSN) registrado en el Registro de Windows.

Sintaxis NombredelControlRDO.DatasourceName = MiConexión

Puede cambiarse en tiempo de ejecución. En este caso, inmediatamente debe utilizar el método
Refresh para abrir la nueva conexión con la base de datos.

Puede leer el valor de esta propiedad. Le devolverá precisamente el DNS que está utilizando.
Esta propiedad sólo le devolverá un valor si ha introducido previamente algún valor en la
propiedad DatasourceName. No le devolverá valor alguno si ha introducido la conexión a
través de la propiedad Connect.

Propiedad Connect
Esta propiedad cumple la misma función que la anterior, pero por otro camino. Mediante la
propiedad Connect le introducimos al control RemoteData la información necesaria para abrir la
conexión, incluyendo en esta información, no solamente el nombre de la conexión, como
hacíamos con la propiedad DatasourceName, sino ampliarla con otros datos de la conexión, tal
como el nombre del usuario, su contraseña, nombre del controlador ODBC a usar, el nombre de
la base de datos, el servidor donde se ubica esta base de datos, nombre de la estación de
trabajo desde la que vamos a trabajar e incluso el nombre de la aplicación en la que vamos a
usar los datos de esa base. Esta propiedad es mucho más completa que la anterior, pero un
poco más complicada de usar.

Para introducir los datos de la propiedad Connect deberá usar una palabra para definir el dato,
seguido del signo = y del dato a introducir. Como final del dato debe introducir necesariamente
el signo punto y coma ;

DSN Origen de datos ODBC registrado. DSN=MiConexiónODBC;


UID Nombre de un usuario reconocido UID=Luis;
PWD Contraseña asociada al usuario PWD=MiContraseña;
DRIVER Descripción del controlador DRIVER=SQL Server;
DATABASE Base de datos predeterminada
para usarla una vez conectado DATABASE=MiBase;
SERVER Nombre del servidor donde se
aloja la base de datos SERVER=MiServidor;

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 15


WSID Nombre de la estación de trabajo
(Nombre del PC que se va a
comunicar con el servidor WSID=NombredemiPC;
APP Nombre de la Aplicación que va a
Usar la Base de Datos APP=MiAplicación

NOTA - Si conoce SQLServer, DATABASE es el nombre de la base de datos que quiere utilizar
una vez realizada la conexión. Para los que no conocen SQLServer, dentro de un fichero de
esta base de datos pueden existir varias bases de datos. Y cada una de ellas puede tener
varias tablas. Es decir, la configuración de esta BD no es tan simple como la de Access. Cada
una de estas bases de datos tiene un propietario y varios usuarios. Cada usuario tiene
habilitadas unas funciones (p.e. un usuario puede leer y escribir y otro solamente leer) Este
parámetro le indica cual de esas bases de datos que contiene el fichero de SQLServer (para
hablar con mas propiedad, el sistema de ficheros de SQLServer)

SQLServer mostrando su carpeta de Bases de Datos (BDGepa, master, model, …)

Observe que tras cada parámetro existe un separador ; No es necesario introducir todos los
datos. Dependerá del driver, de cómo haya creado la base de datos, los atributos que le dio a
cada uno de los usuarios. Y como no, dependerá del tipo de base de datos que esté usando
(SQLServer, Oracle, etc.). Recuerde lo mencionado más atrás. No se fíe nunca de que su
aplicación trabaja perfectamente sobre una base de datos. Lo más probable es que si cambia
de BD ya no le trabajará tan perfectamente.

Veamos un ejemplo de cómo introducir esta propiedad:

Dim MiVariable As String


MiVariable = "DSN=MiConexionODBC;UID=Luis;PWD=MiContraseña;DATABASE=BaseGE;"
RemoteData1.Connect = MiVariable

El hecho de que podamos abrir una base de datos mediante DatasourceName o Connect
tiene su explicación. Si tenemos creada una conexión ODBC con todos los datos necesarios
para que pueda abrir una base de datos, es mucho más simple usar la propiedad

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 16


DatasourceName y el Control RemoteData le abrirá perfectamente la BD. Pero cuando usamos
una BD a través de Red de Area Local, lo normal es que esa base esté compartida por varios
usuarios, que cada uno tendrá un nombre y un Password, que puede estar habilitado para
trabajar desde un puesto o desde varios puestos, e incluso puede estar habilitado para trabajar
sobre una BD utilizando una determinada aplicación, y no estarlo para utilizar esa misma BD
con una aplicación distinta. Por eso este control nos brinda las dos posibilidades, una sencilla,
DatasourceName, para trabajar con los datos ya introducidos en la conexión ODBC, y la otra,
para variar los datos de esa conexión ODBC ya existente y lograr con ello todas las ventajas
que nos ofrece ODBC respecto a restricciones de usuarios, contraseñas, etc. (la conexión
ODBC en este caso es muy normal que tenga solamente el nombre, y que no apunte a ninguna
base de datos concreta). Puede incluso utilizar ambas propiedades. Es muy típico por ejemplo,
que la conexión apunte a una determinada base de datos, (el nombre de la conexión se lo
pasamos en la propiedad DatasourceName) y que en la propiedad Connect le pasamos el
nombre del usuario y la contraseña.

Puede utilizar el control, RemoteData incluso sin tener una conexión preestablecida. Pero
deberá establecer mediante el programa, utilizando los métodos OpenConnection o
EstablishConnection. Se sale del contenido deseado para este curso comentar estos
métodos, pero el alumno aventajado puede intentar obtener información en la escasa
bibliografía existente. No le recomiendo que se complique la vida rizando el rizo, pudiendo
establecer previamente la conexión ODBC.

Propiedad SQL
Mediante las dos propiedades estudiadas, DatasourceName y Connect hacemos que el
control RemoteData sepa la conexión sobre la que va a trabajar - y por lo tanto la base de datos
que utilizará. Ahora nos falta indicarle los datos que deseamos leer o escribir. Nos falta lo que
sería en DAO, darle los datos para crear el Recordset (Por ejemplo el nombre de una tabla o
una sentencia SQL, tal como hacíamos en la propiedad RecordSource del control Data). Para
el control RemoteData esta información se le introduce en la propiedad SQL

La propiedad SQL establece o devuelve una instrucción SQL válida para crear un conjunto de
registros a partir del origen de datos establecido en las propiedades DatasourceName o
Connect. Esta instrucción SQL debe comenzar necesariamente por SELECT, En tiempo de
ejecución, podemos asignar a esta propiedad el nombre de una Consulta ya almacenada en la
BD, pero en este caso, debemos anteponer la palabra EXECUTE. También podemos introducir
en esta propiedad un rdoQuery, un rdoResultset o un rdoTable. Eso lo veremos más
adelante.

Para establecer esta propiedad en tiempo de diseño, basta con escribir la instrucción SQL en la
ventana de propiedades. Una instrucción típica sería

SELECT * From Alumnos


SELECT * From Alumnos Where Apellido1= 'Suárez'

En tiempo de ejecución podemos introducir una de estas instrucciones en la propiedad SQL

MSRDC1.SQL = "SELECT * From Alumnos Where Apellido1= 'Suárez'"

Si la BD tiene una consulta (la típica consulta de Access) llamada C_Suarez, donde hemos
seleccionado todos los registros cuyo campo Apellido1 sea Suárez, podemos poner:

MSRDC1.SQL = EXECUTE C_Suarez

(No intente hacer esto mismo con el nombre de una tabla. Solamente sirve para consultas)

Con los registros seleccionados por la propiedad SQL, formamos lo que en DAO era un
recordset, pero en este caso adopta otro nombre: rdoResultset. En RDO se ha buscado otra

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 17


terminología, posiblemente para diferenciarlo claramente de DAO. Por ejemplo, en vez de
registros es habitual hablar de Filas, y en vez de campos, hablamos de Columnas.

Si pudiésemos crear un rdoResultset mediante algún procedimiento, (y seguro que podremos


hacerlo), podemos introducir directamente ese rdoResultset como rdoResultset del control
RemoteData, al igual que lo hacíamos con el Recordset del Control Data en DAO:

Set MSRDC1.Resultset = rdoResultsetYaCreado

Propiedad Connection
Veamos previamente que es un objeto rdoConnection. Un Objeto rdoConnection es un objeto
de acceso a datos remotos. Es el equivalente al objeto Database en DAO (Vea cuadro página
2) El control RemoteData tiene un objeto rdoConnection subyacente y podemos "verlo"
mediante esta propiedad. El poner verlo entre comillas no significa otra cosa que, al igual que
ocurría con el objeto Database, el objeto rdoConnection es un objeto de acceso a datos del que
podemos ver sus propiedades y ejecutar sus métodos. Por ejemplo, si queremos ver la cadena
de conexión completa podemos analizar la propiedad Connect del Objeto Connection:

Label1 = MSRDC1.Connection.Connect

Si deseamos saber si el control RemoteData sigue conectado para realizar una determinada
operación:
If MSRDC1.Connection.StillConnecting Then ….

Podemos ejecutar uno de sus métodos. Por ejemplo, cerrar la conexión

MSRDC1.Connection.Close

Propiedades EOFAction y BOFAction


Establecen el comportamiento del RemoteData cuando llega a la fila anterior a la primera o a la
fila posterior a la última. (Y no es un juego de palabras) Puede establecerse en tiempo de
diseño, mediante la caja de propiedades, o en tiempo de ejecución mediante la siguiente
sintaxis:

MSRDC1.BOFAction = valor
MSRDC1.EOFAction = valor
Los valores (o constantes) que puede tomar son los siguientes:

Para la propiedad BOFAction

Valor Constante Efecto

0 rdMoveFirst Se mueve a la primera fila


1 rdBOF Se mantiene en la fila anterior a la primera. Se genera el evento
Validate y a continuación el evento Reposition, y se desactiva el botón
de desplazar hacia abajo

Para la propiedad EOFAction

Valor Constante Efecto


0 rdMoveLast Se mueve a la última fila
1 rdEOF Se queda en la fila posterior a la última. Se genera el evento Validate
y a continuación el evento Reposition. Se desactiva el botón de
desplazar hacia arriba.
2 rdAddNew Crea una nueva fila.

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 18


La propiedad EOFAction sólo tiene efecto cuando se manipula el cambio de filas mediante el
ratón, sobre los botones del control RemoteData. No tiene efecto si se llega a la fila posterior a
la última mediante código. (Por ejemplo, mediante la instrucción MSRDC1.resultset.MoveNext)

NO es recomendable establecer la propiedad BOFAction a 1 (rdBOF) ni la propiedad


EOFAction a 1 (rdEOF), ya que puede entrar en una situación de la que es imposible salir. Si
ve aparecer un aviso de error parecido a Estado del conjunto de datos no válido para Update le
está indicando que se ha metido en un proceso del que no puede salir, debido a que se
encuentra en el EOF ó BOF intentando introducir un nuevo dato, y no puede.

Propiedad CursorDriver
Devuelve o establece un valor que especifica el tipo de cursor que se va a crear. Veamos
primero qué es un cursor. Según la definición de Microsoft:

Conjunto lógico de filas administrado por el origen de datos o por el administrador de


controladores ODBC. Los cursores reciben dicho nombre porque indican la posición actual
dentro del conjunto de resultados, igual que el cursor de la pantalla indica la posición actual.
(#G!*¡&@%)

Vamos a no complicarnos la vida para intentar comprenderlo. El mecanismo de ODBC espera


una base de datos albergada en un servidor, a la que le vamos a manipular sus registros desde
un puesto conectado al servidor donde se encuentra la base de datos a través de una red de
área local. Cuando creamos un recordset, el conjunto de registros que forma ese recordset
deberá estar en la memoria RAM de algún equipo. ¿Del servidor? ¿Del cliente? En cualquiera
de ellos que esté deberá estar en la memoria RAM, ocupando cierto espacio. A esa memoria
ocupada por el recordset, y a la forma en la que están guardados los datos dentro de ella es a
lo que llamamos Cursor. Este concepto de cursores es nuevo (No existía en DAO) debido a
que RDO se utiliza fundamentalmente en sistemas basados en un servidor, donde se alberga la
base de datos, y una serie de puestos de operación, unidos al servidor a través de una red. El
tráfico de datos a través de la red es algo que se debe optimizar. Y en algunos casos puede ser
beneficioso llevarse todas las filas de un rdoResultset al puesto, operar con ellas e
introducirlas de nuevo, si es necesario, en la base de datos, una vez procesadas, o puede ser
beneficioso mantener ese conjunto de filas en la memoria RAM del servidor para tener
disponibles allí los datos y acceder a ellos de forma rápida a través de la red. En un caso
lograremos o rapidez y en otro poco tráfico, pero en ambos casos gastaremos recursos.
Podemos no crear un cursor, no usaremos memoria pero, o empleamos mas tiempo, o
introducimos más tráfico en la red.

El crear un cursor de lado cliente o de lado servidor puede hacer que su código funciones o no
funcione. Los cursores lado cliente suelen ser de lectura / escritura, que permiten avanzar hacia
a delante y hacia atrás. Los cursores lado servidor suelen ser solamente de lectura y de avance
solamente hacia delante. Hemos empleado una palabra no muy exacta: suelen ser. Y es que
eso dependerá de la base de datos (Oracle no se comporta como SQLServer, y ninguna de
ellas se comporta como Access) y depende también del controlador ODBC que utilice (Hay
controladores de varias marcas para la misma base de datos) Es muy frecuente realizar un
código que funciona perfectamente con un controlador ODBC, y cuando se cambia de
controlador – o de versión – ya no funciona. Le recomiendo mucho cuidado.

El control RemoteData permite elegir el crear un cursor en el servidor, en el puesto, o crearlo


solamente si es necesario. Para ello usamos la propiedad CursorDriver. Puede tomar los
siguientes valores:

Constante Valor Descripción


El controlador ODBC elegirá el tipo de cursores adecuado. Se
rdUseIfNeeded 0
usarán cursores del servidor si hay alguno disponible.
rdUseOdbc 1 RemoteData usará la biblioteca de cursores de ODBC .
rdUseServer 2 Se usarán cursores del lado del servidor.
rdUseClientBatch 3 RDO usará la biblioteca de cursores por lotes de tipo optimista.

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 19


Le recomiendo que repase el tema de cursores de la base de datos concreta que esté usando,
y espero que la bibliografía que le brinda el fabricante sea suficiente. No suelen ser muy
explícitos con los manuales aportados, o al menos tienen la habilidad de explicarlo de una
forma tan sutil que es a veces inescrutable. Casi siempre esas dudas se resuelven en el curso
que cada marca tienen para su base de datos, que es estrictamente de pago.

Métodos del control RemoteData

Método UpdateRow
Es equivalente al método UpdateRecord del Control Data. Guarda los valores actuales de los
controles enlazados en la base de datos. El método UpdateRow tiene el mismo efecto que
ejecutar el método Edit, modificar una columna y después ejecutar el método Update, excepto
que no ocurre ningún evento.

Nota Cuando usa una biblioteca de cursores ClientBatch, todas las actualizaciones a las tablas
base se retrasan hasta que use el método BatchUpdate. En este caso, el método UpdateRow
actualiza el rdoResultset local, pero no actualiza las tablas base. Estos cambios pueden
perderse si la aplicación termina antes de que se haya completado el método BatchUpdate.

Método BatchUpdate (Método del rdoResultset)


Este método no es del control RemoteData, sino de su rdoResultset asociado.

De igual forma que un control data tenía asociado un recordset, un RemoteData tiene asociado
un Resultset. El Resultset es el objeto rdoResultset del control RemoteData (Colección de
registros, o si lo prefiere, de filas ya que estamos en RDO), y que como cualquier objeto de
acceso a datos, tiene sus métodos, y este es uno.

Realiza una actualización optimista por lotes.

Sintaxis MSRDC1.Resultset.BatchUpdate (filaunica, forzar)

Donde MSRDC1 es el nombre del control RemoteData


Filaunica (Booleano) indica si es True, que solamente actualizará la fila actual, si es False,
actualiza todo el lote. El lote es un conjunto de filas. Pueden ser las filas del cursor.
Forzar (Booleano)indica si está a True que sobreescribirá la fila actual, independientemente de
si causa o no colisiones. Si está a False, no sobreescribirá si va a ocurrir una colisión.

Este método es un método del rdoResultset. Si tenemos un rdoResultset creado con código
(Ahora veremos como se hace) la sintaxis sería

MirdoResultset. BatchUpdate (filaunica, forzar)

Con esta introducción ya podemos pensar que el alumno tiene cierta idea respecto a lo que es
el control RemoteData. Vamos a comenzar a explicar lo que son los objetos de acceso remoto
a datos (Objetos RDO) y podremos seguir viendo cosas acerca del control RemoteData como
aplicación de estos nuevos objetos.

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 20


Objetos de datos remotos (Objetos RDO)

Como ya conocemos los objetos de acceso a datos DAO, veremos los objetos RDO
basándonos un poco en este conocimiento.

Los objetos de datos remotos nos permiten manipular componentes de un sistema de base de
datos ODBC remoto. Lo de remoto no implica que la base de datos deba estar en un ordenador
distinto al que tiene la aplicación. (Aunque esta sea la disposición más usual en aplicaciones
que usan RDO). El significado de RDO es que se accede a la base de datos a través de una
conexión ODBC.

RDO solamente funciona en plataformas de 32 bits. (Windows 95/98/2000 o Windows NT).


Para usar objetos de datos remotos, debe establecer una referencia a Microsoft Remote Data
Object 2.0 en Proyecto | Referencias.

Al igual que en DAO, los objetos RDO tienen una estructura jerárquica que se puede ver en la
siguiente figura:

Estructura jerárquica de los objetos RDO

Los objetos RDO siguen la misma regla para su creación que los objetos DAO: el objeto
jerárquicamente superior crea al objeto inferior.

El Objeto rdoEngine
El objeto rdoEngine representa el origen de datos remoto. Es el equivalente al dbEngine de
DAO, es decir, el motor de bases de datos. Es el objeto de nivel jerárquico superior, por lo tanto
no se crea por otro objeto, sino que está creado simplemente al introducir la referencia.

La característica del rdoEngine es que trabaja siempre a través del Administrador de


controladores. El objeto rdoEngine contiene al objeto rdoEnvironments (Colección de objetos
rdoEnvironment) y el rdoErrors.

Los objetos rdoEnvironment de nueva creación se inicializan de acuerdo a los valores


predeterminados establecidos en el objeto rdoEngine. Se crea de forma automática el objeto
rdoEnvironments(0), al igual que lo hacía el dbEngine con el Workspaces(0) en DAO.

El objeto rdoErrors contiene todos los mensajes de error enviados desde el origen de datos
remoto. Cada vez que se recibe uno de estos mensajes, se produce el evento InfoMessage del
rdoEngine

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 21


Propiedades del objeto rdoEngine

rdoDefaultLoginTimeout Determina el valor predeterminado la propiedad LoginTimeout


de los objetos rdoEnvironment que se creen. Esta propiedad se utiliza en la administración del
tiempo disponible para la conexión. Si la conexión no se ha realizado en el número de segundos
indicado, dará error.
Sintaxis rdoEngine.rdoDefaultLoginTimeout = NumeroDeSegundos

Si el valor NumeroDeSegundos es cero, esperará indefinidamente a que se realice la conexión.

rdoDefaultCursorDriver Determina el valor predeterminado de la propiedad


CursorDriver de los objetos rdoEnvironment. Esta propiedad determina si el Administrador de
controladores ODBC crea cursores por lotes del lado del cliente, locales, del servidor o si no
crea cursores.

Sintaxis rdoEngine.rdoDefaultCursorDriver = valor

Donde Valor es un valor o contante según puede verse en la siguiente tabla


RdUseIfNeeded (Predeterminado) elige el estilo de cursores más apropiado para el
Controlador
RdUseODBC Utiliza la biblioteca de cursores ODBC.
RdUseServer Utiliza cursores del servidor
RdUseClientBatch Usa la biblioteca de cursores optimista por lotes
RdUseNone No crea un cursor desplazable. Básicamente es un conjunto de
resultados de sólo lectura de tipo forward-only

rdoDefaultUser y rdoDefaultPassword Determinan los valores predeterminados de


las propiedades UserName y Password de los objetos rdoEnvironment cuando se abren
conexiones sin suministrar valores para estos parámetros.

rdoVersion Examina la versión de RDO en uso.

rdoLocaleID Devuelve o establece un valor que indica la configuración regional de la


biblioteca RDO, para mostrar los mensajes de error.
Sintaxis rdoEngine.rdoLocaleID = valor

Por defecto, esta propiedad toma el valor 0, que pone la configuración establecida en Windows.
Si el archivo DLL del idioma especificado no está presente en el equipo del usuario, RDO se
establece como rdLocaleEnglish, lo cual no requiere un archivo DLL independiente. Cuando
esto ocurre, se coloca un mensaje informativo en la colección rdoErrors para indicar que RDO
no pudo cargar el archivo DLL de recursos para la configuración regional especificada.
Cuando distribuya la aplicación, asegúrese de incluir el archivo DLL del lenguaje apropiado.

Métodos del rdoEngine


rdoCreateEnvironment Este método es equivalente al CreateWorkspace de DAO. Crea
un nuevo objeto rdoEnvironment. (Es decir, una sesión de trabajo)
Sintaxis Set MiSesion = rdoEngine.rdoCreateEnvironment(Nombre, Usuario, Contraseña)

Donde:
Nombre es la propiedad Name del nuevo objeto rdoEnvironment. (En el código, para nombrar a
este rdoEnvironment debemos hacerlo con MiSesion). Debe suministrar un nombre, ya que si
no lo hace, este rdoEnvironment creado no se suma a la colección rdoEnvironments.
Usuario es el nombre del usuario.
Contraseña es la contraseña usada en esa sesión. Puede tener hasta 14 caracteres.

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 22


Cuando se inicializa el rdoEngine se crea automáticamente una sesión de trabajo
predeterminada, el rdoEnvironments(0), con el nombre de usuario que tenga el rdoEngine en
su propiedad rdoDefaultUser y con contraseña igual a la propiedad rdoDefaultPassword. En
una aplicación multiusuario es necesario crear un rdoEnvironment para cada uno de ellos,
siempre que empleemos transacciones. En este método es necesario suministrar todos los
parámetros (Nombre, Usuario y Contraseña)
rdoRegisterDataSource Introduce la información de conexión en el Registro de Windows
para un origen de datos ODBC (Crea una conexión ODBC igual que lo haríamos en Windows)
Sintaxis rdoEngine.rdoRegisterDataSource DSN, controlador, silencio, atributos

DSN es el nombre que queremos dar a la conexión ODBC


Controlador es el nombre del controlador ODBC. Debe ser uno de los instalados y hay que
poner el nombre exacto por el que se le conoce en Windows, NO el nombre de la DLL. Por
ejemplo, debe poner Microsoft Access Driver y no odbcjt32.dll
Silencio es un valor True / False y se refiere a si queremos que presente el cuadro de creación
de un enlace ODBC (El mismo que aparece en Windows) Si ponemos False en esta propiedad,
le introducimos los datos de la conexión a través de ese cuadro. Si le ponemos True, no
mostrará el cuadro, y por lo tanto deberemos pasarle todos los parámetros correctamente. Si la
información suministrada no es completa, mostrará el cuadro citado.
Atributos. Una expresión de cadena que es una lista de palabras clave que se van a agregar al
archivo ODBC.INI. Las palabras claves están en una cadena delimitadas por retornos de carro.
No es trivial esta cadena de caracteres y es propia de cada controlador. Por lo tanto, le
recomiendo que si no conoce muy bien la cadena a introducir, ponga el parámetro Silencio a
False y se olvide de este parámetro de atributos. Eso sí, deberá ser el usuario quien introduzca
los datos a través del cuadro de creación del enlace ODBC.

Hasta aquí las propiedades y métodos del rdoEngine. Vamos a bajar un nivel jerárquico y ver el
siguiente objeto RDO

El Objeto rdoEnvironment
Un objeto rdoEnvironment es una sesión de trabajo en RDO. Equivale al Workspace de DAO.
En un rdoEnvironment podemos tener varios objetos Connection (varias conexiones) de la
misma forma que en un Workspace podíamos tener varias objetos Database.

La colección de todos los objetos rdoEnvironment es el objeto rdoEnvironments. Visual Basic


crea automáticamente un rdoEnvironment, de la misma forma que creaba un Workspace. El
objeto rdoEnvironment creado es el rdoEnvironments(0) y el nombre de usuario será el que
tenga el rdoEngine en su propiedad rdoDefaultUser y la contraseña igual a la propiedad
rdoDefaultPassword

NOTA. Visual Basic crea automáticamente un Workspace o un rdoEnvironment si el proyecto


contiene la referencia al motor de bases de datos correspondiente. Visual Basic no creará
ninguno de ellos si no tiene la referencia a ningún motor de bases de datos.

Los objetos rdoEnvironment se anexan automáticamente a la colección rdoEnvironments a


menos que no proporcione un nombre para el nuevo objeto cuando utilice el método
rdoCreateEnvironment.

Propiedades del Objeto rdoEnvironment


Propiedad CursorDriver Ya hemos visto esta propiedad para el control RemoteData. La
aplicación al objeto rdoEnvironment es similar, por lo que solamente exponemos su sintaxis:

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 23


MiSesión.CursorDriver = Valor donde Valor toma uno de estos valores o constantes:

0 rdUseIfNeeded El controlador ODBC elegirá el tipo de cursores adecuado. Se


usarán cursores del servidor si hay alguno disponible.
1 rdUseOdbc Usará la biblioteca de cursores de ODBC .
2 rdUseServer Se usarán cursores del lado del servidor.
3 rdUseClientBatch RDO usará la biblioteca de cursores por lotes de tipo optimista.

Propiedad hEnv
Esta propiedad es el Handle de la conexión ODBC. Es similar a la propiedad hDC (para
controles) o hWnd (para formularios) que ya hemos visto en capítulos anteriores. Esta
propiedad es sólo de lectura y devuelve un Long. Este valor lo usan las APIs de Windows para
trabajar. Alguna instrucción nos pedirá el hEnv como parámetro.

Propiedad LoginTimeout
Devuelve o establece el número de segundos que el Administrador de controladores ODBC
espera antes de que se produzca un error de espera al abrir una conexión.

Sintaxis NombreDelObjetordoEnvironment.LoginTimeout = NumeroDeSegundos

El valor predeterminado es el de la propiedad rdoDefaultLoginTimeout del objeto rdoEngine,


y en su defecto, de 15 segundos. Si este valor es igual a 0 se espera indefinidamente y no se
producirá ningún error.

Si establece un valor para esta misma propiedad en uno de sus objetos rdoConnection, este
valor es prioritario al establecido en el objeto rdoEnvironment.

Métodos del objeto rdoEnvironment

Método OpenConnection
Abre una conexión con un origen de datos ODBC. En otras palabras, crea un objeto
rdoConnection, objeto que deberá declarar antes de abrirlo:

Dim MiConexion as rdoConnection


Set MiConexión = MiSesion.OpenConnection(Nombre, LineaComandos, SóloLectura,
Conectar, Opciones)

Nombre puede ser una conexión ya creada, en cuyo caso se abrirá esa conexión. Si este
parámetro es una cadena vacía, deberá obtener los datos de la conexión, o bien del argumento
Conectar, o mediante el cuadro de dialogo de abrir la conexión.

LineaComandos. Determina si muestra o no muestra el cuadro de diálogo de abrir la conexión


ODBC. Puede tomar estos valores
rdDriverPrompt (0) Muestra el cuadro de diálogo
rdDriverNoPrompt (1) No muestra nunca el Cuadro de diálogo
rdDriverComplete (2) Muestra el cuadro de diálogo solamente si la información
facilitada no es suficiente para abrir la conexión.
RdDriverComplete (3) Igual que rdDriverComplete pero deshabilita las opciones
Required que ya estén bien pasadas en la información facilitada.

SóloLectura Determina si la conexión se abre como sólo lectura o para lectura / escritura. Si no
se especifica nada, se abre para lectura / escritura.

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 24


Conectar Este es el argumento que lleva los datos completos de la conexión. Es similar a la
propiedad Connect del control RemoteData, cuyo contenido repetimos aquí por comodidad.

Para introducir los datos de la propiedad Connect deberá usar una palabra para definir el dato,
seguido del signo = y del dato a introducir. Como final del dato debe introducir necesariamente
el signo punto y coma ;

DSN Origen de datos ODBC registrado. DSN=MiConexiónODBC;


UID Nombre de un usuario reconocido UID=Luis;
PWD Contraseña asociada al usuario PWD=MiContraseña;
DRIVER Descripción del controlador DRIVER=SQL Server;
DATABASE Base de datos predeterminada
para usarla una vez conectado DATABASE=MiBase;
SERVER Nombre del servidor donde se
aloja la base de datos SERVER=MiServidor;
WSID Nombre de la estación de trabajo
(Nombre del PC que se va a
comunicar con el servidor WSID=NombredemiPC;
APP Nombre de la Aplicación que va a
Usar la Base de Datos APP=MiAplicación

Estos datos complementan la información de la conexión. Si ya habíamos establecido la


conexión mediante el argumento Nombre, y en esa conexión ya estaban perfectamente
definidos todos los parámetros de esa conexión, de este argumento Conectar solamente
tomará el nombre de usuario y la contraseña.

Puede comprobar si se ha completado la conexión examinando la propiedad StillConnecting


del objeto rdoConnection recién creado, que debe devolver False cuando se ha completado la
operación de conexión.

If MiConexion.StillConnecting = false then ….

BeginTrans, CommitTrans, RollbackTrans (Transacciones)


Son los métodos para realizar transacciones.
· BeginTrans comienza una nueva transacción.
· CommitTrans finaliza la transacción actual y guarda los cambios.
· RollbackTrans finaliza la transacción actual y restaura las bases de datos del objeto
rdoEnvironment al estado en que estaban cuando comenzó la transacción actual.

El funcionamiento en RDO es distinto al de DAO. Además, es distinto para cada base de datos.
La forma de trabajar de SQLServer es distinta de cómo lo hace Oracle. Y muy distinta de cómo
lo hace Access. Le recomiendo que estudie las transacciones en el manual de su gestor de
base de datos.
Hay algunas bases de datos que no aceptan transacciones. Puede comprobarlo analizando la
propiedad Transactions del objeto Connection.

Método Close
Cierra un el rdoEnvironment y todas las conexiones que tenía abiertas. Las modificaciones
pendientes de los objetos RDO inferiores que estuviesen abiertos se deshacen.

Sintaxis MiSesion.Close

No se puede cerrar el rdoEnvironments(0) Si utiliza Close con el objeto ya cerrado, se


producirá un error interceptable..

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 25


El objeto rdoConnection
Un objeto rdoConnection representa una conexión abierta con un origen de datos a través de
ODBC. Es el equivalente al Objeto DataBase de DAO

Un objeto rdoConnection (es decir, una conexión a una base de datos a trvés de ODBC) se
crea o con un control RemoteData o mediante el método OpenConnection del objeto
rdoEnvironment.

Puede también crear un nuevo objeto rdoConnection que no esté vinculado de forma
inmediata con una conexión física específica a un origen de datos. Por ejemplo, el siguiente
código crea un objeto rdoConnection independiente:

Dim OtraConexion as New rdoConnection.

Posteriormente puede introducir las características que desee y establecer la conexión real con
la base de datos. No es normal hacer esto, por lo que le remito en caso necesario, a la ayuda
de VB de este objeto.

Propiedades del Objeto rdoConnection


Un objeto rdoConnection tiene Propiedades. Muchas de ellas ya se han visto, bien al estudiar el
control RemoteData o los objetos RDO ya estudiados. Las propiedades que se han visto se
describirán sólo de forma somera.

Propiedad Connect Devuelve o establece un valor que proporciona información sobre el


origen de un objeto rdoConnection abierto. La propiedad Connect contiene la cadena de
conexión ODBC. Esta propiedad puede leerse siempre, pero no puede modificarse una vez
establecida la conexión.

Sintaxis objeto.Connect = CadenaDeConexión

Las partes de CadenaDeConexión son: (Puede no usar alguna de ellas)

DSN Nombre del origen de datos (Nombre de la conexión ODBC)


UID Nombre del usuario (Puede no tener nombre de Usuario)
PWD Password. (Puede no tener Password)
DRIVER Nombre del driver ODBC empleado
DATABASE Nombre de la base de datos que se va a emplear
SERVER Nombre del servidor remoto
WSIS Nombre de la estación de trabajo dentro de la red
APP Nombre de la Aplicación

(El separador es el carácter punto y coma (;)

No es necesario aportar estos datos para crear la conexión, ya que son los que se han
introducido en Windows al crear la conexión ODBC. Estos datos solamente son necesarios si la
conexión ODBC se creó sin aportarle datos acerca de la base de datos.
Propiedad hDbc
Devuelve el controlador de conexión ODBC.

Sintaxis MiConexion.hDbc

La propiedad hDbc devuelve un valor de tipo Long. Este valor lo utilizan las APIs de Windows.
Y es similar a hDc o hWnd

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 26


Propiedad LastQueryResults
Devuelve un objeto rdoResultset, precisamente el que se ha generado la última consulta, si la
ha habido. Esta propiedad podemos utilizarla para crear un nuevo Resultset, clónico del ultimo
que se ha generado.

Sintaxis
Dim MiRs as rdoResultset
Set MiRs = MiConexion.LastQueryResults

Si no se había creado todavía ningún Resultset, devuelve Nothing.

Propiedad QueryTimeout
Devuelve o establece un valor que especifica el número de segundos que espera el
Administrador de controladores ODBC antes de que se produzca un error de tiempo de espera
al ejecutarse una consulta. El valor predeterminado es de 30 segundos.

Propiedad StillConnecting
Devuelve un valor que indica si la conexión se está estableciendo todavía.

Sintaxis MiConexion.StillConnecting
Esta propiedad devuelve True si la conexión no ha terminado de establecerse, y False si ya
está establecida. Es fundamental saber que la conexión ya está establecida antes de realizar
ninguna operación con ella, por ejemplo, crear un Resultset

Propiedad StillExecuting
Devuelve un valor que indica si una consulta está aún ejecutándose. Esta propiedad se usa
cuando creamos un rdoResultset o un rdoQuery, para conocer si ya se ha finalizado el proceso
de selección de filas que esa operación implica. Esta propiedad puede aplicarse al
rdoConnection, rdoQuery y rdoResultset. Devuelve True cuando la consulta está ejecutándose
todavía, False si ya se ha finalizado.

Sintaxis objeto.StillExecuting

Propiedad Transactions
Devuelve un valor que indica si se pueden realizar transacciones con un objeto rdoConnection ó
rdoResultset. Esta propiedad le permite asegurarse de esta circunstancia antes de ejecutar la
instrucción BeginTrans.
La propiedad Transactions llama a la función SQLGetInfo de ODBC para determinar si el
controlador ODBC es capaz de permitir transacciones, no si el conjunto de resultados actual es
actualizable.

Propiedad AsyncCheckInterval
Devuelve o establece un valor que especifica el número de milisegundos que espera RDO entre
dos comprobaciones para ver si se ha completado una consulta asíncrona.

Sintaxis MiConexion.AsyncCheckInterval = valor

El valor por defecto es de 1 segundo (1000 mseg)

Comentarios Al usar la opción rdAsyncEnable para ejecutar una consulta de forma


asíncrona, RDO comprueba periódicamente el origen de datos para determinar si la consulta se
ha completado. Puede modificar la duración del intervalo entre comprobaciones mediante la

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 27


propiedad AsyncCheckInterval. RDO también comprueba el estado de las consultas
asíncronas cuando se examina la propiedad StillExecuting.

Propiedad UpdateOperation
Esta propiedad afecta a la forma en la que se realiza la modificación de una fila en una
actualización optimista por lotes. Si a esta propiedad se le pone el valor 0 (Predeterminado) la
modificación de la fila se realiza mediante una instrucción Update. Si el valor es 1, la operación
de modificación se realiza mediante dos instrucciones, primero una instrucción Delete (borra la
fila) y a continuación otra instrucción Insert (Crea la fila con los nuevos valores).

Sintaxis objeto.UpdateOperation [= valor]

El Objeto rdoResultset
El Objeto rdoResultset es el conjunto de filas que devuelve la ejecución de una consulta. Es el
equivalente al Recordset de DAO

El Objeto rdoResultset se crea mediante el método OpenResultset del rdoConnection.

Ejemplo:
‘Creamos el objeto rdoEnvironment utilizando el objeto creado automáticamente por VB
Set GepaWs = rdoEnvironments(0)
‘El objeto rdoEnvironment crea el objeto rdoConnection
Set GepaConex = GepaWs.OpenConnection(“Gepa”, rdDriverNoPrompt, False)
‘(Gepa es el nombre de la conexión ODBC creada en el ordenador)
‘El objeto rdoConnection crea el objeto rdoResultset

Set GepaRs = GepaConex.OpenResultset("Select Ex_expedite, Ex_numproye, " & _


"Ex_presenta, Ex_plan, Ex_tipoexpe, Ex_tipoprop, Ex_tipotram, Ex_redaproy, Ex_situxpe, " & _
"Ex_Numero_Ini, Ex_subsiste " & _
"From Expedientes Order By Ex_Numero_Ini", rdOpenDynamic, rdConcurRowVer)

Puede ver que el proceso de creación de un rdoResultset en RDO no difiere demasiado de la


creación de un recordset en DAO.

Veamos cada una de las partes del Método OpenResultset

Set MirdoResultset = MiConexión.OpenResultset(nombre [,tipo [,tipoBloq [,opciones]]])

Donde
MirdoResultset = variable tipo rdoResultset que debe estar declarada.
MiConexión = Objeto Connection con el que se crea el rdoRsultset
Nombre = Nombre de una tabla o consulta de la base de datos, o una sentencia
SQL que pueda devolver filas.
Tipo = Tipo de cursor que se va a crear
TipoBloq = Tipo de bloqueo de la base de datos. Por defecto, lo crea solo lectura.
Opciones = Opciones que puede tener el rdoResultset

El argumento Tipo puede tener una de estos valores:

Constante Valor Descripción


rdOpenForwardOnly 0 (Predeterminado) Abre un rdoResultset tipo forward-only.
rdOpenKeyset 1 Abre un rdoResultset tipo Keyset
rdOpenDynamic 2 Abre un rdoResultset tipo Dinamico
rdOpenStatic 3 Abre un rdoResultset tipo estático

El tipo forwar-only es un rdoResultset en el que las filas solamente se pueden explorar en


sentido ascendente. No se puede retroceder .

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 28


El tipo Keyset es un rdoResultset que se puede actualizar, insertar nuevas filas, y se puede
recorrer en ambos sentidos sin limitación. Los miembros de este rdoResultset son fijos.
El tipo Dinámico es un rdoResultset que se puede actualizar, insertar nuevas filas, y se puede
recorrer en ambos sentidos sin limitación. Los miembros de este rdoResultset no son fijos.Es
similar al Dynaset de DAO.
El tipo estático presenta los valores existentes en la BD en el momento de su creación y no
detecta las posibles variaciones de los datos en la misma. Es similar al Snapshot de DAO

Para el parámetro Tipo de Bloqueo acepta los siguientes datos:

Constante Valor Descripción


rdConcurReadOnly 1 (Predeterminado) Sólo lectura.
RdConcurLock 2 Concurrencia pesimista.
rdConcurRowVer 3 Concurrencia optimista basada en el Id. de fila.
rdConcurValues 4 Concurrencia optimista basada en valores de filas.
rdConcurBatch 5 Concurrencia optimista usando actualizaciones de modo por
lotes. Valores Status devueltos por cada fila actualizada con
éxito.

El parámetro opciones acepta estos valores: (Se pueden sumar ambas)

Constante Valor Descripción


rdAsyncEnable 32 Ejecuta la operación de forma asíncrona.
rdExecDirect 64 (Predeterminado) Evita la creación de procedimientos
almacenados para ejecutar la consulta.

El objeto rdoResultset tiene algunas particularidades que no tienen los recordsets de DAO, por
ejemplo, poder obtener resultados múltiples, es decir, se pueden introducir varias sentencias
SELECT y cada una de ellas crea un conjunto de registros. Esto no significa que haya mas de
un rdoResultset, sino que existe un único rdoResultset con resultados múltiples. Se puede ir
accediendo a cada uno de los conjuntos de registros mediante el método MoreResults.

Propiedades del Objeto rdoResultset


El rdoResultset no tiene exactamente las mismas propiedades que el Recordset. Y además no
siempre funcionan tal como lo hacían en el recordset. En RDO van a depender del tipo de
cursor y del tipo de bloqueo. Veamos las propiedades del rdoResultset

AbsolutePosition. Igual que en RDO, pero no siempre funciona, ya que depende del tipo de
cursor.

ActiveConnection Devuelve una referencia a la conexión con la que está asociado el


rdoResultset

BatchCollisionCount Devuelve un valor que especifica el número de filas que no finalizaron


la última actualización por lotes. Devuelve un Long. En caso de que esta propiedad sea mayor
de 0 significa que la actualización por lotes no se ha completado con éxito. En este caso habrá
que ejecutar el método BatchUpdate para completar la actualización.

BatchCollisionRows
Devuelve una matriz de marcadores que indica las filas que han provocado colisiones en la
última operación de actualización por lotes. Devuelve un Variant con una matriz de las filas que
han provocado una colisión la última vez que se invocó el método BatchUpdate. El número de
elementos de esta matriz es el que indica la propiedad BatchCollisionCount

BatchSize (Propiedad)
Devuelve o establece un valor que especifica el número de instrucciones enviadas al servidor
en cada lote. De forma predeterminada se envían 15 instrucciones al servidor en cada lote. Esta

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 29


propiedad puede modificarse en cualquier momento. Si un DBMS no admite lotes de
instrucciones, puede establecer esta propiedad a 1, con lo que cada instrucción se enviará por
separado.

BOF, EOF Son idénticas a las mismas propiedades del Recordset de DAO

Bookmark Funciona igual que en el Recordset de DAO. Pero en RDO es posible que esa
propiedad no se pueda usar. Depende del tipo de cursor. Para asegurarse de que el objeto
rdoResultset admite marcadores, examine el valor de su propiedad Bookmarkable antes de
usar su propiedad Bookmark. Si Bookmarkable es False, el objeto rdoResultset no admite
marcadores y el uso de Bookmark producirá un error
La propiedad Bookmark no se aplica a los objetos rdoResultset de tipo forward-only.

En DAO la variable donde se guarda el Bookmark debía se un String. En RDO es un variant.


Desconozco la razón, pero usando una variable String para almacenar el Bookmark falla.

Bookmarkable Devuelve un valor que indica si un objeto rdoResultset admite marcadores, es


decir, si acepta la propiedad Bookmark.

EditMode Devuelve un valor que indica el estado de edición de la fila actual. Devuelve un
integer o una constante de acuerdo con la tabla siguiente:

Constante Valor Descripción

RdEditNone 0 No se está efectuando ninguna operación de modificación.


RdEditInProgress 1 Se ha invocado el método Edit y la fila está en buffer de copia.
RdEditInProgress 2 Se ha invocado el método AddNew y la fila actual del búfer de
copia es una fila nueva que no se ha guardado en la B. D.

LastModified Devuelve un marcador que indica la última fila modificada o agregada más
recientemente. Este marcador es el Bookmark de esa fila. Devuelve un Variant.

LockEdits Devuelve un valor de tipo Booleano que indica el tipo de bloqueo en vigor. Si
devuelve True utiliza bloqueo pesimista. Si devuelve False utiliza bloqueo optimista.

Si LockEdits es True y otro usuario ya tiene la página bloqueada, se producirá un error


al intentar usar el método OpenResultset. En general, los demás usuarios pueden leer
datos de las páginas bloqueadas.
Si LockEdits es False (valor predeterminado) y utiliza después Update mientras la
página está bloqueada por otro usuario, se producirá un error.

El bloqueo se realiza sobre una página de datos. La página suele se de 2 K (Ese es el


tamaño que utiliza Microsoft SQL Server)

LockType Devuelve o establece un valor entero de tipo Long que indica el tipo de tratamiento
de concurrencia. Los valores admitidos son:
Constante Valor
Descripción
(Predeterminado) El cursor es de sólo lectura. No se admiten
rdConcurReadOnly 1
actualizaciones.
rdConcurLock 2 Concurrencia pesimista.
rdConcurRowVer 3 Concurrencia optimista basada en el identificador de fila.
rdConcurValues 4 Concurrencia optimista basada en los valores de las filas.
Concurrencia optimista con actualizaciones por lotes. Se obtienen
rdConcurBatch 5
valores de estado para cada fila actualizada correctamente.
Lea la ayuda de VB para obtener mayor información de cada uno de los tipos.

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 30


Restartable Devuelve un valor que indica si un objeto rdoResultset admite el método Requery,
que vuelve a ejecutar la consulta en la que está basado el objeto rdoResultset. Debe usarse
antes de utilizar el método Requery para evitar que se produzca un error.

PercentPosition
Devuelve o establece un valor que indica o modifica la ubicación aproximada de la fila actual en
el objeto rdoResultset, basándose en el porcentaje con respecto al total de filas de dicho
objeto. El valor devuelto es un Single entre 0,0 y 100,0

Puede usar la propiedad PercentPosition con una barra de desplazamiento de un control Form
o TextBox para indicar la ubicación de la fila actual en un objeto rdoResultset. Esta propiedad
solamente se aplica a los rdoResultset tipo Keyset y Dynamic.

RowCount Devuelve el número de filas a las que se ha tenido acceso en un objeto


rdoResultset. Es un Long.
Esta propiedad no indica el número de filas del Resultset, sino el número de filas a las que se
ha accedido. No es por lo tanto, el equivalente a la propiedad RecordCount del Recordset DAO.
Si esta propiedad no está disponible en el controlador, devuelve -1

Status Devuelve o establece el estado de la fila o columna actual. El valor de esta propiedad
indica si la fila o la columna estarán implicadas en la próxima actualización optimista por lotes y
de qué modo lo estarán.

Los valores admitidos para la propiedad Status son:

Constante Valor Valor de la propiedad Prepared


(Predeterminado) La fila o la columna no se han modificado o se
rdRowUnmodified 0
han actualizado correctamente.
La fila o la columna se han modificado y aún no se han
rdRowModified 1
actualizado en la base de datos.
La fila o la columna se han insertado con el método AddNew,
rdRowNew 2
pero aún no se han insertado en la base de datos.
La fila o la columna se han eliminado, pero aún no se han
rdRowDeleted 3
eliminado de la base de datos.
La fila o la columna se han eliminado localmente y también de la
rdRowDBDeleted 4
base de datos.

StillExecuting Devuelve un valor de tipo Booleano que indica si una consulta está aún
ejecutándose.
Esta propiedad es muy útil (muy necesaria) para saber si la consulta ya está disponible, antes
de presentar los datos de esa consulta. La propiedad debe ser False para poder presentarlos.
Es típico crear un bucle parecido a este:

Do While GepaRs.StillExecuting = True


DoEvents
Loop

Transactions Devuelve un valor Booleano que indica si un rdoResultset permite


transacciones.

Type Devuelve un Long el tipo de rdoResultset. (0 = rdOpenForwardOnly, 1 = rdOpenKeyset,


2 = rdOpenDynamic, 3 = rdOpenStatic)

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 31


Updatable Devuelve un valor Booleano que indica si se pueden efectuar cambios en el
rdoresultset

Métodos del Objeto rdoResultset

El rdoResultset tiene algunos métodos comunes con el Recordset de DAO, sin embargo no se
puede esperar que funcionen siempre de la misma forma. En DAO era Visual Basic quien abría
la base de datos, y una base muy concreta, Access, dBase, etc., bases que controla
directamente Visual Basic a través de la dll correspondiente a la versión de la BD que vamos a
abrir. Esto no es exactamente igual en RDO. Aquí quien abre el fichero que contienen la base
de datos no es Visual Basic, sino el driver de ODBC. Y no solamente eso, dependiendo de la
base de datos, unas permiten hacer unas operaciones y otras no. Lo mismo podemos decir del
tipo de rdoResultset, del cursor y de si es lado cliente o lado servidor. Por lo tanto no se asuste
si pretende ejecutar un método y no funciona. Probablemente es que Visual Basic ha puesto
por defecto unas características a los objetos que no son las adecuadas. Y si no fuese posible,
en última instancia nos queda realizar directamente la operación que pretendíamos realizar con
el método, es decir, mediante las operaciones que nos permite el propio driver de ODBC. Eso
sí, en este caso estamos en sus manos. Lo veremos más adelante.

Método AddNew
Crea una nueva fila para un objeto rdoResultset actualizable.

Sintaxis MirdoResultset..AddNew

Funciona igual que el mismo método de DAO, se ejecuta el método AddNew, se introducen los
datos en los campos y se termina la operación con el método Update, que es cuando los datos
entran en la base de datos. Si se está usando cursores de tipo Client Batch los datos se
escribitrán en la BD cuando se ejecute el método BatchUpdate.
Hay que tener cuidado, pues el método AddNew no devuelve ningún error si se intenta añadir
una nueva fila a un rdoResultset no actualizable. Ese error va a salir cuando ejecutemos el
método Update. Para evitar este error hay que comprobar la propiedad Updatable del
rdoResultset.
Debe tener cuidado también con asegurarse que tras el método AddNew ejecuta el método
Update antes de cambiar de fila, ya que de no hacerlo se pierden los cambios realizados y VB
no avisa de ese error.
Si desea interrumpir la entrada de datos, una vez ejecutado el método AddNew puede anularse
usando el método CancelUpdate

MirdoResultset. CancelUpdate

La fila recién añadida no pasa a ser la fila actual. Sigue siendo fila actual la que era
anteriormente. Para que sea la nueva la fila actual basta con poner el siguiente código:

MirdoResultset.BookMark = MirdoResultset.LastModified

Pero eso sí, el rdoResultset debe aceptar marcadores. Para comprobarlo, se usa la propiedad
Bookmarkable.

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 32


Método BatchUpdate
Realiza una actualización optimista por lotes. Veamos que significa esto.
Este método solamente se puede aplicar a un rdoResultset del tipo Client Batch (Cuando se
crea el rdoResultset usando como tercer parámetro rdUseClientBatch) El tipo de rdoResultset
puede ser Keyset o Dynamic. En estas condiciones, cuando usamos el método Update para
guardar los datos, solamente se guardan en el rdoResultset local, pero no se meten en la base
de datos. Cuando se ejecuta este método, se envían a la base de datos todos los cambios
pendientes.

Sintaxis MirdoResultset.BatchUpdate (filaÚnica, forzar)

El parámetro filaÚnica es un Booleano que si es True, hace que la actualización sea solamente
de la fila actual. Si es False, se actualizan todas las filas pendientes.
forzar es tambiénun Booleano que si es True fuerza a escribir los valores, aunque puedan
causar colisiones.

Si usa el método CancelBatch, se descartan los cambios guardados en el objeto rdoResultset


local.

Método Close
Cierra un rdoResultset abierto. Es igual al método Close del Recordset de DAO

Sintaxis MirdoResultset.Close

Método Delete
Elimina la fila actual de un objeto rdoResultset actualizable.

Sintaxis MirdoResultset.Delete

Es posible deshacer la eliminación de una fila si emplea transacciones y el método


RollbackTrans, suponiendo que usa BeginTrans antes que el método Delete.

Se producirá un error al utilizar Delete si:

No hay ninguna fila actual.


La conexión o el rdoResultset es de sólo lectura.
Ninguna columna de la fila es actualizable.
La fila ya se ha eliminado.
Otro usuario ha bloqueado la que contiene la fila.
El usuario no tiene permiso para realizar la operación.

Método Edit
Inicia la operación de cambiar los valores de los datos de la fila actual o en un objeto
rdoResultset actualizable. Funciona de la misma forma que el método del mismo nombre del
Recordset de DAO. Al igual que en el método AddNew, es necesario terminar la operación con
el método Update.

Sintaxis MirdoResultset.Edit

Si cambia la fila actual antes de ejecutar el método Update, se perderán los cambios. Si desea
anular el cambio que está realizando, basta con ejecutar el método CancelUpdate.

Cuando la propiedad LockEdits del objeto rdoResultset es True (bloqueo pesimista), todas las
filas del conjunto de filas del objeto rdoResultset se bloquean en cuanto se ejecuta Edit, y se
mantienen bloqueadas hasta que se ejecuta Update.

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 33


Método GetRows
Recupera múltiples filas de un rdoResultset y las introduce en una matriz.

Sintaxis matriz = MirdoResultset.GetRows (filas)

Donde filas es el número de filas que se quieren recuperar. Es un Long


matriz es un Variant

El primer subíndice de la matriz identificará la columna y el segundo identifica el número de fila,


de esta forma:
matriz(intColumn)(intRow)
Método MoreResults

Este método se utiliza cuando se ha creado un rdoResultset de resultados múltiples, es decir,


se han empleado varias sentencias SELECT para crearlo. Cada sentencia formará dentro del
rdoResultset un juego de filas. Cuando se utiliza el método MoreResults se borran las filas del
conjunto de resultados actual y se colocan en su lugar las filas correspondientes al siguiente. El
método devuelve un Booleano que es True si ha encontrado un nuevo conjunto de resultados, o
False si no lo ha encontrado. No todas las bibliotecas de cursores son compatibles con
consultas de conjuntos de resultados múltiples. Por ejemplo, la biblioteca de cursores del
servidor no es compatible con este tipo de consultas si no desactiva el procesamiento del cursor
en un cursor de sólo lectura sólo hacia adelante con la propiedad RowsetSize a 1.

Método Move
Cambia la posición de la fila actual en un objeto rdoResultset. Funciona igual que el mismo
método del Recordset de DAO

Sintaxis MirdoResultset.Move filas[, inicio]

Métodos MoveFirst, MoveLast, MoveNext y MovePrevious


Funciona de la misma forma que los métodos del mismo nombre en el Recordset de DAO.

Método Requery
Actualiza los datos de un objeto rdoResultset volviendo a ejecutar la consulta en la que está
basado el objeto.

Sintaxis MirdoResultset.Requery [opciones]

El valor admitidi para Opciones es rdAsyncEnable (32) que ejecuta la operación de forma
asíncrona

Método Update
Termina una operación de modificación de datos o de añadir una nueva fila. Ya se ha
comentado su funcionamiento con los métodos AddNew y Update.

No vamos a profundizar más en los objetos RDO. Su comportamiento es muy parecido a DAO,
exceptuando los nombres de los objetos, y las particularidades del ODBC en cuanto a la
situación de los cursores.
ODBC es una tecnología ya obsoleta (En el año 2002) y no debe emplearse para nuevos
proyectos. Lógicamente un curso de Visual Basic debe incluir RDO, pero siempre para aplicarlo

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 34


al mantenimiento de aplicaciones ya existentes. No se debe emplear para nuevos proyectos, ya
que si se quiere emplear ODBC es mucho más práctico y sencillo emplear DAO en su versión
de ODBCDirect. Tendrá código compatible con DAO, y más rapidez que con RDO. Además
RDO es una tecnología considerada obsoleta por Microsoft, con lo que ello conlleva.
Microsoft dice, y este autor recomienda: USE ADO EN TODOS SUS NUEVOS PROYECTOS

Pero si usa Access con la base de datos instalada en el mismo ordenador que el programa, use
directamente DAO. Si usa Access olvídese de nuevas tecnologías. Con Access DAO significa:
Rapidez, sencillez, eficacia, control sobre el programa, independencia de drivers.

LSB Visual Basic - Guía del estudiante. Capítulo 13 Página 35


Visual Basic - Guía del Estudiante Cap. 14
ACTIVE X DATA OBJECT (ADO)

ADO es lo último de Microsoft en acceso a bases de datos. No se porqué, pero desde su inicio,
ADO está como metido en una aureola de dificultad a la que solamente pueden acceder
informáticos especialmente elegidos. Quizás sea el uso de palabras de argot muy rebuscadas,
que más que facilitar el estudio, atemorizan al principiante. La Guía del Estudiante pretende
quitar esos velos que ocultan la sencillez de lo cotidiano y mostrar la facilidad de esta técnica.
Con el estilo didáctico que caracteriza a este libro, pasaremos de las definiciones gloriosas e
iremos a lo verdaderamente importante: saber programar con ADO

ADO permite crear aplicaciones capaces de manipular bases de datos a través de un proveedor
OLE DB (Object Linking and Embedding for DataBase). El objetivo de OLE DB es poner a
disposición del programador una herramienta de nivel inferior que le de acceso universal a los
datos con independencia del origen de datos, ya sea un servidor de correo electrónico, una hoja
de cálculo u otro tipo de almacenamiento de datos. Debido a la complejidad de los elementos
de OLE DB, no se puede acceder a ellos directamente desde Visual Basic; para ello
utilizaremos los objetos ADO que permiten acceder a la práctica totalidad de las funciones de
OLE DB.

O
L
E Bases de datos
Relacionales
D
A B
D
Aplicación que accede a los datos

O
O
D
B
C Texto

Modelo de datos ADO

R
D
O Bases de datos
O
D relacionales
B
D C
A
O
Modelo DAO/RDO

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 1


Las características generales de ADO son:

· Mayor velocidad y facilidad de uso.


· Menor carga de memoria y de espacio en el disco duro.

Las características específicas que proporciona ADO para entornos de Cliente/Servidor (C/S)
son:
· Creación de los objetos de forma independiente. No se necesita navegar por ninguna
jerarquía de objetos para poder crearlos. La mayoría de los objetos se pueden
instanciar de forma independiente. De esta forma crearemos solo los objetos que
necesitemos.
· ADO nos permite utilizar los procedimientos almacenados en el sistema gestor de la
base de datos (si este soporta esta funcionalidad), pudiendo recoger los resultados
devueltos por dichos procedimientos como parámetros de salida. Esta característica
permite mejorar el rendimiento y la rapidez de las aplicaciones.
· Diferentes tipos de cursores.
· Soporte para limitar el número máximo de registros devueltos de una sola vez en un
recordset. Esta característica mejora el rendimiento tanto de la aplicación como de la
red.
· Soporte para recibir varios recordset como resultados devueltos de un procedimiento
almacenado.

Hay que tener en cuenta que todas estas características están limitadas por el servidor de los
datos. Es decir, si el servidor de datos no soporta procedimientos almacenados, no podremos
utilizar con él las características de ADO que se refieren a dichos tipos de procedimientos.

Fig 72.1 Jerarquía de Objetos ADO.

*
Connection

Errors Error*

Command*

Parameters Parameter*

Recordset
*

Fields Field*
* Todos los objetos marcados con un asterisco contienen la colección Properties con un
subconjunto de objetos Property.
Properties
Property

Como puede verse en la figura, existen tres objetos principales dentro de ADO: El objeto
Connection, el objeto Command y el objeto recordset. Luego veremos algunas de las
características principales de cada uno de estos objetos.

Antes de proseguir con estos objetos vamos a explicar donde y porqué se deben utilizar objetos
ADO en vez de objetos DAO u objetos RDO

Hasta ahora habíamos utilizado bases de datos Access, y también otras bases de datos
sencillas como dBase. Acceder a Access es extremadamente fácil. Y ello es debido a que
Access es una base de datos sin grandes aspiraciones en cuanto a seguridad. Es una gran
base de datos, y tiene sus dispositivos de seguridad en cuanto a permisos de acceso (Vea El
dbEngine. Visión desde DAO y la propiedad SystemDB en el Capítulo 12) sin embargo estas
posibilidades se usan en muy pocas ocasiones, y estos mecanismos de seguridad de Access

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 2


tampoco son una maravilla. Por lo tanto Access se ha quedado como una gran base de datos
para aplicaciones que no pasen de algunos centenares de miles de registros y con pocos
puestos de operación. En esta base de datos, el método ideal de acceso es DAO, bien
directamente o a través de ODBC Direct. Cuando se accede directamente, la BD se suele
buscar bien mapeando el disco del servidor como una unidad más del puesto cliente, o bien
accediendo a través de la dirección IP del servidor.

Cuando queremos empezar a tener una seguridad en los accesos, disponer de privilegios
distintos para cada usuario, trabajar en una red de área local con muchos usuarios, hay que
recurrir a bases de datos tipo Oracle o SQLServer. Ya empezamos a tener problemas: Visual
Basic no puede acceder directamente a abrir estas bases de datos. Podemos acceder a través
de ODBC, pero como ya se dijo en el, capítulo correspondiente, ODBC se ha quedado obsoleto.
Y Microsoft ha sacado para ello ADO. Y ADO permite abrir la base de datos usando para ello un
dispositivo intermedio que es el proveedor OLE DB. Este no es más que una DLL. Mejor dicho,
un juego de DLLs que puede ver en la carpeta:

C:\Archivos de Programa\Archivos Comunes\System\Ado

Estas DLLs permiten conectar con las bases de datos más conocidas (Oracle, SQLServer,
Access y las demás BD controladas por el motor Jet). ADO funciona de forma diferente a
ODBC. Con ODBC se preparan conexiones permanentes en el ordenador, y cualquier
programa puede acceder a la BD a través de esas conexiones. Con ADO no hay que preparar
previamente ninguna conexión. Es el propio programa el que llama al proveedor de datos OLE
DB y le pasa como parámetros los datos necesarios para que este realice la conexión y abra la
BD. Si hubiese dos programas ejecutándose simultáneamente y accediendo a la misma base
de datos a través de ADO, cada programa prepara una conexión a esa BD. En ODBC
podríamos ver las conexiones existentes en el PC a través del Panel de Control | Fuentes de
Datos ODBC. En ADO no existe esa posibilidad ya que, como se ha dicho, es el propio
programa quien crea esa conexión al ajecutarse.

Para que VB pueda acceder a ADO es necesario introducir en el programa la referencia a


Microsoft ActiveX Data Objets 2.1 Library (Proyecto|Referencias)

Una particularidad de ADO frente a lo ya visto con DAO o RDO es que ADO se salta la
jerarquía a la hora de crear nuevos objetos. En DAO, el objeto DAO superior creaba al objeto
DAO inferior (Recuerde aquello del juego de niños). En ADO podemos crear cada objeto sin
que exista el objeto inmediatamente superior. Por ejemplo podemos crear un recordset sin que
exista el objeto Connection. Claro que en este caso, a la hora de crear el objeto recordset
deberemos indicarle, mediante los parámetros que debemos aportar en la sintaxis de creación
del recordset, todos aquellos datos que le aportaríamos a la creación del objeto Connection.
Como ve no tiene ventajas. Solamente que nos desentendemos un poco de abrir y cerrar el
objeto Connection.

Veamos como se crea la conexión: Mediante el Objeto Connection

EL OBJETO CONNECTION

El objeto Connection representa una sesión con el origen de los datos. Dependiendo de la
funcionalidad del proveedor de los datos podremos utilizar determinadas propiedades, métodos
y colecciones de este objeto. La función de este objeto es recoger toda la información del
proveedor de los datos que se va a utilizar para crear un objeto recordset.

Para crear un objeto Connection, previamente debemos declararlo como variable objeto
Connection:

Dim MiConexion as ADODB.Connection

El sitio donde se debe declarar depende como siempre, del ámbito que deseamos que tenga
ese objeto.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 3


Para crear el objeto Connection deberemos utilizar la siguiente sintaxis:

Set MiConexion = New ADODB.Connection

Nota: En el caso de que ejecutemos la aplicación y nos salga un error diciendo que el tipo no
está definido por el usuario, es que no hemos añadido la referencia de “Microsoft Actives Data
Objects Library x.x”

La conexión ¿está creada?. Sí, pero de momento es completamente inútil ya que no sabe ni
siquiera que base de datos debe abrir, ni con que usuario, ni las condiciones en las que debe
abrir esa base (Solo lectura, etc.) Esta información se la pasamos mediante la propiedad
ConnectionString (Cadena de conexión)

La propiedad ConnectionString

Es la propiedad más importante del objeto Connection. Se basa en encadenar una serie de
argumentos en una cadena de caracteres. Los diferentes argumentos son (dependiendo del
proveedor OLE DB y de la configuración de la red, se necesitarán todos o parte de ellos)

Provider Especifica el nombre del proveedor que se usa en la conexión. (Oracle,


SQLServer, Jet, etc)
Data Source Especifica el nombre de la fuente de datos para la conexión. (Nombre de la
base de datos a la que se va a acceder.
User Id Especifica el nombre de usuario que abre la conexión. Debe ser un usuario ya
declarado en la base de datos.
Password Especifica la clave utilizada por el usuario para abrir la conexión. Debe coincidir
con el que tiene ese usuario registrado en la Base de datos.
File Name Especifica el nombre del fichero específico de proveedor, que contiene la
información de configuración de la conexión. Este fichero es útil en
instalaciones en red que requieran modificaciones de conexión frecuentes.
Remote Provider Especifica el nombre de un proveedor de datos remoto cuando se
utiliza una conexión cliente/servidor
Remote Server Especifica el nombre del camino al servidor que se va a usar cuando
se establece una conexión cliente/servidor

Como ejemplo para la conexión a una base de datos Oracle, con el usuario que esa BD tiene
por defecto (scott) y el Password de este usuario (tiger) tendremos que especificar en el
ConnectionString la siguiente cadena de caracteres.

‘Provider=MSDAORA.1;Password=tiger;User ID=scott;Data Source=MADRID;’

donde el valor de Source es la cadena de conexión de Oracle que previamente tiene que estar
configurada con el SQL*Net o Net8 de Oracle.

Si lo que queremos es crear una conexión con una base de datos Access 2000

‘Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\GuiadelEstudiante\PruebaADO.mdb;’

Si la base de datos es de Access 97 entonces tendremos que especificar otro provider:

‘Provider=Microsoft.Jet.OLEDB.3.5;Data Source=C:\GuiadelEstudiante\db1.mdb;’

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 4


Para una base de datos SQLServer

"Provider=SQLOLEDB.1;Password=ayudas01; User ID=ayudas01; Initial


Catalog=Ayudas_M; Data Source=ayudas_sql" (en una línea única)

Como puede comprobar, resulta una tanto complicado construir la cadena de conexión y
mientras que seamos novatos en ADO podemos tener problemas para crear esta cadena.
¿Pero es que no existe una manera más fácil de construir esta cadena? Efectivamente. Hay un
pequeño truco mediante el cual no solo podemos crearla con un asistente, sino que además
probaremos si la conexión es satisfactoria o no.

Truco para construir la cadena de conexión.

1) Primero tenemos que incluir el componente “Microsoft ADO data control 6.0 (OLEDB)”.
Podemos hacerlo pulsando Ctrl.-T o en el menú Proyecto à Componentes.
2) Metemos en nuestro formulario el control y pulsamos F4 para ver sus propiedades.
3) Hacemos Click en la propiedad
ConnectionString y nos
aparecerá el botón de puntos
suspensivos. Hacemos Click en
el botón.

4) Ahora nos aparece el asistente


que nos mostrará 3 opciones.
Utilizar un DSN de archivo,
utilizar un controlador ODBC o
utilizar una cadena de conexión.
En todos los casos, a la
derecha de la opción hay una
opción que nos permite
seleccionar o generar el origen
de los datos. Usaremos la
cadena de conexión (opción por
defecto) y pulsaremos el botón
generar.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 5


5) Al pulsar el botón generar, nos aparece otra ventana en la que tenemos cuatro
pestañas aunque únicamente necesitaremos dos de ellas para crear una cadena de
conexión correcta y probada. El resto de las pestañas forman parte de otro capítulo
exclusivo del control data de ADO, aunque le invito a que curiosee por ellas.
Seleccionaremos el proveedor de datos que queramos utilizar y pulsaremos el botón
siguiente para pasar a la siguiente pestaña.

6) En la Pestaña conexión, tenemos que proporcionar los datos correspondientes al


proveedor de la base de datos a la que queremos conectar. Por ejemplo para conectar
con una base de datos de tipo MS Access (MS Jet 4.0 OLEDB Provider para la versión
2000 de Access, MS Jet 3.5 OLEDB Provider para la versión 97 de Access), tenemos
que decirle el nombre y path de la BD. Para ello podemos utilizar el botón de los puntos
suspensivos, que abrirá una ventana que permitirá seleccionar el archivo .mdb . Si
utilizamos el proveedor de datos de Oracle, tendremos que indicarle como nombre de
servidor la cadena de conexión utilizada en el SQL Net o en el Net8 de Oracle (la
misma cadena que especifica cuando se conecta a través de SQL*Plus).
En esta pestaña existen dos opciones interesantes:
· “Contraseña en Blanco”, si la marcamos no nos permitirá teclear la contraseña.
· “Permitir guardar la contraseña”, dependiendo de si está o no seleccionada,
incluirá o no en la cadena de conexión la clave del usuario. Para la primera
prueba le recomiendo que la marque. No obstante, haga diferentes pruebas
con ellas para ver los resultados.
Después de haber dado esta información, pulsaremos el botón Probar conexión. En el
caso de que haya algún error, el asistente nos lo indicará con un mensaje.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 6


Prueba de conexión (fallida) con Proveedor de datos de Oracle

Prueba satisfactoria

7) Una vez que hemos probado satisfactoriamente la conexión, pulsaremos aceptar y


volveremos a la pantalla inicial, la de las 3 opciones. La diferencia es que ahora
tenemos la cadena de conexión rellenada por el asistente. Ahora podemos copiarla con
ctrl.-C y llevarla a la parte del código donde queremos establecer la conexión. No se
olvide de que es una cadena y que cuando se asigne a la propiedad ConnectionString
debe ir entre comillas dobles.
8) Una vez que hemos probado que funciona al abrir el objeto Connection, No debemos
olvidarnos de eliminar el control data de ADO y de quitar el componente de nuestro
proyecto, salvo que lo vayamos a utilizar para otra cosa.

Ya conocemos el truco para formar la cadena de conexión y se la hemos introducido en la


propiedad ConnectionString ¿Ya está creada la conexión? Sí, pero todavía no sirve para
obtener datos de la base de datos. Pero ya hemos avanzado mucho. Ahora nuestro programa
ya sabe al menos, como poder abrir esa base de datos, pues conoce su nombre, usuario que la
abre y Password. Solamente queda aplicar un método del objeto Connection: el método Open
con una sintaxis que no es excesivamente difícil:
Miconexión.Open

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 7


La conexión se va a realizar a una base de datos que está en un servidor. Este servidor puede
definirse, bien por su dirección IP o por su nombre. Lo normal es definirlo por su nombre
(Server_SQL_Mae) y no por su dirección IP. Obviamente el nombre del servidor corresponderá
a una dirección IP (Vamos a considerar una red IP estática, pues si pretendemos entrar a
explicar lo que es una red con direcciones IP asignadas dinámicamente se nos complica la
explicación). Esa dirección IP debemos indicársela al PC en el fichero Hosts (o Lmhosts) que
están en la carpeta Windows o en una de sus subcarpetas. En estos ficheros explica como
hacerlo. No se extrañe si, una vez indicado en ese fichero, sigue sin encontrarlo. La primera
conexión con el servidor la busca mediante llamadas broadcast en la red que no siempre son
bien tratadas por los routers. En muchas ocasiones he tenido que buscar el servidor a mano
(entorno de red) y, milagros de Windows, a partir de esa operación ya lo encuentra sin
problemas.

Para seguir un poco el ejemplo que acompaña a este capítulo, vamos a ver el código utilizado
para crear la conexión. En el ejemplo usamos una base de datos Access (No es la mejor para
demostrar como funciona ADO, pero es la que los alumnos van a tener con mayor facilidad.
Una base Oracle o SQL no se instala fácilmente en un ordenador personal)

Set MiConexion = New ADODB.Connection


'MiConexion.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\GuiaDelEstudiante\ADO\PruebaADO.mdb;Persist Security Info=False"
'MiConexion.Open

Ahora nuestro programa ya está en contacto con la base de datos. Lo que falta ya lo puede
suponer: crear un recordset.

Aquí vamos a ver la primera diferencia con DAO. El recordset no lo crea el objeto Connection.
Se crea él a sí mismo. Para que pueda existir un objeto Recordset primero hay que declararlo:

Dim MiRecordset As ADODB.Recordset (Hay que declararlo en el sitio adecuado


dependiendo del ámbito que necesite)

En el procedimiento donde se vaya a crear el recordset, para crearlo utilizaremos la siguiente


sintaxis:

Set MiRecordset = New ADODB.Recordset (Ya está creado. Pero no está abierto, ahora
hay que abrirlo)

MiRecordset.Open "Alumnos", MiConexion, adOpenDynamic, adLockOptimistic

Ya tenemos abierto el recordset. En este caso el recordset está formado por todos los registros
con todos sus campos de la tabla Alumnos, que está en la base de datos definida en la
conexión MiConexion, es del tipo Dynamic y el bloqueo de escritura es optimista.

Podríamos elegir ciertos registros, y solamente unos campos. Utilizaríamos una sentencia SQL

MiRecordset.Open "Select Alumno_Nombre, Alumno_Ape1, Alumno_Ape2 From Alumnos " _


& “Where Alumno_Nombre = ‘Luis’”, MiConexion, adOpenDynamic, adLockOptimistic

Si no hubiésemos creado previamente el objeto Connection, podríamos crear y abrir igualmente


este objeto recordset, pero, en vez de pasarle el nombre de la conexión (MiConexion) le
pasaríamos la cadena de conexión usada para crear ese objeto Connection.

Set MiRecordset = New ADODB.Recordset

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 8


MiRecordset.Open "Alumnos", "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\GuiaDelEstudiante\ADO\PruebaADO.mdb;Persist Security Info=False",
adOpenDynamic, adLockOptimistic
(Es solamente una línea. Ha sido Word quien la ha troceado)
Ahora ya podemos presentar los campos del recordset, usando la sintaxis que ya conocemos
de DAO

TbNombre = “” & MiRecordset!Alumno_Nombre


TbApe1 = “” & MiRecordset!Alumno_Ape1
TbApe2 = “” & MiRecordset!Alumno_Ape2

Hagamos una pequeña pausa. Observe que hay diferencias de trabajar con ADO o hacerlo con
DAO.

Con DAO.

Declarar MiSesion, MiBase y MiRecordset


Dim MiSesion as Workspace
Dim MiBase As DataBase
Dim MiRecordset as Recordset

Crear el objeto Workspace, el objeto DataBase y el objeto Recordset


Set MiSesion = Workspaces(0)
Set MiBase = MiSesion.OpenDatabase (“C:\GuiadelEstudiante\Alumnos.Mdb”)
Set MiRecordset = MiBase.OpenRecordset (“Alumnos, dbOpenDynaset)

Con ADO (Creando el objeto Connection)

Declarar MiConexion y MiRecordset


Dim MiConexion As ADODB.Connection
Dim MiRecordset As ADODB.Recordset

Crear la conexión y ponerle la cadena de conexión en su propiedad ConnectionString


Set MiConexion = New ADODB.Connection
MiConexion.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\GuiaDelEstudiante\ADO\PruebaADO.mdb;Persist Security Info=False"

Abrir el objeto Connection


MiConexion.Open

Crear el objeto recordset


Set MiRecordset = New ADODB.Recordset

Abrir el objeto Recordset


MiRecordset.Open "Alumnos", MiConexion, adOpenDynamic, adLockOptimistic

Con ADO (Sin crear el objeto Connection)

Declarar MiRecordset
Dim MiRecordset As ADODB.Recordset

Crear el Recordset
Set MiRecordset = New ADODB.Recordset

Abrir el Recordset
MiRecordset.Open "Alumnos", "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\GuiaDelEstudiante\ADO\PruebaADO.mdb;Persist Security Info=False",
adOpenDynamic, adLockOptimistic

Observe siempre que tanto en las declaraciones del objeto Connection y del objeto Recordset,
como en su creación, debemos anteponer siempre la palabra ADODB

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 9


Tanto el objeto Recordset como el objeto Connection se deberán cerrar cuando ya no se
utilicen, o al menos, al cerrar la aplicación. Esto es tanto más necesario cuanto mayor sea la
seguridad de la base de datos que vamos a utilizar. En algunas bases de datos, dejar una
sesión abierta significa dejar una aplicación zombie ejecutándose en el servidor, que habrá que
cerrar desde su propio sistema operativo. Este problema no le va a ocurrir utilizando Access,
pero como ya se dijo al principio, Access no es el mejor ejemplo de utilización de ADO. Para
cerrar una sesión y un recordset utilizaremos el método Close

MiRecordset.Close
MiSesion.Close (Recuerde que debe cerrar antes el recordset que la conexión)

¿Qué pasa con el equivalente del Workspace?

Cuando resumíamos en la página anterior el código a usar si usábamos DAO o ADO, parecía
(aunque no fuese cierto) que podíamos asimilar estos objetos

DAO ADO

Recordset Recordset
DataBase Connection
WorkSpace ¿

Efectivamente el Workspace no tiene algo que pudiésemos decir “equivalente” en ADO. Esto
es debido a que ADO ya considera que el acceso desde los usuarios lo gestiona directamente
la base de datos. Recuerde que el Workspace en DAO era una “sesión de trabajo” de la base
de datos, donde podíamos asociar un Workspace a cada usuario. ADO ya le pasa a la BD el
nombre del usuario y su Password para que la propia base de datos quien autorice a ese
usuario.

Algunas cosas que le van a ocurrir cuando ya haya creado el recordset.

El empleo de bases de datos complejas en cuanto a seguridad nos va a obsequiar con


limitaciones a los recordsets que vamos a abrir en ADO. Y además esas sorpresas van a ser
distintas si usa uno u otro tipo de base de datos. (nos centraremos solamente en Oracle y
SQLServer. Access, con la modestia que le caracteriza, no va a dar ningún problema.)

Los recordsets abiertos mediante una consulta SQL (aquellos en los que seleccionamos parte
de los registros mediante Select … Where van a crearse solo de lectura. Independientemente
de los parámetros que le pasemos a la hora de crearlos. La descripción del error va a ser algo
así como que el cursor es solamente de lectura. También observará con frecuencia, cuando
intente ir a un registro anterior al actual, MiRecordset.MoveFirst, p.e.) que le enviará un error
diciendo que el cursor es solamente de avance hacia a delante. Estos efectos los observará
también cuando use la instrucción SQL Order By. No hay que arrojar la toalla solamente por
esto. Cuando eso ocurra, lo que hay que hacer es volver a crear el recordset de forma que
acepte escritura y movimiento hacia atrás. Eso generalmente se logra abriendo el recordset
con todos los registros de la tabla, e incluyendo en él todos los campos.

En vez de :
MiRecordset.Open "Select Alumno_Nombre, Alumno_Ape1, Alumno_Ape2 From Alumnos " _
& “Where Alumno_Nombre = ‘Luis’”, MiConexion, adOpenDynamic, adLockOptimistic

usar esta otra alternativa:

MiRecordset.Open "Alumnos", MiConexion, adOpenDynamic, adLockOptimistic

Posiblemente necesitemos crear dos recordsets en un mismo procedimiento. Por ejemplo, es


muy típico tener que buscar el último registro para ver el último número de un identificador de
registro (Alumno_ID) y poner en este campo, al registro que vamos a crear, un número igual a

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 10


ese más 1. En ese caso, abriríamos el recordset usando la sentencia Order By Alumno_ID.
Cuando queramos introducir un nuevo registro mediante:

MiRecordset.AddNew nos dirá que el cursor (el recordset, para entendernos) es


solamente de lectura. La solución es, abrir el recordset con la sintaxis anterior, leer el número
de Alunmo_ID, cerrar el recordset, crear otro recordset con el mismo nombre, usando la
sintaxis:

MiRecordset.Open "Alumnos", MiConexion, adOpenDynamic, adLockOptimistic

Ahora ya nos permitirá usar el método AddNew. Basta con añadir las líneas de código
adecuado para introducir los valores en cada campo:

Mirecordset.AddNew
MiRecordset!Alumno_ID = Valor numérico
MiRecordset!Alumno_Nombre = Valor string
Etc.
….
MiRecordset.Update

No renuncie nunca a intentar hacer esto. No siempre funciona. Pero esto es mucho más
sencillo que introducir los datos “a capón” utilizando la instrucción SQL Insert que ya veremos
más adelante. SQLServer es bastante más dócil que Oracle para usar el método AddNew.

A este respecto, hay que citar la propiedad CursorLocation que veremos más adelante. Si
creamos un cursor lado cliente, seguramente nos permitirá utilizar más opciones (entre ellas
AddNew) que si lo establecemos de lado servidor. Tenga en cuenta que si usa un cursor lado
cliente, el recordset no se actualiza cuando otro usuario realiza modificaciones en la base.

Modificar datos mediante EDIT

En ADO no hace falta usar Edit para modificar los datos del registro actual. Edit no existe en
ADO. Para modificar un dato basta con poner el mismo código que utilizábamos en DAO, pero
sin comenzar por la línea Mirecordset.Edit. Colocándonos en el registro a modificar pondremos:

MiRecordset!Alumno_Nombre = “Pedro”
MiRecordset!Alumno_Ape1 = “Perez”
MiRecordset.Update

De cualquier forma, esto tampoco tiene porque funcionar en todas las bases de datos. En ese
caso tendremos que recurrir, al igual que para un registro nuevo, a las instrucciones SQL, que
en este caso será Update. Pero ya lo veremos más adelante. Hasta ahora solamente he
querido usar el código más simple para que pueda empezar con ADO, y sobre todo, para que
vea que esta es una técnica completamente accesible, aunque, dadas las grandes prestaciones
que tiene, un poco más adelante se va a complicar algo.

Ya ha visto que podemos trabajar perfectamente con recordsets, tal como lo hemos hecho con
el DAO de toda la vida. Pero ya lo comentábamos al principio, parece que hay que adornar lo
obvio para que no lo parezca tanto. Y ahí viene el Objeto Command, que como habrá podido
ver en la figura de la Jerarquía de los objetos ADO, es un objeto que aún no sabemos lo que
hace.

El objeto Command lo que va a hacer es crear un recordset. O también, meter “a capón” un


nuevo registro, o borrarlo, utilizando directamente instrucciones SQL. Hay que darse cuenta
que ADO trabaja con una gran diversidad de bases de datos, y no todas trabajan igual. Por eso,
muchas veces fallan operaciones tan sencilla como añadir un nuevo registro con el método
AddNew del recordset

MiRecordset.AddNew

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 11


Y hay que emplear una instrucción SQL: INSERT

En estos casos, en ADO utilizamos el método EXECUTE sobre el objeto Connection. Creamos
una variable, StrIntroducir, con el contenido de la instrucción SQL y ejecutábamos esa
instrucción mediante Execute

StrIntroducir = "Insert Into INT_DOCUMENTOS " _


& "(CL_DOC,NOM_DOC,TITULO_DOC,AUTOR_DOC,CL_TEMA_DOC,CL_DPT_DOC,” _
& “L_TIPO_DOC,FICH_DOC,FECHA_EMISION_DOC,ULTIMA_HORA_DOC,VISIBLE_DOC)"_
& "Values (" & NumeroDocumento & ",'" & TbTitulo & "','" & TbTitulo & "','" & TbTitulo.Tag _
& "',19,2,1,'" & HRefPrensa & "/" & TbNombFichTIF & "','" & Date & "',0,1)"

ConexBDPrensa.Execute StrIntroducir

Esta línea (StrIntroducir) es el contenido de la propiedad CommandText de un objeto Command


de ADO. Ni más ni menos que una instrucción que queremos realizar sobre la BD. Un objeto
Command tiene pocas cosas más. Como objeto ADO que es tiene sus propiedades y métodos.
Pero en esencia es lo que acaba de ver con la instrucción EXECUTE del objeto Connection. Lo
que pasa, que ADO lo han hecho muy organizado, y por eso tiene la categoría de Objeto. Es
hacer lo mismo, utilizando las mismas expresiones, pero dándole más cuerpo.

Con la instrucción anterior, lo que hacíamos era añadir un registro. Si lo que queremos hacer
es crear un recordset, la instrucción SQL comenzaría por “Select * From ….” Y el método
EXECUTE devolvería un Recordset

StrIntroducir = “Select * From Alumnos Where Apellido1 = ‘Suarez’”

Podemos crear un recordset (MiRecordset, previamente declarado como tal) con esta
instrucción

MiRecordset = ConexBDPrensa.Execute StrIntroducir

O con estas otras

Set MiComando as New ADODB.Command


MiComando.ActiveConnection = ConexBDPrensa
MiComando.CommandText = “Select * From Alumnos Where Apellido1 = ‘Suarez’”
MiRecordset = MiComando.Execute

Verá el ejemplo completo al final del capítulo.

Ahora, tras la explicación informal de cómo se crea una conexión y un recordset en ADO, y que
es un Command, vamos a entrar a conocer sus propiedades y métodos. Al final, y con un buen
ejemplo realizado de varias formas, entenderá perfectamente la forma de trabajar con ADO.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 12


ADO. El Objeto Connection
Un objeto Connection representa una conexión abierta con un origen de datos. Ya hemos visto
como crear un objeto Connection, por lo que vamos a pasar directamente
a ver sus objetos, colecciones, propiedades y métodos.

Como puede verse en la figura, el Objeto Connection tienen los objetos


Command y Recordset, y la colección Errors.

El Objeto Recordset es el recordset de toda la vida: un conjunto de


registros que contienen datos. El Objeto Recordset, aunque pertenece al
objeto Connection, puede crearse sin que exista previamente un objeto Connection. Esta es
una de las propiedades de los objetos ADO: no necesita cumplir estrictamente con la jerarquía.

El Objeto Command es una definición de un comando específico que se piensa ejecutar contra
un origen de datos. Los objetos Command sirven para tener almacenadas operaciones de
acceso a datos y usarlas en el momento adecuado, simplemente citándolas. Lo que obtenemos
de un objeto Command es, o un recordset (verá que no merece la pena usar un objeto
Command para crear un recordset, puesto que se pueden crear directamente) o una operación
que afecte a los registros de la base de datos (añadir registros, borrarlos, si es que no se deja
hacer eso mediante recordsets)

La Colección Errors es el conjunto de errores generados por el proveedor de datos ante el


fallo de una operación de acceso. La colección Errors se refiere únicamente a los errores
generados por el proveedor, no a los fallos interceptables producidos por el programa, que
deben ser tratados de la forma habitual: mediante Err

Propiedades del Objeto Connection (Lea esto de las propiedades sin complicarse
demasiado la vida. Las realmente importantes verá que están advertidas debidamente)

Las propiedades del objeto Connection dependen de cada proveedor. No todos se comportan
de igual forma, por lo que cada propiedad debe condicionarse a si el proveedor es capaz de
ofrecerla.

Propiedad Attributes

Es un Long. Acepta dos valores o la suma de los dos:

adXactCommitRetaining
adXactAbortRetaining

Estos atributos condicionan el modo de operación de la conexión con los métodos


CommitTrans y RollBackTrans.
Propiedad CommandTimeout
Indica, en segundos, el intervalo de espera para que se ejecute un comando (Objeto
Command) antes de que finalice el intento y se genere un error. Es un Long. El valor
predeterminado es 30.
Propiedad ConnectionTimeout
Indica, en segundos, el intervalo de espera para establecer una conexión antes de que finalice
el intento y se genere un error. Es un Long y el valor predeterminado es 15.
Propiedad ConnectionString (IMPORTANTE)
Es una cadena de caracteres que contiene la información que se utiliza para establecer una
conexión a un origen de datos. (Vea la explicación amplia más atrás)

La cadena de conexión tiene varios argumentos, todos ellos separados por un punto y coma (;)
de la forma
argumento1 = valor; argumento2 = valor; argumento3 = valor etc.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 13


ADO procesa solamente cuatro argumentos: Provider, File Name, Remote Provider y Remote
Server. Los demás argumentos los pasa al proveedor para que el los procese (Usuario,
Password, etc)

Si al emplear el método Open se utiliza el parámetro Connection String, este parámetro utilizado
en el método Open sustituirá a cualquier otro existente anteriormente. Una vez abierta la
conexión, esta propiedad no se puede cambiar puesto que es solamente de lectura.
Los argumentos File Name y Provider son excluyentes.

Propiedad CursorLocation (IMPORTANTE)


Establece o devuelve la posición de un servicio de cursores. Es un Long, y acepta las siguientes
constantes:

AdUseNone No se usan servicios de cursor. (Esta constante es obsoleta y aparece


únicamente por compatibilidad con versiones anteriores.)
AdUseClient Usa cursores del lado del cliente.
AdUseServer Predeterminado. Usa cursores del lado servidor.

Esta propiedad parece que no dice nada. Y es sumamente importante.

Los cursores son, por decirlo de alguna manera, los mecanismos de la base de datos donde se
crean los recordsets. Se estará dando cuenta que las bases de datos que tienen cursores son
ya bases de datos con mecanismos propios para la creación de recordsets. (SQL Server u
Oracle, p.e.) Estas bases de datos trabajan como aplicaciones cliente – servidor. Tienen en el
servidor, aparte de los datos, la mayoría de sus recursos. En el cliente tienen prácticamente los
recursos de conectividad, y poco más. Esta conectividad permite enviar desde el cliente una
petición a la base de datos alojada en el servidor. Esa petición será el resultado por ejemplo, de
una sentencia SQL. Al recibirla el servidor, gestionará la obtención de los resultados y una vez
que los haya conseguido viene su primera duda: ¿Dónde los almaceno? Puede almacenarlos
en el servidor, y cada vez que necesitemos un nuevo registro, por ejemplo al ejecutar la
sentencia MiRecordset.MoveNext, el cliente se lo indica al servidor y este le envía el nuevo
registro. También puede almacenar los datos obtenidos en el cliente, y de esta forma el cliente
puede moverse con entera libertad a lo largo de los registros del recordset. Puede hasta
contarlos y saber en que posición está. La diferencia entre uno y otro sistema es que en el
primer caso el tráfico por la red es mínimo (solamente se envía la información estrictamente
necesaria) y en el segundo caso, se envía mucha información de un golpe, la correspondiente a
todos los registros del recordset, independientemente de si se va a usar en el servidor o no.

Considerando el tráfico generado, parece que es mejor crear los cursores en el lado servidor.
Pero esto trae también sus dificultades. Nos priva de muchas propiedades del recordset. Una
propiedad muy usada, AbsolutePosition, no la tienen los cursores de lado servidor,
circunstancia que no nos debe sorprender, ya que al no estar todos los registros en el cliente,
éste, aunque disponga de todos los datos guardados en todos los campos de un determinado
registro, no puede saber que posición ocupa ese registro dentro de la totalidad de registros del
recordset. Por lo tanto, usar cursores de lado cliente o lado servidor será siempre una decisión
a tomar dependiendo de la velocidad de la red, de la memoria disponible en el cliente, de la
complejidad del programa, etc.

Recuerde que por defecto, ADO crea cursores de lado servidor. Para que la conexión le cree
todos los cursores de lado cliente basta ejecutar la instrucción:

MiConexion.CursorLocation = adUseClient

Si desea hacer transacciones, deberá crear cursores del lado servidor, ya que los de lado
cliente no las admiten. Comprenderá según vaya programando y encontrándose con
problemas, que esta propiedad es absolutamente importante.

Este valor debe establecerlo antes de crear la conexión. De esta forma, todos los cursores
creados con esa conexión serán de lado cliente o lado servidor, según haya elegido. Pero
muchas veces sería ideal que unos recordsets tuvieran el cursor de un tipo y otros de otro. Los

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 14


recordsets también tienen esta propiedad, por lo que puede elegir el lado deseado para cada
recordset utilizando esta propiedad aplicada no a la conexión, sino al recordset.

El número de registros que el servidor envía al cliente, cuando el cursor es de lado servidor, se
controla mediante la propiedad CacheSize del recordset. Lo verá más adelante.

Propiedad DefaultDatabase
Establece la base de datos predeterminada para un objeto Connection. Es un string con el
nombre de la base de datos por defecto de esa conexión. Solamente es válida con aquellos
proveedores que permiten varias bases de datos por conexión.

IsolationLevel
Esta propiedad afecta al comportamiento de un objeto Connection durante una transacción.
Una vez establecida esta propiedad, solamente será efectiva cuando se invoque el método
BeguinTrans. Vea la ayuda para mayor información de los valores posibles.

Propiedad Mode,
Establece los permisos disponibles para modificar datos en un objeto Connection.

Los valores aceptados son:

AdModeUnknown Predeterminada. Indica que los permisos no se han establecido aún o


que no se pueden determinar.
AdModeRead Indica que son permisos de sólo lectura.
AdModeWrite Indica que son permisos de sólo escritura.
AdModeReadWrite Indica que son permisos de lectura/escritura.
AdModeShareDenyRead Impide que otros abran una conexión con permisos de lectura.
AdModeShareDenyWrite Impide que otros abran una conexión con permisos de
escritura.

AdModeShareExclusive Impide que otros abran una conexión.

AdModeShareDenyNone Impide que otros abran una conexión con cualquier tipo de
permiso.

Sólo puede establecer la propiedad Mode cuando el objeto Connection está cerrado. Cuando
se usa en un objeto Connection del lado del cliente, la propiedad Mode sólo se puede
establecer a adModeUnknown.

Propiedad Provider
Es un string que indica el nombre del proveedor de un objeto Connection. Si no se especifica
ningún proveedor, la propiedad tendrá el valor predeterminado MSDASQL (Proveedor de
Microsoft OLE DB para ODBC).

Propiedad State
Devuelve el estado del objeto Connection: abierto (adStateOpen = 1) o cerrado (adStateClosed
= 0).

Propiedad Version
Devuelve el número de versión de ADO. Es un String.

Métodos del Objeto Connection

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 15


Métodos BeginTrans, CommitTrans y RollbackTrans
Estos métodos de transacción administran el proceso de la transacción dentro de un objeto
Connection de la forma siguiente:
· BeginTrans: inicia una nueva transacción.

· CommitTrans: guarda las modificaciones y termina la transacción actual. También


puede iniciar una nueva transacción.

· RollbackTrans: cancela las modificaciones efectuadas durante la transacción actual y


termina la transacción. También puede iniciar una nueva transacción.

Después de invocar el método BeginTrans, el proveedor ya no aplicará inmediatamente las


modificaciones hasta que invoque CommitTrans o RollbackTrans para terminar la
transacción. Los métodos BeginTrans, CommitTrans y RollbackTrans no están disponibles
en los objetos Connection del lado del cliente.

Método Cancel
Cancela la ejecución de una llamada asíncrona pendiente a un método Execute u Open.

Sintaxis NombreConection.Cancel

El método Cancel se utiliza para terminar la ejecución de una llamada asíncrona a un método
Execute o Open (es decir, el método fue invocado con la opción adAsyncConnect,
adAsyncExecute o adAsyncFetch). Cancel devolverá un error de ejecución si no se utilizó
adAsyncExecute en el método que quiere terminar.

Close, método
Cierra el objeto Connection.

Sintaxis NombredelObjetoConnection.Close

El cierre de un objeto Connection mientras hay objetos Recordset abiertos en la conexión


cancela las modificaciones pendientes en todos los objetos Recordset. El cierre explícito de un
objeto Connection (llamando a su método Close) mientras una transacción está en progreso
genera un error. Si un objeto Connection cae fuera del alcance mientras la transacción está en
progreso, ADO cancela automáticamente la transacción.

El cierre de un objeto Connection no lo elimina de la memoria; puede modificar los valores de


sus propiedades y volver a abrirlo más tarde. Para eliminar completamente un objeto de la
memoria, establezca la variable de objeto a Nothing.

Set NombredelObjetoConnection = Nothing

Método Execute (Vea también Método Execute para el objeto Command)


Ejecuta una consulta, instrucción SQL, procedimiento almacenado especificados o texto
específico del proveedor.

Sintaxis (Para una cadena de comando que no devuelva filas):

conexión.Execute CommandText, RecordsAffected, Options

(Para una cadena de comando que devuelva filas):

Set MiRecordset = connection.Execute (CommandText, RecordsAffected, Options)

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 16


(MiRecordset debe ser una variable declarada tipo ADODB.Recordset)

CommandText Es un String que contiene la instrucción SQL, el nombre de la tabla, el


procedimiento almacenado o el texto específico del proveedor que se va a ejecutar.
RecordsAffected Opcional. Una variable Long en la que el proveedor devuelve el número de
registros afectados por la operación.
Options Opcional. Una constante o valor Long que indica cómo debe evaluar el proveedor el
argumento CommandText. Puede ser uno de los siguientes valores.

Constante Descripción
Indica que el proveedor tiene que evaluar CommandText como
adCmdText
definición textual de un comando, como una instrucción SQL.
Indica que ADO tiene que generar una consulta SQL para devolver
adCmdTable
todas las filas de la tabla mencionada en CommandText.
Indica que el proveedor tiene que devolver todas las filas de la tabla
adCmdTableDirect
mencionada en CommandText.
Indica que ADO tiene que generar una consulta SQL para devolver
adCmdTable
todas las filas de la tabla mencionada en CommandText.
Indica que el proveedor tiene que evaluar CommandText como
adCmdStoredProc
procedimiento almacenado.
adCmdUnknown Indica que el tipo de comando en CommandText es desconocido.
adAsyncExecute Indica que el comando se tiene que ejecutar de forma asíncrona.
Indica que el resto de las filas siguientes a la cantidad inicial
adAsyncFetch especificada en la propiedad CacheSize tiene que ser recuperada
de forma asíncrona.

Cuando esta operación termina se genera el evento ExecuteComplete.

Método Open (IMPORTANTE)


Abre una conexión a un origen de datos.

Sintaxis MiConnection.Open ConnectionSTring, UserID, Password, Options

MiConnection.Open

Los parámetros ConnectionSTring, UserID, Password, Options puede introducirlos previamente


a abrir la conexión, y utilizar la segunda sintaxis cuando desee abrirla realmente. Estos
parámetros se le pasan en la cadena de conexión:

ConexBDPrensa.ConnectionString = "Provider=MSDAORA.1;User ID=INTRANET;” & _


“Password=INTRANET;Data Source=intranet;Persist Security Info=False"

Options Opcional. Puede ser una de las constantes siguientes:

AdConnectUnspecified Abre la conexión de forma sincronía


AdAsyncConnect Abre la conexión de forma asíncrona

Cuando se usa un objeto Connection del lado del cliente, el método Open no establece
realmente una conexión con el servidor hasta que se abre un Recordset del objeto Connection.
Colecciones del Objeto Connection
Colección Errors
Contiene todos los objetos Error creados en respuesta a un único fallo relacionado con el
proveedor. Cada objeto Error representa un error específico del proveedor, no un error ADO.
Los errores ADO se exponen al mecanismo de control de excepciones en tiempo de ejecución.
Por ejemplo, en Microsoft Visual Basic, cuando ocurre un error específico de ADO dispara un
evento On Error y aparece en el objeto Err.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 17


Cuando otra operación ADO genera un error, se borra la colección Errors y el nuevo conjunto
de objetos Error se coloca en la colección Errors. Las operaciones ADO que no generan un
error no tienen ningún efecto sobre la colección Errors. Para borrar manualmente la colección
Errors utilice el método Clear.

Cada objeto Error de la colección, nos dará información sobre un error producido en la
conexión. Sus propiedades son las siguientes:
· Description: Contiene la descripción del error producido (String).
· NativeError: Indica el error devuelto por la base de datos (Long).
· Number: Es el código de error (Long).
· Source: Indica el nombre del objeto o aplicación que ha generado el error (String).
· SQLState: Indica el error SQL estándar asociado.(String).
Debido a que este objeto será de gran utilidad a continuación se incluye un ejemplo de su uso.
Ejemplo del tratamiento de errores:
El resultado de la ejecución es el siguiente:
Private Sub CBConexion_Click()
Dim MiConex1 As ADODB.Connection
Dim MiError As ADODB.Error
On Error GoTo RutErr
Set MiConex1 = New ADODB.Connection
MiConex1.ConnectionString = "Provider=MSDAORA.1;Password=tiger;User
ID=EScot;Data Source=MADRID;Persist Security Info=True"
MiConex1.Open
Exit Sub
RutErr:
For Each MiError In MiConex1.Errors
MsgBox ("Error VB:" & MiError.Number & vbCrLf _
& "Error Oracle:" & MiError.NativeError & vbCrLf _
& "Error SQL:" & MiError.SQLState & vbCrLf _
& "Generado Por:" & MiError.Source & vbCrLf _
& "Descripción:" & MiError.Description)
Next
End Sub

Como puede observarse, algunas de las propiedades no devuelven los valores esperados:
NativeError vale 0 cuando debería valer –1017, que es el error asociado de Oracle. Aún así
podemos capturar el código del error desde la cadena de caracteres description. Con este
comentario se pretende sugerir que se realicen pruebas con el proveedor de datos que
vayamos a utilizar para conocer su comportamiento respecto a este objeto error y dónde nos
devuelve los códigos.

Observese en el código que la declaración de MiError se hace con ADODB.Error

Colección Properties
Es el conjunto de objetos Property

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 18


Objeto Property
Un objeto Property representa una característica dinámica de un objeto ADO que está definida
por el proveedor.

Los objetos ADO tienen dos tipos de propiedades: intrínsecas y dinámicas.


Las propiedades intrínsecas son aquellas propiedades implementadas en ADO e
inmediatamente disponibles para cualquier nuevo objeto, utilizando la sintaxis
Objeto.Propiedad. No aparecen como objetos Property en la colección Properties de un
objeto, de forma que aunque puede modificar sus valores, no puede modificar sus
características.

Las propiedades dinámicas están definidas por el proveedor de los datos y aparecen en la
colección Properties del objeto ADO apropiado. Por ejemplo, una propiedad específica del
proveedor puede indicar si un objeto Recordset acepta transacciones o actualizaciones. Estas
propiedades adicionales aparecerán como objetos Property en la colección Propiedades de
dicho objeto Recordset. A las propiedades dinámicas se les puede hacer referencia sólo a
través de la colección, utilizando la sintaxis Objeto.Properties(0) u Objeto.Properties("Name").

Un objeto Property dinámico tiene cuatro propiedades incorporadas propias:


· La propiedad Name es una cadena que identifica la propiedad.
· La propiedad Type es un entero que especifica el tipo de datos de la propiedad.
· La propiedad Value es un variant que contiene el valor de la propiedad.
· La propiedad Attributes es un valor Long que indica características de la propiedad
específicas del proveedor.

El Objeto Recordset de ADO


El objeto Recordset representa un conjunto de registros. El recordset en ADO puede crearse
abriéndolo, tomando todos los registros de una tabla o seleccionándolos con una consulta SQL,
o ejecutando un comando que contienen el nombre de esa tabla o la consulta. En un momento
determinado, el objeto Recordset sólo hace referencia a un único registro dentro del conjunto
de registros, llamado registro actual.

Propiedades del Objeto Recordset


El recordset de ADO tiene propiedades iguales al recordset de DAO, pero tienen otras que no
tienen el de DAO. Se van a estudiar todas, profundizando más en las que son particulares del
recordset ADO.
Propiedad AbsolutePosition (ADO)
Especifica la posición ordinal del registro actual de un objeto Recordset. Esta propiedad
devuelve un Long con el número de orden del registro. Es posible que el recordset no acepte
esta propiedad, dependiendo del proveedor de datos, y del tipo de cursor (lado cliente o lado
servidor. El cursor tipo lado servidor no permite esta propiedad) Esta propiedad devolverá 1
cuando el registro actual sea el primer registro del recordset.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 19


Propiedades BOF y EOF
Indican si la posición del puntero del Recordset está apuntando a un registro anterior al primero
(BOF = True) o posterior al último (EOF = True). Esta propiedad siempre la podremos mirar,
independientemente si el cursor es lado cliente o lado servidor.

Propiedad ActiveConnection (ADO)


Indica a qué objeto Connection pertenece actualmente el objeto Recordset especificado.
Devuelve un string con el nombre del objeto Connection.

Propiedad Bookmark
Devuelve un marcador que identifica unívocamente al registro actual de un objeto Recordset o
establece el registro actual de un objeto Recordset al registro identificado por un marcador
válido. El valor del Bookmark hay que introducirlo en una variable tipo Variant.

La propiedad Bookmark solo podrá establecerse cuando el proveedor lo permita. Puede


utilizarse el método Supports para averiguarlo. Cuando el recordset es de lado cliente,
siempre está disponible el Bookmark.

Propiedad CacheSize
Indica el número de registros del objeto Recordset que están en la memoria caché local. Es un
Long de lectura y escritura. El valor predeterminado es 1.

Esta propiedad nos permite conocer cuantos registros están en la memoria local. Si ponemos
esta propiedad por ejemplo a 10, al abrir la primera vez el objeto Recordset, el proveedor
recupera los 10 primeros registros en la memoria local. A medida que se desplaza por el objeto
Recordset, el proveedor devuelve los datos desde el búfer de memoria local. Tan pronto como
pasa del último registro de la memoria caché, el proveedor recupera los 10 registros siguientes
desde el origen de datos y los carga en la memoria caché.
Los registros recuperados desde la memoria caché no reflejan los cambios concurrentes que
hagan otros usuarios en el origen de datos. Para forzar una actualización de todos los datos en
la memoria caché, debe usarse el método Resync.

Propiedad MaxRecords
Indica el número máximo de registros que se devuelven a un Recordset desde una consulta. Es
un Long y el valor predeterminado es 0, que significa sin límite (Obtienen todos los registros).
Esta propiedad es de lectura y escritura cuando el recordset está cerrado, y solamente de
lectura cuando está abierto.

Esta propiedad debe usarse solamente cuando se prevé que se pueden obtener un número
muy grande de registros. Es prudente tomar medidas frente a aquellas operaciones en las que
el ordenador pueda meterse en un proceso excesivamente largo o que ocupe más recursos de
los disponibles. Estas cosas son las que suelen “colgar” al ordenador y en las que es muy
frecuente echarle luego la culpa a Windows Si estamos frente a una base de datos con todos
los datos de los afiliados a la Seguridad Social, no es del todo prudente crear un recordset
mediante esta sentencia:

SELECT * From Afiliados Where Apellido1 = ‘Fernandez’

Incluso las hay peores:

SELECT * From Afiliados

A nadie se le ocurriría, pero puede surgir involuntariamente cuando ese acceso se realiza desde
un puesto de operación público (Acceso desde Internet por ejemplo). Con la propiedad
MaxRecords puede limitar el número de registros obtenidos. Posiblemente no llegue a obtener

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 20


el dato deseado, y se vea en la obligación de realizar la misma consulta sucesivas veces hasta
encontrarlo.

Propiedad CursorLocation
Establece o devuelve la posición de un servicio de cursores. Es idéntica a la propiedad del
mismo nombre vista más atrás con todo detalle para el objeto Connection.

Propiedad CursorType
Indica el tipo de cursor que se usa en un objeto Recordset. Es de lectura y escritura si el
recordset está cerrado, y solo de lectura si está abierto. Puede tomar uno de los siguientes
valores:

AdOpenForwardOnly Predeterminado. Idéntico a un cursor estático, excepto sólo


permite desplazarse hacia delante en los registros. Esto mejora el rendimiento en
situaciones en las que sólo se quiere pasar una vez por cada registro.

En muchas ocasiones es necesario moverse por el recordset hacia delante y hacia


atrás. Este tipo de cursor solamente permite moverse hacia delante. Tenga presente
que este es el tipo predeterminado.

AdOpenKeyset Cursor de conjunto de claves. Igual que un cursor dinámico, excepto


que no se pueden ver los registros que agregan otros usuarios, aunque los registros
que otros usuarios eliminan son inaccesibles desde su conjunto de registros. Los
cambios que otros usuarios hacen en los datos permanecen visibles.

AdOpenDynamic Cursor dinámico. Las incorporaciones, cambios y eliminaciones


que hacen otros usuarios permanecen visibles, y se admiten todo tipo de movimientos
entre registros, a excepción de los marcadores si el proveedor no los admite. Es el
equivalente en DAO al tipo Dynaset

AdOpenStatic Cursor estático. Una copia estática de un conjunto de registros que se


puede usar para buscar datos o generar informes. Las incorporaciones, cambios o
eliminaciones que hacen otros usuarios no son visibles. Es el equivalente en DAO al
tipo Snapshot

NOTA. Si un proveedor no admite el tipo de cursor solicitado, el proveedor puede que devuelva
otro tipo de cursor. La propiedad CursorType cambiará para coincidir con el tipo de cursor en
uso cuando el objeto Recordset se abra. Para comprobar la funcionalidad específica del cursor
devuelto, use el método Supports. Cuando cierre el Recordset, la propiedad CursorType
volverá a su configuración original.

Propiedad LockType
Indica el tipo de bloqueo que se pone en los registros durante el proceso de edición. Establece
también si el recordset se actualiza registro a registro o por lotes. Este último sistema permite
realizar varios cambios en el recordset y mantenerlos en la caché durante cierto tiempo, y
proceder a la actualización de todos los cambios pendientes en una sola operación. Esto es
muy importante cuando se está trabajando con una base de datos situada en un servidor con
un acceso lento (conexión vía Internet, por ejemplo)

Los valores de la propiedad LockType pueden ser:

AdLockReadOnly Predeterminado. Sólo lectura—no puede modificar los datos


AdLockPessimistic Bloqueo pesimista, registro a registro: el proveedor hace lo necesario
para asegurar la modificación correcta de los registros, generalmente
bloqueando registros en el origen de datos durante todo el proceso de

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 21


modificación. Este valor solamente es válido si el cursor (Propiedad
CursorLocation) esta establecido a lado servidor.
AdLockOptimistic Bloqueo optimista, registro a registro: el proveedor usa bloqueo
optimista, bloqueando registros sólo cuando llama al método Update.
AdLockBatchOptimistic Actualizaciones optimistas por lotes: requerido para el modo de
actualización por lotes como contraposición al modo de
actualización inmediata.

Propiedad EditMode
Indica el estado de modificación del registro actual. Es solamente de lectura. Devuelve uno de
las siguientes constantes:

AdEditNone Indica que no hay ninguna operación de modificación en ejecución.


AdEditInProgress Indica que los datos del registro actual se han modificado pero que no
se han guardado.
AdEditAdd Indica que se ha invocado el método AddNew y que el registro situado
actualmente en el búfer de copia es un nuevo registro que no se ha
guardado en la base de datos.
AdEditDelete Indica que el registro actual se ha eliminado.

Propiedad Filter

Esta propiedad solamente la tienen los recordset ADO. Y es que ADO presupone que está
obteniendo datos de una base de datos alojada en un servidor y que la comunicación entre
servidor y cliente puede ser especialmente lenta. Mediante Filter puede descartar registros que
no cumplan una determinada condición. En realidad lo que hacemos mediante Filter es crear un
nuevo Recordset a partir de otro Recordset.

La propiedad Filter se utiliza también para actuar sobre determinados registros en varios
métodos del recordset (Resync, Save, …) pero no se va a explicar en este manual la
explicación de la utilización de esta propiedad en esos métodos, ya que el nivel del programador
que utiliza esos recursos debe ser elevado. Le reservamos por tanto la posibilidad de conocerlo
directamente desde la ayuda de Visual Basic, que en este caso es bastante buena.

De momento lo que vamos a hacer con Filter es crear un nuevo recordset ¿Por qué no creamos
directamente el nuevo recordset utilizando una sentencia SQL que lleve implícito ese filtro?
Personalmente no me gusta utilizar la propiedad Filter, y prefiero crear un nuevo recordset.
Creo que solamente lo he usado para rellenar un MSHFlexGrid con parte de los datos del
recordset que uso en una parte de la aplicación. Veamos un ejemplo:

(MiConexion es una conexión ya creada)


Dim RsInicial As ADODB.Recordset
Dim RsFiltrado As ADODB.Recordset
Set RsInicial = New ADODB.Recordset
Set RsFiltrado = New ADODB.Recordset
RsInicial.Open "Autores", MiConexion, adOpenDynamic, adLockOptimistic

‘Este es el recordset que uso para muchas cosas dentro de la aplicación. Ahora quiero
presentar en un MSHFlexGrid solamente los datos de los autores de nacionalidad española.
Filtro el recordset anterior utilizando un criterio de igualdad de un campo: Nacionalidad

RsFiltrado = RsInicial.Filter (“Nacionalidad = ‘Española’”)

‘Ahora ya podemos aplicar este recordset al MSHFlexGrid:

Set MSHFlexG1.Recordset = RsFiltrado

‘Y cuando queremos presentar todos los autores, basta con poner la línea:

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 22


Set MSHFlexG1.Recordset = RsInicial

Este es el único ejemplo que puedo sacar de todas mis aplicaciones. Seguro que el alumno va
a ver más aplicaciones de esta propiedad.

La propiedad Filter puede mostrar también aquellos registros que han sido manipulados
recientemente, mediante las constantes siguientes:

AdFilterNone Quita el filtro actual y vuelve a poner todos los registros a la


vista.
AdFilterPendingRecords Permite ver sólo los registros que han cambiado, pero que no
han sido enviados aún al servidor. Aplicable sólo para el modo
de actualización por lotes.
AdFilterAffectedRecords Permite ver sólo los registros afectados por la última llamada a
Delete, Resync, UpdateBatch o CancelBatch
AdFilterFetchedRecords Permite ver los registros de la caché actual, es decir, los
resultados de la última llamada para recuperar registros de la
base de datos
AdFilterConflictingRecords Permite ver los registros que fallaron en el último intento de
actualización por lotes.

Propiedad Index
Indica el nombre del índice que se utiliza actualmente en el Recordset. Es un String con el
nombre del índice.

El índice se utiliza para moverse a lo largo del recordset mediante el método Move. El índice ya
debe estar creado en la tabla de la base de datos.

Al utilizar un índice, el orden de los registros se cambia al orden establecido en ese índice. Por
lo tanto, los valores obtenidos anteriormente por la propiedad AbsolutePosition cambiarán
completamente.
No todos los proveedores de datos aceptan la propiedad Index. Puede comprobarlo mediante el
método Supports.

Propiedad MarshalOptions
Esta propiedad se usa cuando estamos trabajando con cursores lado cliente. En este caso,
como vimos más atrás, los registros del recordset están en el equipo cliente. Todas las
operaciones realizadas sobre el recordset se realizan en el cliente, por lo tanto llegará el
momento en que habrá que actualizar en el servidor los datos que hayamos modificado en el
recordset que está en el equipo cliente. Mediante esta propiedad podemos hacer que se envíen
al servidor todos los registros (filas) o solamente los que han cambiado. Acepta estas dos
constantes:

AdMarshalAll Predeterminada. Indica que todos los registros se devuelven al


servidor.
AdMarshalModifiedOnly Indica que sólo los registros modificados se devuelven al
servidor.

Esta propiedad puede mejorar el rendimiento de la aplicación para aquellos casos en los que se
use un canal de comunicación lento.

Propiedad PageSize
Indica cuántos registros constituyen una página del objeto Recordset. Es de lectura y escritura.
Devuelve un Long y su valor predeterminado es 10.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 23


Esta propiedad permite determinar cuántos registros componen una página lógica de datos. Al
establecer un tamaño de página, puede utilizar la propiedad AbsolutePage y se moverá al
primer registro de una página específica. Esto es útil en las situaciones de servidor Web cuando
se desea permitir que el usuario pase páginas de datos y vea cierto número de registros al
mismo tiempo. Esta propiedad se puede establecer en cualquier momento y su valor se utilizará
para calcular la ubicación del primer registro de una página específica.

Propiedad PageCount
Indica cuántas páginas de datos contiene el objeto Recordset. Es solamente de lectura.
Devuelve un Long. Si el objeto Recordset no admite esta propiedad, el valor será -1 para
indicar que no se puede determinar el valor de PageCount.

Propiedad AbsolutePage
Especifica en qué página reside el registro actual. Es de lectura y escritura. Devuelve un Long o
una de las siguientes constantes:

AdPosUnknown El objeto Recordset está vacío, la posición actual se desconoce o el


proveedor no admite la propiedad AbsolutePage.

AdPosBOF El puntero del registro actual está al comienzo del archivo (es decir, la
propiedad BOF tiene el valor True).

AdPosEOF El puntero del registro actual está al final del archivo (es decir, la
propiedad EOF tiene el valor True).

Propiedad RecordCount
Indica el número actual de registros de un objeto Recordset. Devuelve un Long
Es posible que esta propiedad no la permita el proveedor de datos, o que no pueda llegar a
averiguarse, ya que dependiendo del tipo de cursor utilizado puede que no suministre ese dato.

Propiedad Source
Devuelve la tabla, consulta o sentencia SQL utilizado en el método Open para crear el
recordset. Es un String.

Propiedad State
Indica el estado (abierto, cerrado, proceso de ejecución) en el que se encuentra el recordset.
Devuelve uno de los siguientes valores:

Constante Descripción
Valor predeterminado. Indica que el objeto está
adStateClosed
cerrado.
adStateOpen Indica que el objeto está abierto.
Indica que el objeto Recordset se está
adStateConnecting
conectando.
Indica que el objeto Recordset está ejecutando un
adStateExecuting
comando.
Indica que se está obteniendo el conjunto de filas
adStateFetching
del objeto Recordset.
Puede tener una combinación de valores. Por ejemplo, si se está ejecutando una instrucción,
esta propiedad tendrá un valor combinado de adStateOpen y adStateExecuting.

Propiedad Status
Esta propiedad se refiere al registro actual. Indica el estado de este registro respecto a las
operaciones de actualización por lotes u otras operaciones masivas. No es una propiedad que
se use todos los días. Vea la ayuda para mas detalles.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 24


Propiedades dinámicas del objeto recordset
Las propiedades anteriores se refieren a propiedades del recordset que se refieren a unas
características propias del recordset una vez creado. Son estas:

Unique Table, Unique Schema y Unique Catalog

Unique Table especifica la tabla sobre la que se permite realizar modificaciones de datos
(Insertar o actualizar), en el caso de que el recordset se haya creado mediante una operación
JOIN

Unique Schema indica el nombre del propietario de la tabla


Unique Catalog indica el nombre de la base de datos a la que pertenece la tabla. Estas dos
últimas propiedades deben tener un valor para poder poner valor a la propiedad Unique Table.
Estas propiedades son tipo String

Estas propiedades dinámicas se anexan a la colección Properties del objeto Recordset al


asignar el valor adUseClient a la propiedad Cursor Location.

Métodos del objeto Recordset de ADO


METODO Supports
Este método es muy útil para ver si un recordset acepta una determinada funcionalidad.
Devuelve un Booleano y es solamente de lectura. De esta forma puede consultar si un
recordset admite el método MoveFirst, la propiedad AbsolutePosition, Bookmark, etc., antes de
invocar ese método o leer esa propiedad, y evitar de esta forma un error en la ejecución. Esto
es muy útil habida cuenta que no todos los proveedores funcionan de la misma forma. Es por lo
tanto muy prudente consultar si el Recordset soporta una funcionalidad antes de pedírsela.

Estas funcionalidades se le pasan como parámetro mediante una de las siguientes constantes:

AdAddNew Puede usar el método AddNew para agregar nuevos registros.


AdApproxPosition Puede leer y establecer las propiedades AbsolutePosition y
AbsolutePage.
AdBookmark Puede usar la propiedad Bookmark para tener acceso a registros
específicos
AdDelete Puede usar el método Delete para eliminar registros.
AdHoldRecords Puede recuperar más registros o cambiar la posición de recuperación
siguiente sin efectuar todos los cambios pendientes.
AdMovePrevious Puede usar los métodos MoveFirst y MovePrevious, y los métodos
Move o GetRows para desplazar hacia atrás la posición del registro
actual sin que se requiera marcadores.
AdResync Puede usar el método Resync para actualizar el cursor con los datos
visibles en la base de datos subyacente.
AdUpdate Puede usar el método Update para modificar datos existentes.
AdUpdateBatch Puede usar actualización por lotes (métodos UpdateBatch y
CancelBatch) para transmitir grupos de cambios al proveedor.
AdIndex Puede utilizar la propiedad Index para dar nombre a un índice.
AdSeek Puede utilizar el método Seek para encontrar una fila en un Recordset.

En este ejemplo vemos la sintaxis de Supports:

If RsSeg.Supports(adApproxPosition) = True Then


MsgBox "SI"
Else
MsgBox "NO"
End If

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 25


Nota Aunque el método Supports puede devolver True para una funcionalidad determinada,
eso no garantiza que el proveedor pueda hacer que la característica esté disponible bajo
cualquier circunstancia. El método Supports devuelve simplemente si el proveedor puede
admitir la funcionalidad especificada, dando por supuesto que se reúnen determinadas
condiciones. Por ejemplo, el método Supports puede indicar que un objeto Recordset admite
actualizaciones aunque el cursor se base en una unión de múltiples tablas, de las que algunas
columnas no son actualizables.

El valor devuelto por el método Supports dependerá del tipo de recordset elegido. En la
siguiente tabla puede ver el tipo de recordset y las constantes para las que va a devolver True:

AdOpenForwardOnly Ninguna
AdOpenKeyset adBookmark, adHoldRecords, adMovePrevious, adResync
AdOpenDynamic AdMovePrevious
AdOpenStatic adBookmark, adHoldRecords, adMovePrevious, adResync

Método Open
Es el método que ABRE el recordset. Este método es el que busca los registros que han de
rellenar el recordset.

Sintaxis. Esta es la sintaxis general:

MiRecordset.Open Source, ActiveConnection, CursorType, LockType, Options

Un recordset puede abrirse partiendo de una conexión ya abierta. Pero también puede crearse
directamente, sin abrir previamente la conexión. Al final, deberá aportar todos los datos
necesarios para determinar en que base de datos se abre ese recordset. Sobre que tabla,
consulta o sentencia SQL., que tipo de cursor va a ser, etc. Lo que ocurre es que ADO es muy
flexible y nos permite hacerlo de varias formas, aunque todas ellas conducen a lo mismo.

Source (Opcional) Es el nombre de una tabla, consulta o sentencia SQL de la cual se obtienen
los registros del Recordset.

ActiveConnection (Opcional). Es el nombre de un objeto Connection abierto o una cadena de


conexión válida. Esta cadena es la misma que la que emplearíamos para abrir el objeto
Connection.

CursorType (Opcional). Un valor que determina el tipo de cursor que el proveedor debe usar al
abrir el Recordset. Puede ser una de las siguientes constantes

AdOpenForwardOnly (Predeterminado) Abre un cursor de tipo sólo avance.


AdOpenKeyset Abre un cursor de tipo conjunto de claves.
AdOpenDynamic Abre un cursor de tipo dinámico. (Igual que el Dynaset de
DAO)
AdOpenStatic Abre un cursor de tipo estático.

LockType (Opcional). Un valor que determina el tipo de bloqueo que debe usar el proveedor al
abrir el Recordset. Con este parámetro se le indica también si debe hacer las actualizaciones
registro a registro o en bloque. Puede ser una de las siguientes constantes

AdLockReadOnly (Predeterminado) Sólo lectura. No puede modificar los datos.


AdLockPessimistic Bloqueo pesimista, registro a registro. El proveedor hace lo
necesario para asegurar una modificación correcta de los
registros, normalmente bloqueando registros en el origen de
datos inmediatamente antes de la modificación.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 26


AdLockOptimistic Bloqueo optimista, registro a registro. El proveedor usa
bloqueooptimista, bloqueando registros sólo cuando se llama al
método Update.
AdLockBatchOptimistic Actualizaciones optimistas por lotes. Requeridas en el
modo de actualización por lotes en oposición al modo
de actualización inmediata. (Actualización en bloque)
Options (Opcional). Constante que determina como va a evaluar el proveedor de datos el
argumento Source. Puede ser una de las siguientes constantes de esta lista.

AdCmdText Indica que el proveedor debe evaluar Source como una definición
textual de un comando.
AdCmdTable Indica que ADO debe generar una consulta SQL para devolver
todaslas filas de la tabla nombrada en Source.
AdCmdTableDirect Indica que el proveedor debe devolver todas las filas de la
tabla nombrada en Source.
AdCmdStoredProc Indica que el proveedor debe evaluar Source como un
procedimiento almacenado
AdCmdUnknown Indica que el tipo de comando del argumento Source es
desconocido.
AdCmdFile Indica que el Recordset guardado se debe restaurar desde el
archivo nombrado en Source.
AdAsyncExecute Indica que Source se debe ejecutar de forma asíncrona.
AdAsyncFetch Indica que, tras alcanzar la cantidad inicial especificada en la
propiedad Initial Fetch Size, las filas restantes deben
buscarse de forma asíncrona. Si se requiere una fila que no se
ha encontrado, se bloqueará el subproceso principal hasta que
se disponga de la fila solicitada.
AdAsyncFetchNonBlocking Indica que el subproceso principal nunca se bloquea
durante la búsqueda. Si no se encuentra la fila
solicitada, la fila actual se desplaza automáticamente
al final del archivo.

Habrá observado que hemos remarcado que el método Open ABRE un recordset. No lo crea. El
recordset debe estar creado previamente. ¿Qué cuando se crea? Mediante la instrucción:
Set MiRecordset = New ADODB.Recordset

Metodo Requery
Actualiza los datos de un objeto Recordset volviendo a ejecutar la consulta utilizada para abrirlo.
Se obtiene el mismo resultado que si se cerrara el recordset y se volviera a abrir.

Sintaxis MiRecordset.Requery Opciones

Optiones Opcional. Máscara de bits que indica opciones que afectan a esta operación. Si el
valor de este parámetro está establecido a adAsyncExecute, esta operación se ejecutará de
forma asíncrona y se emitirá un evento RecordsetChangeComplete cuando concluya.

Método Resync
Actualiza los datos del objeto Recordset actual. Este método, a diferencia del método Requery,
no vuelve a ejecutar el comando de creación del recordset, sino que lee los registros existentes
en el recordset para actualizar su valor, pero no presenta aquellos registros que hubieran sido
creados con posterioridad a la apertura del recordset. Es más rápido que el método Requery, y
en muchos casos solamente nos interesa actualizar los registros sobre los que estamos
trabajando.

Sintaxis MiRecordset.Resync AffectRecords, ResyncValues

Los parámetros AffectRecords y ResyncValues determinan que registros se van a volver a


leer y sobreescribir. Vea la ayuda para mas detalles.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 27


METODO AddNew
Crea un nuevo registro en un objeto Recordset actualizable.

Sintaxis NombreDelRecordset.AddNew FieldList, Values

Los parámetros FieldList y Values son opcionales. En caso de ponerlos, FieldList serán los
nombres de los campos a los que se les va a poner un valor, y Values son los valores de cada
uno de estos campos. El orden nombre - valor debe mantenerse estrictamente.

Siempre recomendaré que, en vez de meter los datos mediante estos parámetros, se metan
posteriormente linera a línea, tal como se hizo siempre con los recordsets

NombreDelRecordset!NombredelCampo = ValorDelCampo
ó
NombreDelRecordset(“NombredelCampo”) = ValorDelCampo

Esta segunda forma es necesaria cuando el nombre del campo tiene espacios. Nunca es
recomendable poner espacios en los nombres de campos, pero en caso de que existan, debe
optar por utilizar la sintaxis segunda, con los paréntesis y comillas dobles.

No siempre se puede utilizar el método AddNew. Puede comprobar si se puede utilizar, usando
el método Supports visto anteriormente.

El método AddNew convierte a este registro recién creado en registro actual. Pero este registro
solamente existe en el recordset. Para introducir los datos en la base de datos, (Y por lo tanto
en el disco duro) es necesario invocar el método Update una vez introducidos todos los valores
de los campos que deseamos introducir. Con algún tipo de cursor es necesario también utilizar
el método Requery para poder acceder al registro recién creado.

Si se invoca el método AddNew mientras se está editando el registro actual, o durante otra
operación AddNew, ADO invoca automáticamente el método Update para guardar los
cambios. Vea más adelante los métodos Update y UpdateBatch.

Método Update
Guarda los cambios realizados en el registro actual de un objeto Recordset. Se utiliza tanto para
“rematar” una operación de creación de un registro iniciada con AddNew, como para guardar
los nuevos datos del registro actual (Recuerde que en ADO no existe el método Edit, tal como
ocurría en DAO)
.
Sintaxis NombreDelRecordset.Update Fields, Values

En esta sintaxis, Fields y Values son opcionales, y solamente tienen aplicación cuando se trata
de cambiar los valores del registro actual, no de terminar una operación de creación de un
nuevo registro mediante AddNew.

Vuelvo a recomendar lo anterior. Para cambiar los valores de varios campos de un registro, nos
colocaremos sobre ese registro, y sin invocar ningún método, ejecutaremos este código

MiRecordset!Campo1 = Valor1
MiRecordset!Campo2 = Valor2
……….
MiRecordset!CampoN = ValorN
MiRecordset.Update

Pero en ADO pasa una cosa que no pasaba en DAO. Si cambiamos de registro una vez
modificado el valor de un registro, ADO invoca automáticamente el método Update. Por lo
tanto, el código siguiente:

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 28


MiRecordset!Campo1 = Valor1
MiRecordset!Campo2 = Valor2
……….
MiRecordset!CampoN = ValorN

Tendrá el mismo resultado que el anterior cuando cambiemos de registro actual. Esto puede
ser bueno a malo, pero personalmente pienso que no es práctico porque implica tener mucho
más cuidado que en DAO. Hace lo mismo que cuando tenemos unos controles enlazados a
datos mediante un control Data.

Si una vez que ejecutamos una línea tal como esta

MiRecordset!Campo1 = Valor1

Queremos que ese nuevo valor no entre en la base de datos, debemos cancelarlo mediante el
método CancelUpdate.

Método UpdateBatch
Escribe en disco todas las actualizaciones pendientes de proceso por lotes. En ADO un
recordset puede actualizarse registro a registro o por lotes. Todo dependerá de cómo se ha
abierto (Si el valor LockType se ha puesto a AdLockBatchOptimistic)

Sintaxis MiRecordset.UpdateBatch AffectRecords

AffectRecords Constante que determina a cuántos registros afectará el método


UpdateBatch. Puede tomar uno de los siguientes valores.

AdAffectCurrent Escribe solamente los cambios pendientes en el


registro actual.
AdAffectGroup Escribe los cambios pendientes que cumplen el valor
de la propiedad Filter.
AdAffectAll (Predeterminado) Escribe los cambios pendientes en
todos los registros del objeto Recordset.

Método Cancel
Cancela la ejecución del método Open.

Sintaxis NombreDelRecordset.Cancel

El método Cancel solamente puede usarse si el método Open fue invocado con la opción
adAsyncConnect, adAsyncExecute o adAsyncFetch.

Método Delete
Elimina el registro actual o un grupo de registros. Por defecto elimina solamente el registro
actual. Vea la ayuda para ampliar los detalles respecto al parámetro opcional AffectRecords

Sintaxis MiRecordset.Delete AffectRecords

Método CancelUpdate
Habíamos visto más atrás que el ADO no existe el método Edit. Para modificar un registro
basta con poner una instrucción tal como esta:

MiRecordset!MiCampo = MiNuevoValor

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 29


Y a continuación rematar la operación mediante el método Update

MiRecordset.Update

Si por cualquier circunstancia se ha ejecutado la primera instrucción, y luego queremos


volvernos atrás, antes de ejecutar el método Update debemos deshacer el cambio con el
método CancelUpdate, con lo que el registro afectado recuperará nuevamente su valor original.

Sintaxis MiRecordset.CancelUpdate

Recuerde que ADO funciona de forma distinta a DAO con estos métodos de modificación de los
registros. Recuerde que si está en proceso de modificación de un registro (Ha ejecutado la
primera línea del ejemplo anterior) y cambia de registro, por el hecho de cambiar de registro,
ADO invoca automáticamente el método Update.

Método CancelBatch
Cancela una actualización por lotes pendiente. Es similar a la anterior, pero para actualización
por lotes.

Sintaxis MiRecordset.CancelBatch AffectRecords

Método Clone
Crea un objeto Recordset duplicado a partir de un objeto Recordset existente. Opcionalmente,
puede especificarse que el nuevo recordset sea solamente de lectura

Sintaxis Set rstDuplicate = rstOriginal.Clone (LockType)

(El objeto rstDuplicate debe estar declarado previamente como objeto ADODB.Recordset)

LockType puede tomar uno de los siguientes valores:

AdLockUnspecified (Predeterminado) El recordset resultante tendrá el mismo tipo de


bloqueo que el original.
AdLockReadOnly El recordset creado es solamente de lectura.

El recordset resultante del método Clone, aunque igual al original en el momento de su


creación, es completamente independiente de este a partir de ese momento, por lo que las
actualizaciones efectuadas en el original no afectan al clonado.

Método Move
Mueve la posición del registro actual de un objeto Recordset
.
Sintaxis MiRrecordset.Move NumRecords, Start

NumRecords Un valor Long con signo que especifica el número de registros que debe
moverse a partir de la posición del registro actual o del registro especificado en el parámetro
Start, si es que se especifica.

Start Opcional. Un String o Variant cuyo resultado sea un marcador del tipo Bookmark. Puede
utilizar también una de las siguientes constantes:

AdBookmarkCurrent (Predeterminado) Cuenta a partir del registro actual


AdBookmarkFirst Cuenta a partir del primer registro
AdBookmarkLast Cuenta a partir del último registro

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 30


Métodos MoveFirst, MoveLast, MoveNext y MovePrevious
Pasa al primer, último, siguiente o anterior registro de un objeto Recordset especificado y lo
convierte en el registro actual. Funciona igual que en DAO

Tenga en cuenta a la hora de usar los métodos Move que pueden existir Recordsets que no
permiten el movimiento hacia atrás.
Método Find
Busca el primer registro del recordset que satisfaga los criterios especificados en el criterio de
búsqueda. Si se cumple el criterio de búsqueda, la posición del recordset se establece en el
primer registro encontrado; si no, la posición se establece al final del recordset.

Sintaxis MiRecordset.Find (criterio, SkipRows, searchDirection, start)

criterio Es el criterio de búsqueda. Por ejemplo “Pais = España” siendo Pais el


nombre del campo en el cual buscamos el valor España

SkipRows (Opciopnal) Es un Long, cuyo valor predeterminado es cero, que especifica el


número de registros a partir del registro actual donde debe empezar la búsqueda.

searchDirection (Opcional) Un valor que especifica si la búsqueda se realiza en dirección al


final del recordset (adSearchForward) o en dirección hacia el principio del recordset
(adSearchBackward). La búsqueda termina al final o al principio del recordset, dependiendo
del valor de searchDirection.

start (Opcional) Un marcador tipo BookMark que se utiliza como posición inicial de
la búsqueda.

El operador de comparación de criterio puede ser ">", "<", "=", ">=" , "<=", "<>" (distinto de) o
"like" (coincidencia parcial de cadenas). El valor de comparación puede ser una cadena, un
número en coma flotante o una fecha. Los valores de cadena están delimitados con comillas
sencillas (por ejemplo, "Pais = 'España'"). Los valores de fecha están delimitados con signos "#"
y con formato mm/dd/yy (por ejemplo, "fecha_inicial > #7/22/97#"). Si el operador de
comparación es "like", el valor de la cadena puede contener los caracteres comodín "*" o "_".
(Funcionan de forma idéntica, sustituyendo a cualquier sucesión de caracteres.) No acepta el
carácter “?” (Por ejemplo, "Pais like ‘Es_’" o “Pais Like ‘Es*’ encuentra España y Estonia)

ADO no tiene los métodos FindFirst, FindNext, FindPrevious y FindLast. Deberá emplear el
método Find de forma inteligente para implementar estos otros.

Método Save
Este método permite guardar el contenido de un Recordset en un fichero. Puede ser muy útil
cuando queremos exportar ese recordset hacia otra aplicación.

Sintaxis MiRecordset.Save FileName, PersistFormat

FileName es la ruta completa del fichero en el que se guardará el Recordset.


PersistFormat (Opcional). Un valor que especifica el formato en que se guardará el
Recordset. Puede ser una de las constantes siguientes.

AdPersistADTG (Valor predeterminado) Se guarda en un formato propietario


(Advanced Data Tablegram). No es inteligible a simple vista,
pero genera ficheros bastante cortos.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 31


AAdPersistXML Se guarda en formato XML. Es un formato puramente en ASCII
donde pueden verse los nombres de los campos y su
contenido. Este formato genera ficheros más grandes que el
ADT
Si el recordset tienen aplicado un filtro (Mediante la propiedad Filter) solamente guarda los
registros que deja ver ese filtro.

Si ya existe el fichero le dará un error. Cerciórese que no existe (Mediante la función Dir) y
bórrelo antes de volver a utilizar el método Save.

Método Seek
Este método busca un registro desplazándose por el recordset a lo largo de un índice o un
conjunto de índices. La búsqueda mediante Seek es mucho más rápida que con Find, ya que la
realiza siguiendo el ordenamiento de los registros según un índice.

Para poder usar el método Index es necesario que el proveedor acepte índices en el objeto
recordset. Esto ha llevado al autor a no poder presentar ningún ejemplo de este método, ya
que todas las bases de datos ensayadas no permitían índices. Puede ver si acepta índices
mediante el método Supports:

If MiRecordset1.Supports(adIndex) = True Then

Vea la ayuda de VB para mayor información

Método NextRecordset
Para entender este método es necesario explicar previamente como se puede crear un
recordset compuesto.

Un recordset compuesto es un recordset que se crea concatenando sentencias SELECT, y


cada una de ellas creará, dentro del mismo Recordset, un recordset particular. Al crear el
recordset, el recordset particular que va a estar activo es el correspondiente a la primera
sentencia SELECT. Mediante el método NextRecordset podemos ir avanzando a través de los
siguientes recordsets particulares. El carácter de separación entre las sentencias SELECT es
el punto y coma ( ; )

MiRecordset1.Open "Select * From Regimenes; Select * From Regimen_Seguimiento Where


Rs_Origen = 'LSB'", MiConexionADO, adOpenDynamic, adLockOptimistic

(La instrucción anterior debe leerse como una sola línea)

MiRecordset es un recordset compuesto. Toma datos de dos tablas distintas, pero podría
haberlo hecho solamente de una tabla con una condición distinta en la SELECT.

Cuando se ejecuta esa línea, el recordset actual es el correspondiente a la primera selección.


(Select * From Regimenes). Ejecutando el método NextRecordset ese recordset primero se
borra y pasa a ser recordset actual el creado con la selección segunda (Select * From
Regimen_Seguimiento Where Rs_Origen = 'LSB'")

Set MiRecordset1 = MiRecordset1.NextRecordset

Puede usar también este recordset para crear un nuevo recordset a partir del primero

Set MiRecordset2 = MiRecordset1.NextRecordset

MiRecordset2 debe estar declarado como objeto recordset, y creado con la instrucción New:

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 32


Set MiRecordset2 = New ADOBD.Recodset

La colección Fields de un recordset ADO


Contiene todos los objetos Field de un objeto Recordset.

Un objeto Recordset tiene una colección Fields que contiene todos los objetos Field. Cada
objeto Field se corresponde a una columna del Recordset.

Vamos a ver aquí un truco que nos permite ADO. Podemos crear un recordset ¡Sin necesidad
de una base de datos!

Cuando estudiamos el objeto recordset vimos que el recordset se crea con una instrucción
como esta:
Set MiRecordset1 = New ADODB.Recordset

Ahora ya podemos abrir el recordset leyendo los datos desde una base de datos. Utilizamos
para ello el método Open del recordset:

MiRecordset1.Open "Select * From Regimenes", MiConexionADO, adOpenDynamic, adLockOptimistic

Mediante el método Open lo que hace el recordset es conocer su estructura (Que campos
tiene, propiedades de estos campos, etc) y el valor de cada uno de los campos de sus registros.
¿Qué pasaría si en vez de abrir el recordset le vamos añadiendo objetos Field a su colección
Fields? Lo hacemos mediante el método Append:

MiRecordset1.Fields.Append "MiCampo1", adBigInt


MiRecordset1.Fields.Append "MiCampo2", adChar, 25
MiRecordset1.Fields.Append "MiCampo3", adBSTR

Lo que ocurre es que el recordset ya tiene tres campos, el primero de nombre MiCampo1,
numérico Long, el segundo, un string de 25 caracteres de nombre MiCampo2, y el tercero, de
nombre MiCampo3, una cadena de caracteres de longitud indefinida, terminada en un carácter
nulo. Ya tenemos una estructura de un recordset sin necesidad de haber leído la base de
datos. No es necesario por lo tanto que exista una tabla o consulta almacenada con esa
estructura. Ahora podemos abrir el recordset:

MiRecordset1.Open

Lo abrimos sin pasarle ningún parámetro. Ahora ya está abierto y podemos trabajar con el
como con un recordset cualquiera. Recuerde que al principio está vacío.

MiRecordset1.AddNew
MiRecordset1!MiCampo1 = 34
MiRecordset1!MiCampo2 = "Guía del Estudiante"
MiRecordset1!MiCampo3 = "Hola mi amor" & vbCrLf & "Yo soy tu lobo"
MiRecordset1.Update

Ya tenemos un registro dentro del recordset. Podemos introducirle tantos registros como
queramos, y luego movernos por el recordset mediante los métodos Movexxxx. Ahora
podremos leer el contenido del registro actual:

Label1 = MiRecordset1!MiCampo1
Label2 = MiRecordset1!MiCampo2

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 33


Label3 = MiRecordset1!MiCampo3
El resultado del código de el ejemplo se traducirá en algo como esto:

Y ahora vienen lo mejor. ¿Para que queremos un recordset que no tienen datos leídos desde
una base de datos? Las aplicaciones de esto solamente está limitadas por la imaginación.
Pienso, por ejemplo, en introducir en un recordset todos los datos leídos de un fichero de
configuración, y así tener todos esos datos disponibles durante toda la aplicación, en vez de en
variables, como MiRecordset!MiDato1

Es una idea, pero piense que esto no regala nada. El espacio de memoria consumido será
similar a si usa variables. Pero posiblemente estará más cómodo y más inteligible su código.

Veamos los métodos de la colección Fields

Método Append
Agrega un campo a una colección Fields de un Recoprdset.

Sintaxis MiRecordset.Fields.Append Name, Type, DefinedSize, Attrib

Name Un String con el nombre del nuevo objeto Field, que tiene que ser único dentro de la
coleccón Fields.

Type Tipo de datos que va a contener ese campo. Puede tomar uno de estos valores:

Se une en una instrucción OR lógica con otro tipo para indicar que los
adArray
datos son una matriz segura de ese tipo (DBTYPE_ARRAY).
adBigInt Un entero con signo de 8 bytes (DBTYPE_I8).
adBinary Un valor binario (DBTYPE_BYTES).
adBoolean Un valor Boolean (DBTYPE_BOOL).
Se une en una instrucción OR lógica con otro tipo para indicar que los
adByRef
datos son un puntero a los datos del otro tipo (DBTYPE_BYREF).
Una cadena de caracteres terminada en nulo (Unicode)
adBSTR
(DBTYPE_BSTR).
adChar Un valor de tipo String (DBTYPE_STR).
Un valor de tipo Currency (DBTYPE_CY). Un valor Currency es un
adCurrency número de coma fija con cuatro dígitos a la derecha del signo decimal.
Se almacena en un entero con signo de 8 bytes en escala de 10.000.
Un valor de tipo Date (DBTYPE_DATE). Un valor Date se almacena
como un valor de tipo Double; la parte entera es el número de días
adDate
transcurridos desde el 30 de diciembre de 1899 y la parte fraccionaria
es la fracción de un día.
adDBDate Un valor de fecha (aaaammdd) (DBTYPE_DBDATE).
adDBTime Un valor de hora (hhmmss) (DBTYPE_DBTIME).
Una marca de fecha y hora (aaaammddhhmmss más una fracción de
adDBTimeStamp
miles de millones) (DBTYPE_DBTIMESTAMP).
Un valor numérico exacto con una precisión y una escala fijas
adDecimal
(DBTYPE_DECIMAL).
adDouble Un valor de coma flotante de doble precisión (DBTYPE_R8).
adEmpty No se ha especificado ningún valor (DBTYPE_EMPTY).
adError Un código de error de 32 bits (DBTYPE_ERROR).
adGUID Un identificador único global (GUID) (DBTYPE_GUID).

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 34


Un puntero a una interfaz Idispatch de un objeto OLE
adIDispatch
(DBTYPE_IDISPATCH).
adInteger Un entero firmado de 4 bytes (DBTYPE_I4).
Un puntero a una interfaz Iunknown de un objeto OLE
adIUnknown
(DBTYPE_IUNKNOWN).
adLongVarBinary Un valor binario largo (sólo para el objeto Parameter).
adLongVarChar Un valor largo de tipo String (sólo para el objeto Parameter).
Un valor largo de tipo String terminado en nulo (sólo para el objeto
adLongVarWChar
Parameter).
Un valor numérico exacto con una precisión y una escala exactas
adNumeric
(DBTYPE_NUMERIC).
adSingle Un valor de coma flotante de simple precisión (DBTYPE_R4).
adSmallInt Un entero con signo de 2 bytes (DBTYPE_I2).
adTinyInt Un entero con signo de 1 byte (DBTYPE_I1).
adUnsignedBigInt Un entero sin signo de 8 bytes (DBTYPE_UI8).
adUnsignedInt Un entero sin signo de 4 bytes (DBTYPE_UI4).
adUnsignedSmallInt Un entero sin signo de 2 bytes (DBTYPE_UI2).
adUnsignedTinyInt Un entero sin signo de 1 byte (DBTYPE_UI1).
adUserDefined Una variable definida por el usuario (DBTYPE_UDT).
adVarBinary Un valor binario (sólo para el objeto Parameter).
adVarChar Un valor de tipo String (sólo para el objeto Parameter).
adVariant Un tipo Variant de automatización (DBTYPE_VARIANT).
Se une en una instrucción OR lógica con otro tipo para indicar que los
datos son una estructura DBVECTOR, tal como está definida por OLE
adVector
DB, que contiene un contador de elementos y un puntero a los datos
del otro tipo (DBTYPE_VECTOR).
Una cadena de caracteres Unicode terminada en nulo (sólo para el
adVarWChar
objeto Parameter).
Una cadena de caracteres Unicode terminada en nulo
adWChar
(DBTYPE_WSTR).

DefinedSize Un Long que define el tamaño del campo si fuese necesario. (Por ejemplo para
un string)

Attrib (Opcional). Especifica los atributos del campo a añadir. Puede tomar estos
valores:

Indica que el campo se aplaza, es decir, los valores del campo no se


adFldMayDefer recuperan del origen de datos con todo el registro, sino solamente
cuando se tiene acceso explícito a los mismos.
adFldUpdatable Indica que se puede escribir en el campo.
Indica que el proveedor no puede determinar si se puede escribir en el
adFldUnknownUpdatable
campo.
adFldFixed Indica que el campo contiene datos de longitud fija.
adFldIsNullable Indica que el campo acepta valores Null.
adFldMayBeNull Indica que se pueden leer valores Null del campo.
Indica que se trata de un campo binario largo. También indica que se
adFldLong
pueden utilizar los métodos AppendChunk y GetChunk.
Indica que el campo contiene un identificador de fila persistente en el
que no se puede escribir y que no tiene ningún valor significativo
adFldRowID
excepto la identificación de la fila (como por ejemplo un número de
registro, un identificador único, etc.).
Indica que el campo contiene algún tipo de marca de hora o de fecha
adFldRowVersion
que se utiliza para efectuar actualizaciones.
Indica que el proveedor almacena los valores del campo en la memoria
adFldCacheDeferred
caché y que las lecturas siguientes se efectúan en dicha memoria .

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 35


Método Delete
Teóricamente elimina un objeto de la colección Fields.

Sintaxis Fields.Delete Field

Field Un Variant que designa el objeto Field que se va a eliminar. Este parámetro tiene
que ser el nombre del objeto Field; no puede ser una posición ordinal o el propio objeto Field.
Comentarios
La llamada al método Fields.Delete en un Recordset abierto provoca un error de ejecución.

(Como ha ocurrido en otras ocasiones, al autor le ha sido imposible ejecutar este método con
los resultados esperados)

Método Item

Sintaxis MiRecordset.Fields.Item (Index)

Devuelve el elemento de la colección Fields especificado en el índice. Devuelve el objeto, por lo


tanto, y sobre ese objeto, podemos obtener las propiedades que deseemos. En el ejemplo
siguiente, introducimos los nombres de todos los campos en un ComboBox llamado
ComboCampos

Dim MM As String, I As Integer


For I = 0 To MiRecordset1.Fields.Count - 1
MM = MiRecordset1.Fields.Item(I).Name
ComboCampos.AddItem MM
Next I

Método Refresh
Aunque la colección Fields tiene este método, la verdad es que no tienen efectos visibles sobre
esa colección.

Propiedades de la colección Fields

Propiedad Count
Devuelve el número de campos de la colección Fields. Es un Long.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 36


LSB Visual Basic Guía del Estudiante Capítulo 14 Página 37
El Objeto Command
Un objeto Command es la definición de un comando específico que se piensa ejecutar contra
un origen de datos. Mediante un objeto Command podemos crear un recordset, pero recuerde
que un recordset lo podemos también crear directamente.

Utilice un objeto Command para consultar una base de datos y obtener registros en un objeto
Recordset, para añadir o eliminar registros, ejecutar una operación de manejo masivo de datos
o para manipular la estructura de una base de datos.

Propiedades del Objeto Command

Propiedad ActiveConnection
Indica a qué objeto Connection pertenece actualmente el objeto Command. Es un string con el
nombre de la conexión.

Propiedad CommandText
Contiene el texto del comando que se quiere emitir al proveedor. Es un string. Suele ser una
instrucción SQL, un nombre de tabla o un procedimiento almacenado, o cualquier otra
instrucción que reconozca el proveedor. El valor predeterminado es una cadena vacía.
Propiedad CommandTimeout
Especifica el intervalo de espera para que se ejecute un comando antes de que finalice el
intento y se genere un error. Es un Long que indica en segundos ese tiempo. El valor
predeterminado es 30.

Propiedad CommandType (IMPORTANTE)


Indica el tipo de un objeto Command. Esta propiedad se usa para optimizar la evaluación de la
propiedad CommandText, ya que de esta forma el proveedor no tiene que perder tiempo
examinando si es una instrucción SQL, un procedimiento almacenado o un nombre de tabla. Si
el valor de esta propiedad es adCmdUnknown (valor predeterminado), estamos forzando al
proveedor a que realice esa investigación lo que provocará probablemente un descenso en su
rendimiento. Si sabe qué tipo de comando está usando, el establecimiento de la propiedad
CommandType instruye a ADO a que vaya directamente al código relevante. Si la propiedad
CommandType no coincide con el tipo de comando de la propiedad CommandText, ocurre un
error cuando llama al método Execute.

Valores posibles

AdCmdText Indica que es una definición textual de un comando o una llamada a un


procedimiento almacenado.

AdCmdTable Indica que es un nombre de tabla cuyas columnas se devuelven todas


mediante una consulta SQL generada internamente.

AdCmdTableDirect Indica que es un nombre de tabla en la que se devuelven todas las


columnas.

AdCmdStoredProc Indica que es un nombre de procedimiento almacenado

AdCmdUnknown Predeterminado. El tipo de comando de la propiedad CommandText


es desconocido.

AdCmdFile Evalúa CommandText como el nombre de archivo de un valor


Recordset persistente.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 38


AdExecuteNoRecords Indica que es un comando o un procedimiento almacenado que no
devuelve filas (por ejemplo, un comando que sólo inserta datos). Si se recupera alguna fila, se
descarta y no se devuelve. Siempre se combina con adCmdText o adCmdStoredProc.

Propiedad Prepared
Es un Booleano que indica si se debe guardar una versión compilada de un comando antes de
su ejecución. Esta propiedad fuerza al proveedor a guardar una versión preparada (compilada)
de la consulta especificada en la propiedad CommandText antes de la primera ejecución de un
objeto Command. Esto puede disminuir el rendimiento de la primera ejecución de un comando,
pero cuando el proveedor haya compilado el comando, utilizará la versión compilada del mismo
para las ejecuciones siguientes, lo cual aumentará el rendimiento.
Si el proveedor no admite la preparación del comando, puede devolver un error cuando esta
propiedad se establezca a True. Si no devuelve un error, simplemente ignora la solicitud de
preparar el comando y establece la propiedad Prepared a False.

Propiedad State
Describe el estado del objeto: abierto o cerrado. Devuelve un Long o una constante:
adStateClosed o adStateOpen

Métodos del Objeto Command

Método Execute (IMPORTANTE, más bien diríamos, el objetivo del Command)


Ejecuta la consulta, la instrucción SQL o el procedimiento almacenado especificado en la
propiedad CommandText. Devuelve un recordset o modifica la base de datos.

Sintaxis
Para un Command que devuelva filas:

Set recordset = command.Execute(RecordsAffected, Parameters, Options)

Para un Command que no devuelva filas:

command.Execute RecordsAffected, Parameters, Options

command es el nombre del Objeto Command

RecordsAffected Opcional. Una variable Long en la que el proveedor devuelve el número de


registros afectados por la operación.

Parameters Opcional. Una matriz Variant con los valores de los parámetros pasados con una
instrucción SQL. (Los parámetros de salida no devuelven valores correctos cuando se pasan en
este argumento).

Options Opcional. Un valor Long o una constante. Acepta estos valores

adCmdText Indica que el proveedor tiene que evaluar CommandText como


definición textual de un comando, como una instrucción SQL.
adCmdTable Indica que ADO tiene que generar una consulta SQL para devolver
todas las filas de la tabla mencionada en CommandText.
adCmdTableDirect Indica que el proveedor tiene que devolver todas las filas de la tabla
mencionada en CommandText.
AdCmdStoredProc Indica que el proveedor tiene que evaluar CommandText como
procedimiento almacenado.
adCmdUnknown Indica que el tipo de comando en CommandText es desconocido.
adAsyncExecute Indica que el comando se tiene que ejecutar de forma asíncrona.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 39


adAsyncFetch Indica que el resto de las filas siguientes a la cantidad inicial especificada en la
propiedad CacheSize tiene que ser recuperada de forma asíncrona.

Método Cancel
Cancela la ejecución de una llamada asíncrona pendiente al método Execute

Sintaxis NombredelObjetoCommand.Cancel

Utilice el método Cancel para terminar la ejecución de una llamada asíncrona a un método
Execute (es decir, el método fue invocado con la opción adAsyncExecute o adAsyncFetch).

Comandos parametrizados.

Los objetos Command pueden utilizar parámetros. De esta forma, podemos construir una
consulta utilizando la interrogación (?) como comodín. Así cada vez que ejecutemos el
comando, V.B. se encargará de sustituir el comodín por los parámetros asociados a dicho
command. Además podemos utilizar los parámetros para recoger los valores devueltos por un
Procedimiento almacenado en la base de datos. Para entender mejor este tipo de consultas
primero veremos qué es el objeto parameter.

Ejemplo de la utilización de Command


Veamos un ejemplo de cómo usar el Objeto Command. Pero previamente vamos a ver un
código del que hemos partido para hacer ver al alumno que ADO permite hacer las cosas de
muchas maneras. Este código mete los datos de un documento en una base de datos Oracle,
leyendo previamente el número más alto del documento para poner al nuevo documento un
número igual al último + 1.:

Declaraciones
Dim ConexBDPrensa As ADODB.Connection
Dim RsBDPrensa1 As ADODB.Recordset
Dim StrIntroducir As String, NumeroDocumento as long

Rem Se abre un objeto Connection para crear sobre él el recordset


Set ConexBDPrensa = New ADODB.Connection
ConexBDPrensa.ConnectionString = "Provider=MSDAORA.1;” & _
“User ID=INTRANET;Password=INTRANET;Data Source=intranet;” & _
“Persist Security Info=False"
ConexBDPrensa.Open

Rem Se abre un recordset para leer el número, se lee y se vuelve a cerrar


RsBDPrensa1.Open "Int_Documentos Order By CL_DOC", ConexBDPrensa, adOpenDynamic,
adLockOptimistic
RsBDPrensa1.MoveLast
NumeroDocumento = RsBDPrensa1!CL_DOC
NumeroDocumento = NumeroDocumento + 1
RsBDPrensa1.Close

(* Este es el punto donde cambia el código que verá más adelante)

Rem Se introduce en una variable tipo String una instrucción para añadir un nuevo registro
Rem Esa instrucción se va a ejecutar desde el objeto Connection mediante su método Execute

StrIntroducir = "Insert Into INT_DOCUMENTOS " & _


"(CL_DOC,NOM_DOC,TITULO_DOC,AUTOR_DOC,CL_TEMA_DOC,CL_DPT_DOC,” & _
“CL_TIPO_DOC,FICH_DOC,FECHA_EMISION_DOC,ULTIMA_HORA_DOC,” & _

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 40


VISIBLE_DOC) Values (" & NumeroDocumento & ",'" & TbTitulo & "','" & TbTitulo & _
"','" & TbTitulo.Tag & "',19,2,1,'" & HRefPrensa & "/" & TbNombFichTIF & "','" & Date & "',0,1)"

Rem Observe que los valores tipo string introducidos (TbXXX) van entre comilla simple
Rem Se ejecuta esa instrucción desde el objeto Connection ConexBDPrensa

ConexBDPrensa.Execute StrIntroducir

Rem Se cierra el Objeto Connection

ConexBDPrensa.Close
Rem Aquí termina la operación de crear un nuevo registro
MsgBox "Documento enviado"

Este es el código real de una aplicación que introduce los datos el resumen de prensa diario en
una base de datos. Se introduce un nuevo registro en la tabla INT_DOCUMENTOS. El resumen
de prensa es un fichero .Tiff de nombre TbNombFichTIF que se mete en una carpeta del
servidor mediante FTP, y para su loccalización y presentación en una página Web es necesario
introducir su nombre y Path y otros datos en una base de datos. Los campos que se introducen
y los valores de cada uno son:

Campo Valor

CL_DOC, NumeroDocumento (Long calculado)


NOM_DOC TbTitulo (String contenido en TbTitulo.Text)
TITULO_DOC TbTitulo (String contenido en TbTitulo.Text – se repite-)
AUTOR_DOC TbTitulo.Tag (String contenido en TbTitulo.Tag)
CL_TEMA_DOC 19 (Integer, dato fijo)
CL_DPT_DOC 2 (Integer, dato fijo)
CL_TIPO_DOC 1 (Integer, dato fijo)
FICH_DOC HRefPrensa & "/" & TbNombFichTIF Un string que indica el nombre
del fichero (TbNombFichTIF.Text) y su carpeta (Variable HrefPrensa)
FECHA_EMISION_DOC Date (Fecha actual)
ULTIMA_HORA_DOC 0 (Byte, dato fijo)
VISIBLE_DOC 1 (Byte, dato fijo)

Esta forma de introducir los datos, método que los lingüistas especializados en la jerga
informática llaman “a capón”, es la que nunca falla. Exige un poco de código, con muchas
probabilidades de equivocarse, pero muchas veces se prefiere esta forma de meter datos a
utilizar el método AddNew. Tiene la gran ventaja de que la acepta cualquier base de datos,
independientemente de donde esté el cursor. Habrá observado que utilizamos el método
Execute del objeto Connection. Y así funciona perfectamente. Vamos a hacer lo mismo, pero
introduciendo la cadena de caracteres un objeto Command, (Que pertenece al mismo objeto
Connection sobre el que ahora hemos ejecutado el Execute) y vamos a ejecutar el Execute de
ese Command. ¿Se da cuenta que estamos haciendo lo mismo? El nuevo código creado a
partir del anterior es el siguiente:

(* Este es el mismo punto de antes. Aquí comienza el cambio del código)

Dim MiComando As ADODB.Command


Set MiComando = New ADODB.Command
MiComando.ActiveConnection = ConexBDPrensa

MiComando.CommandText = "Insert Into INT_DOCUMENTOS " _


&
"(CL_DOC,NOM_DOC,TITULO_DOC,AUTOR_DOC,CL_TEMA_DOC,CL_DPT_DOC,CL_TIPO
_DOC,FICH_DOC,FECHA_EMISION_DOC,ULTIMA_HORA_DOC,VISIBLE_DOC) " _
& "Values (" _
& NumeroDocumento & ",'" & TbTitulo & "','" & TbTitulo & "','" & TbTitulo.Tag & "',19,2,1,'" &
HRefPrensa & "/" & TbNombFichTIF & "','" & Date & "',0,1)"

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 41


MiComando.Execute
ConexBDPrensa.Close

ADO le permite hacer las cosas de maneras muy distintas, pero siempre debe aportar la misma
información. En este caso ha visto que el objeto Command no hace falta para nada. ¿Entonces,
para que existe? La respuesta es sencilla: facilita la comprensión del código. Pero que el
objeto Command no le perjudique precisamente eso, la comprensión del código. No se
preocupe de no ser estrictamente académico. Este humilde autor nunca usa Command excepto
para explicarlo. ADO nos permite eso.

Vamos a ver ahora cómo haríamos esto mismo con el método AddNew.

Deberemos crear un recordset. Lo primero, lo declaramos:


Dim RsBDPrensa as ADODB.Recodset

Luego lo creamos:
Set RsBDPrensa = New ADODB.Recordset

Lo abrimos. Pero primero tomamos la precaución de poner la propiedad CursorLocation del


Objeto Connection a adUseClient (Lado cliente) y de esta forma los cursores creados para los
recordsets abiertos sobre ese objeto connection estarán del lado cliente. Si el cursor está de
lado servidor es posible que no nos deje usar el método AddNew. (Vea Nota 1)

ConexBDPrensa.CursorLocation = adUseClient

Abrimos el Recordset:
RsBDPrensa.Open "Int_Documentos", ConexBDPrensa, adOpenDynamic, adLockOptimistic

Ejecutamos el método AddNew


RsBDPrensa.AddNew

Metemos los datos


RsBDPrensa!CL_DOC = NumeroDocumento
RsBDPrensa!NOM_DOC = TbTitulo
RsBDPrensa!TITULO_DOC = TbTitulo
RsBDPrensa!AUTOR_DOC = TbTitulo.Tag
RsBDPrensa!CL_TEMA_DOC = 19
RsBDPrensa!FECHA_EMISION_DOC = Date
RsBDPrensa!CL_DPT_DOC = 2
RsBDPrensa!CL_TIPO_DOC = 1
RsBDPrensa!FICH_DOC = HRefPrensa & "/" & TbNombFichTIF
RsBDPrensa!VISIBLE_DOC = 1
RsBDPrensa!ULTIMA_HORA_DOC = 0

Rematamos con el método Update


RsBDPrensa.Update

Cerramos el recordset.
RsBDPrensa.Close

Cerramos la conexión
ConexBDPrensa.Close

Nota 1. – Muchos programadores se rinden cuando ven que no les funciona los métodos
AddNew / Update para introducir nuevos datos. Cierto es que cada base de datos se comporta
de forma distinta respecto a este método. Pero antes de rendirse y usar el código “a capón”
intente ver como tienen la propiedad CursorLocation, el tipo de recordset abierto y el tipo de
bloque elegido (Recuerde que por defecto es de solo lectura). Eso sí, el método “a capón”
funciona siempre (Excepto que sea solo lectura), independientemente del bloqueo y del tipo de
cursor

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 42


LSB Visual Basic Guía del Estudiante Capítulo 14 Página 43
El “Control Data” de ADO - (Adodc ADO Data Control)
Este capítulo parece que quedaba un poco corto. No por el número de páginas, sino porque
tanto en DAO como en RDO nos explayamos con el control Data, y en ADO parece que
solamente lo hemos visto de pasada para explicar cómo se compone la cadena de conexión.
Veámoslo un poco más en profundidad.

El control Data para ADO es el “Microsoft ADO data control 6.0 (OLEDB)” que se encuentra
en Proyecto | Componentes. La apariencia es similar a la del Data de DAO

Hagamos un repaso de sus propiedades. Veremos solamente aquellas que son específicas de
ADO:

Propiedad BOFAction.
Establece la forma de proceder cuando llega a la fila anterior a la primera. Toma uno de estos
valores:

0 – adDoMoveFirst Vuelve a la primera fila


1 – adDoStayBOF Permanece en la fila BOF

Propiedad CommandType
Es idéntica a la misma propiedad del objeto Command. Acepta los valores:

AdCmdText Indica que es una definición textual de un comando o una llamada a un


procedimiento almacenado.

AdCmdTable Indica que es un nombre de tabla cuyas columnas se devuelven todas


mediante una consulta SQL generada internamente.

AdCmdStoredProc Indica que es un nombre de procedimiento almacenado

AdCmdUnknown Predeterminado. El tipo de comando de la propiedad CommandText


es desconocido.

Propiedad ConnectionString

Esta propiedad ya le hemos visto más atrás. Es la cadena de conexión con la base de datos.

Propiedad CursorLocation

Es la misma que la vista para el objeto Recordset.

Propiedad CursorType
Es la misma que para el objeto Recordset. Acepta los valores:
1 – adOpenKeyset
2 - adOpenDynamic
3 – adOpenStatic

Propiedad EOFAction

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 44


Establece la forma de proceder cuando llega a la fila EOF. Acepta los valores:

0 – adDoMoveLast Vuelve a la última fila


1 – adStayEOF Permanece en la fila EOF
2 – adDoAddNew Añade una nueva fila

Propiedad LockType

Tipo de Bloque. Igual a la misma propiedad del Objeto Recordset

Propiedad MaxRecords

Es similar a la del Objeto Recordset. Establece el número de filas que obtiene en su recordset
asociado.

Propiedad Mode.
Igual a la misma propiedad del objeto Recordset

Propiedades Password
Establece la contraseña para crear la cadena de conexión durante la creación del objeto
Recordset asociado. Esta contraseña es la contraseña del usuario en la base de datos.

Esta propiedad es solamente de escritura. Si se pretende leer da error.

Propiedad UserName
Establece el nombre del usuario. Debe ser uno de los usuarios registrados en la base de datos.
Esta propiedad es de lectura y escritura. El valor de la propiedad Password debe ser el
asociado a este usuario.

Propiedad RecordSource
Es una cadena de caracteres con el nombre de una tabla o una sentencia SQL que devuelve
filas.

Métodos del control Adodc

UpdateControls
Actualiza la información de los controles enlazados a datos. No existe el método
UpdateRecords.

Refresh
Vuelve a construir el recordset. Es idéntico al del control Data de DAO.

Vistas ya las propiedades y métodos del control Adodc, vamos a ver un poco como funciona y
cuales son sus diferencias con el control data de DAO

Funcionamiento del Adodc

El Adodc puede enlazar una base de datos a los típicos controles enlazados (Label, TextBox)
usando la tecnología ADO. Los demás controles enlazados no tienen un comportamiento igual

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 45


con el Adodc, Control Data o RDODataControl. En la siguiente lista puede ver que controles
trabajan con uno u otro control Data.

Control ADO RDO DAO Referencia

DBGrid NO SI SI Microsoft Data Bound Grid Control 5.0 SP3


DataGrid SI NO NO Microsoft DataGrid Control 6.0 (OLEDB)
DataList SI SI SI Microsoft Data List Controls 6.0 (OLEDB)
DataCombo SI SI SI Microsoft Data List Controls 6.0 (OLEDB)
DBList SI SI SI Microsoft Data Bound List Controls 6.0
DBCombo SI SI SI Microsoft Data Bound List Controls 6.0
MSFlexGrid NO SI SI Microsoft FlexGrid Control 6.0
MSHFlexGrid SI NO NO Microsoft Hierarchical FlexGrid Control 6.0 (OLEDB)

Por lo demás el funcionamiento del Adodc es similar al Control data y al RDODataControl.

Con este capítulo creo que ya tienen conocimientos suficientes para empezar a trabajar con
ADO, y por la tanto, ya tiene permiso para aprender a programar con esta tecnología. Le
recomiendo paciencia, y sobre todo no tener miedo a esta tecnología. Y como se dijo al
principio, úsela siempre que tenga que usar una base de datos instalada en un servidor y
conectada al usuario a través de una red de área local. En el próximo capítulo verá como se
enlazan un cliente con el servidor SQL Server.

De cualquier forma no olvide la tecnología DAO para sus pequeñas aplicaciones, con la base
de datos en el mismo ordenador que la aplicación. Personalmente creo que es mucho más
rápida y más sencilla.
Suerte.

Agradecimientos. En este capítulo participó activamente mi alumno del CEU César Moreno Fernández.

LSB Visual Basic Guía del Estudiante Capítulo 14 Página 46


Visual Basic - Guía del Estudiante Cap. 15

Apuntes finales sobre bases de datos y Visual Basic

Bases de Datos SQL Server y Oracle

Las bases de datos más conocidas de las utilizadas en plataforma Windows son posiblemente
Oracle y SQL Server. Cualquier programador conoce al menos unas de ellas. Queremos
explicar aquí los pasos que hay que realizar para poder “ver” la base de datos y trabajar con
ella desde Visual Basic.

Una base de datos de esta categoría va a estar instalada con toda seguridad en un servidor, y
accederemos a ella desde otro ordenador, que será el cliente. Puede estar instalada si lo desea
en el mismo ordenador, pero en ese caso deberá tratarlo como si su ordenador trabajase al
tiempo como servidor y como cliente.

La instalación de la base de datos dentro del servidor es bastante compleja, y no se va a


explicar en este curso. Se supone que el suministrador de la BD explicará como hacerlo. La
instalación de SQL Server exige que se haga sobre un PC o Net Server que tenga Windows
2000 Server (o NT Server), sistema operativo que no se suele instalar en los PCs de cliente y
mucho menos en los PC domésticos. Oracle dispone de una versión con prestaciones algo
reducidas que le permite instalarla en un puesto con Windows 98, en configuración
monousuario, circunstancia que permite hacer pruebas de funcionamiento en PCs particulares,
pero que no es la instalación típica que puede existir en una organización o empresa. Nos
referiremos siempre en este capítulo a la instalación convencional, de un servidor donde se
aloja la base de datos, y una serie de puestos clientes conectados a él mediante Red de Area
Local.

En la base de datos es necesario introducir los nombres de usuario que están permitidos, y la
clave de acceso para cada usuario. Lógicamente para que un puesto pueda acceder a la BD
debe conocer su nombre de usuario y la clave de acceso. Estos datos normalmente se
introducen en el cliente en su configuración, y no es necesario teclearlas cada vez que se inicia
una sesión.

La configuración del sistema de la base de datos es la de cliente - servidor.

El servidor tiene un programa que es el Gestor de la Base de Datos. La base de datos


propiamente dicha estará formada por uno o más ficheros con los datos que tienen introducidos
y la estructura de tablas, consultas e índices que tenga. El programa gestor es quien controla
estos ficheros y puede obtener de ellos los datos en una forma adecuada.

El cliente necesita tener un programa que será el que se comunique con el programa gestor
que está en el servidor. Este programa lo realiza el mismo fabricante de la base de datos y se
distribuye en el mismo disco que el programa servidor y el resto del sistema. A esta parte de la
aplicación cliente – servidor que se instala en cada cliente se le llama Componentes de
Conectividad. Y la misión de estos componentes de conectividad es servir de intermediario
entre el gestor de la base de datos instalado en el servidor, y el programa que en el equipo
cliente va a manejar los datos de esa base de datos. Este programa que va a manejar los datos
puede ser el Administrador Corporativo de SQL Server, el Developper 2000 de Oracle, o una
aplicación realizada por nosotros en Visual Basic. Pero el funcionamiento es siempre el
mismo, el programa que va a manejar los datos en el cliente conecta con el programa
Componentes de Conectividad y es este quien conecta con el Gestor de la Base de Datos
para que realice la operación que tenga que realizar y le devuelva, si ha lugar, la información
extraída de la base de datos. Por lo tanto para poder trabajar desde un cliente con la base de
datos, es necesario que en el servidor esté corriendo el programa gestor de la base de datos, y
en el cliente, que estén instalados los componentes de conectividad.

Los componentes de conectividad, tal como se dijo más atrás, están fabricados por el mismo
fabricante de la BD, pero no se extrañe si encuentra algún programa fabricado por otro

LSB Visual Basic Guía del Estudiante Cap. 15 Pág. 1


fabricante. Para Oracle hay varios fabricantes que han realizado un producto de este tipo. No
es difícil, ya que al tratarse de una aplicación cliente – servidor, lo único importante es el
protocolo de comunicación entre el programa gestor de la BD y los componentes de
conectividad. Vea el capitulo correspondiente a aplicaciones cliente –servidor para más
detalles.

Instalación de los componentes de conectividad para SQL Server


Para instalar los componentes de conectividad de SQL Server en un puesto cliente basta con
introducir el disco de distribución de SQL Server y dejar que se ejecute el Autorun.

Se le indica que instale el servidor de bases de datos. Al darse cuenta que no tiene Windows
2000, dice que no puede instalar más que los componentes del cliente.

Deje que siga la instalación aceptando todos los aviso que se produzcan. Llegará a esta
ventana:

SQL Server tiene dos discos, Standard y Profesional. El Profesional le permite hacer
instalaciones en equipos remotos, y en ese caso estaría la opción Equipo Remoto habilitada.
No es nuestro caso, ya que solamente debemos instalar en el equipo local. Siga la instalación
en la que en sucesivas ventanas le aparecerá la opción: “Crear una nueva instancia de SQL
Server o instalar herramientas de cliente”. Acepte esa opción. A continuación le pide el nombre
y contraseña. Se refiere a la del equipo, no al de la base de datos. Acepte. Llegará a la
ventana siguiente:

LSB Visual Basic Guía del Estudiante Cap. 15 Pág. 2


En esta ventana puede elegir instalar Solo conectividad (es lo que necesita para que un
programa realizado en visual basic funcione), Solo herramientas cliente (le instalará, además
de la conectividad, el Administrador Corporativo, Analizador de consultas, y otras herramientas
de SQL Server. El Administrado Corporativo es la interfase que SQL Server suministra para ver
la base de datos, tanto la estructura como los datos. No es necesario para que funcione una
aplicación realizada en Visual Basic, que lo único que necesita es conectarse a través de los
Componentes de Conectividad.

Vaya aceptando todas las ventanas y la instalación terminará con éxito.

Una vez instalada la conectividad debe asegurarse que desde el cliente ve al servidor y que no
está cerrado el paso al puerto 1433 mediante algún Firewall u otro dispositivo. Ya puede
trabajar con la base de datos SQL Server.

Posiblemente le surja una pregunta ¿Contra que base, en qué servidor, con qué usuario y
clave de acceso? Con lo Ud. ponga en el programa de Visual Basic en la propiedad
ConnectionString del objeto Connection de ADO. Vea un ejemplo real:

ConexRAEN.ConnectionString = "Provider=SQLOLEDB.1;Password=lsuarez;Persist Security


Info=True;User ID=lsuarez;Initial Catalog=Ayudas_M;Data Source=seae_sql"

Aquí tienen todos los datos necesarios para conocer todas las preguntas que se hacía antes:

Provider=SQLOLEDB.1 Nombre del proveedor de datos


Data Source=seae_sql Nombre del servidor donde está la base de datos.
Initial Catalog=Ayudas_M Nombre de la base de datos contra la que se abre la conexión.
User ID=lsuarez Nombre de Usuario
Password=lsuarez Clave de acceso
Persist Security Info=True ¿

LSB Visual Basic Guía del Estudiante Cap. 15 Pág. 3


Instalación de la conectividad de Oracle

Para instalar la conectividad de Oracle ocurre algo parecido a SQL Server. Le recomiendo que
se instruya adecuadamente con los manuales de Oracle para su correcta instalación. No es
complicado, pero este autor no conoce Oracle como SQL Server.

Con el disco Oracle 7 Client


Software (He empleado la versión
7.3.4.0.0) introduzca el CD-Rom y
deje que se ejecute el Autorun. Le
aparecerá esto. Acepte

Le pide el idioma:

Le van apareciendo
sucesivas ventanas en
una le pide el directorio
donde quiere instalar el
programa, en otra le pide
permiso para cambiar
una línea del Autoexec,
etc. Acepte los valores
hasta que la instalación
se haya realizado por
completo.

Una vez terminada verá que le ha creado una carpeta llamada


Orant que puede ver expandida en esta figura.

En \Orant\Network\Admin tiene un fichero llamado Sqlnet.Ora que


contienen algo como esto.

AUTOMATIC_IPC = OFF
TRACE_LEVEL_CLIENT = OFF
names.directory_path = (TNSNAMES)
names.default_domain = world
name.default_zone = world

Fíjese en la línea
names.directory_path = (TNSNAMES)

Esta línea indica que el fichero TNSNAMES.ORA que está en la


misma carpeta contiene el fichero de configuración de SQL Net.
Contiene varios ejemplos, que le pueden servir para configurar la
conexión a su servidor.

El contenido de ese fichero en mi PC es esto:

LSB Visual Basic Guía del Estudiante Cap. 15 Pág. 4


#Este es un fichero de Configuración de SQL*Net generado por la Configuración Rápida de
SQL*Net.
#Atención: No modifique este fichero.
#Si lo hace, la Configuración Rápida de SQL*Net puede no funcionar correctamente.

Tcp-loopback.world =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS =
(COMMUNITY = tcp.world)
(PROTOCOL = TCP)
(Host = 127.0.0.1)
(Port = 1521)
)
)
(CONNECT_DATA = (SID = ORCL)
)
)
Beq-Local.world =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS =
(COMMUNITY = beq.world)
(PROTOCOL = BEQ)
(PROGRAM = oracle73)
(ARGV0 = oracle73ORCL)
(ARGS = '(DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))')
)
)
(CONNECT_DATA = (SID = ORCL)
)
)
Intranet.world =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS =
(COMMUNITY = tcp.world)
(PROTOCOL = TCP)
(Host = 10.3.22.4)
(Port = 1521)
)
(ADDRESS =
(COMMUNITY = tcp.world)
(PROTOCOL = TCP)
(Host = 10.3.22.4)
(Port = 1526)
)
)
(CONNECT_DATA = (SID = SEUE2)
)
)

La parte que afecta a la aplicación en la que me conecto con Oracle es la que comienza por la
linea:

Intranet.world =

Los datos son reales. Pero he de manifestar que no conozco Oracle tan bien como para
explicarlo, y que la instalación la hizo personal de una distribuidora de Oracle. De cualquier

LSB Visual Basic Guía del Estudiante Cap. 15 Pág. 5


forma puede verse que está definiendo la conexión Intranet , que tienen el Host en la dirección
10.3.22.4 y el puerto de comunicación es el 1521, con una segunda alternativa en el puerto
1526.

Le recomiendo que si su caso es una conexión a Oracle se informe mejor de la configuración


de sus clientes. Es de suponer que los técnicos de Oracle le resuelvan las grandes dudas que
le pueden surgir por las escasa explicaciones de este curso…de Visual Basic.

Visual Basic con el que se escribió estas líneas para crear una conexión ADO con esa base de
datos:

Set ConexBDPrensa = New ADODB.Connection

ConexBDPrensa.ConnectionString = "Provider=MSDAORA.1;User ID=INTRANET;” & _


“Password=INTRANET;Data Source=intranet;Persist Security Info=False"

ConexBDPrensa.Open

El parámetro Data Source=intranet es el que emplea la conectividad de Oracle para buscar


en el fichero TNSNAMES.ORA la dirección del Host y el puerto empleado.

Puede darse cuenta que tanto en SQL Server como en Oracle estamos empleando conexiones
ADO. Podría hacerse también mediante RDO, creando un enlace ODBC (Para poder crear ese
enlace ODBC también es necesario instalar previamente la conectividad). Pero ODBC es una
tecnología que ya está considerada obsoleta, por lo que prescindimos de cualquier ejemplo.

Se sale necesariamente de este curso una explicación más profunda de estas dos bases de
datos.

LSB Visual Basic Guía del Estudiante Cap. 15 Pág. 6


Visual Basic - Guía del Estudiante Cap. 16
CONTROLES AVANZADOS DE VISUAL BASIC

Este capítulo pretende ampliar el conocimiento de ciertos controles introducidos con la versión 6
de VB, que, aunque ya son de uso habitual en cualquier aplicación, se salen un poco de los
conceptos estudiados en los controles de los capítulos 1 y 2. Vienen generalmente como un
paquete OCX que contiene varios de ellos.

Se estudian algunos de los paquetes distribuidos por Microsoft, sean o no fabricados por esta
compañía. Sería interminable comentar los paquetes realizados por casas especializadas,
controles de gran calidad, normalmente caros y para aplicaciones específicas dentro del ámbito
comercial en el que se mueve la empresa que lo realiza. Existen también gran cantidad de
controles realizados por particulares, con la mejor intención, que se pueden encontrar en
Internet distribuidos de forma gratuita. Son desaconsejables. No porque no funcionen, sino
simplemente porque no ofrecen ningún tipo de garantía, están normalmente sin información de
funcionamiento, y en caso de problemas no se puede recurrir a nadie para resolverlos. Una
aplicación profesional nunca deberá llevar un control shareware.

Paquete MSCOMCTL.OCX

Este paquete se denomina Microsoft Windows Common Controls 6.0 Contiene los siguientes
controles:

TabStrip Es un control de pestañas. Pero este control no hace de contenedor de otros


controles, por lo que hay que introducir un control Frame o PictureBox por cada
una de las pestañas. No es práctico. Utilice en su lugar el SSTab.

Fig. 16.1 Aspecto del TabStrip

ToolBar Este es el control que presenta una barra de tareas. Es configurable, pudiendo
poner los botones que queramos con el icono apropiado. Es el control que el
alumno introduce por norma en sus primeras aplicaciones. Luego se va dando
cuenta de que hay cosas mejores y más simples. (Un Picture Box con varios
controles Image).Se coloca automáticamente en la parte superior del
formulario.

Fig. 16.2 ToolBar con cuatro botones

StatusBar Similar al anterior, pero para la barra de estado en la parte inferior del
formulario. Personalmente, creo que es más útil que el anterior. Puede
presentar automáticamente algunos parámetros del PC (Bloq. Mayúsculas,
Bloq. Números, Hora, Fecha) o el texto que se desee.
Fig. 16.3
StatusBar

ProgressBar Es la típica barra de progreso de Windows.

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 1


Fig. 16.4

Slider Es un control que permite introducir valores mediante un cursor

Fig. 16.5

Los controles anteriores se parecen a otros similares ya explicados en los capítulos anteriores,
y la profundización en sus propiedades y métodos no va a ser problema para el alumno sin más
explicaciones. Reservemos el tiempo de estudio para lo interesante, que es lo que viene ahora

ImageList Es un almacén de imágenes. Este control es necesario para poder poner


imágenes en el resto de los controles de este paquete. Se pueden usar varios
controles ImageList dentro del mismo formulario, y con la propiedad ImageList
de cada control utilizar uno u otro en cada uno de los controles que se usen en
el mismo formulario. Ya se ha visto en un capítulo anterior, pero ampliaremos
aquí los detalles de su funcionamiento.

TreeView Es un control que permite presentar de forma gráfica datos estructurados de


forma jerárquica, pudiendo usar gráficos y textos para presentarlos.

ListView Es un control que permite presentar datos en una lista, utilizando para ello
gráficos y texto, con cuatro disposiciones distintas.

ImageCombo Es como un combo convencional, pero en este se pueden insertar también


gráficos y hacer sangrías independientes para cada elemento.

Estos cuatro últimos controles se explican a continuación con detalle.

Control ImageList
Es un almacén de imágenes. Se representa en la caja de herramientas de esta
forma: Fig. 16.6

En tiempo de ejecución no tiene presentación gráfica. No tiene eventos y solamente un


Método.
Como todos los controles de este paquete, tiene un cuadro de propiedades personalizado que
facilita la introducción de las mismas.
El cuadro de propiedades tiene tres pestañas, de las cuales solamente tienen importancia dos
de ellas: General e Imágenes. La tercera se refiere a los colores que en este caso no tienen
función alguna. Las pestañas pueden verse en las figuras 16.7 y 16.8

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 2


Fig. 16.7 Pestaña General.
En esta pestaña se elige el ancho y alto de la imagen. Es importante esto a la hora de presentar
los iconos sobre un ListView o TreeView, ya que el tamaño con el que aparecen en estos
controles es precisamente el elegido en esta pestaña. Mediante el uso de dos ImageList, uno
con imágenes de 32 x 32 y otro, con las mismas imágenes, pero de 16 x 16, podemos cambiar
el tamaño de los iconos en los controles ListView o TreeView. Este truco es la única solución
para poder poner iconos grandes o pequeños en el TreeView. Para cambiar el tamaño es
necesario que el ImageList no tenga cargada aún ninguna imagen.

Fig. 16.8 Pestaña de Imágenes


En esta se pueden introducir las imágenes que vamos a utilizar en los controles que tengan
asociado este ImageList. Es importante citar la propiedad Key de cada imagen, que sirve para
elegir la imagen. Una imagen de un ImageList se puede elegir mediante su índice (El índice va

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 3


de 1 a n, siendo n el número de imágenes), pero eso puede llevarnos a error, ya que dice muy
poco el número de la imagen dentro del ImageList, además de que ese número puede variar si
introducimos posteriormente una imagen nueva en una posición central. Podemos utilizar para
definir la imagen el texto que introduzcamos en la propiedad Key. Por ejemplo, en la figura
anterior, la imagen que presenta una interrogación tiene el valor Question, valor que expresa de
forma inconfundible el contenido de esa imagen, y que es inalterable sea cual sea la posición
que ocupa esa imagen en el ImageList. De esta forma, para poner esa imagen en el nodo
número 1 del TreeView1 basta con poner:
TreeView1.Nodes(1).Image = "Question"

Otras propiedades y métodos del control ImageList


Propiedad ListImages. Esta propiedad representa al conjunto de imágenes del control
ImageList. Pueden introducirse más imágenes en tiempo de ejecución, utilizando el método Add
sobre esta propiedad, cuya sintaxis es la siguiente:
ImageList.ListImages.Add Index, Key, Picture
Por ejemplo: ImageList1.ListImages.Add 6, "Imagen1TE", Picture1.Picture
(Se ha introducido en la colección ListImages la imagen que tienen el Picture1 como imagen
con Index = 6 y con Key = Imagen1TE)
También se puede vaciar un ImageList usando el método Clear:
ImageList1.ListImages.Clear

Propiedad MaskColor
Devuelve o establece el color que se usa para crear las máscaras de un control ImageList.

Sintaxis ImageList.MaskColor = color

Esta propiedad se usa en el método Overlay. La propiedad MaskColor determina qué color de
una imagen será transparente en el método Overlay. Sólo es aplicable cuando la imagen del
ImageList es un BMP

Método Overlay
Dibuja una imagen utilizando dos imágenes de la colección ListImages de un control ImageList,
y pone esa imagen dentro de un control

Sintaxis Control.Picture = ImageList.Overlay (índice1, índice2)

Donde Indice1 e Indice2 son la propiedad Index o la propiedad Key de la imagen que se va a
superponer (Indice1) y de la imagen sobre la que se va a superponer la primera (Indice2).
Control es un control capaz de contener una imagen (Picture, Image, Formulario)

Antes de utilizar el método Overlay deberemos poner un valor a la propiedad MaskColor. (La
transparencia de un color solamente va a funcionar cuando vamos a superponer dos imágenes
en formato BMP)

Control TreeView.
Es un control que permite presentar datos que están estructurados de forma jerárquica. Los
datos se pueden presentar como un texto, acompañados de un icono que determina el tipo de
dato. Puede por ejemplo presentar el organigrama de una empresa, mostrando los
departamentos que la componen, y dentro de estos, las personas que pertenecen a cada
departamento, y para cada persona, su número de teléfono, fax, E-Mail y domicilio, y todos
ellos, representados con un icono. Al hacer doble clic sobre un icono se despliegan los

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 4


elementos que existen bajo ese icono. Volviendo a hacer doble clic, se ocultan. Es lo más
parecido al funcionamiento del explorador de Windows.

Fig. 16.9 TreeView


mostrando seis
nodos, a la
izquierda con iconos grandes y a la derecha con iconos pequeños.
La vista de la Fig. 16.9 nos lleva a la primera idea acerca del TreeView: los Nodos. En
cualquier estructura jerárquica, un elemento tiene contenido en sí mismo, pero de él pueden
depender otros elementos. Esto nos lleva al concepto de Nodo. En el TreeView los datos se
presentan mediante nodos. El conjunto de todos los nodos es la colección Nodes. Esta
colección como cualquier colección en visual basic tiene sus propiedades y métodos.
Para empezar, la colección Nodes tiene el método Add. De esta forma ya podemos introducir
nodos en el TreeView. También tienen los método Remove, para eliminar uno de los nodos, y
Clear, para eliminar todos los nodos del TreeView.
El TreeView tiene varios estilos de presentación. Puede presentar los datos solamente con
textos, con texto y un icono, con un signo + ó – para indicar que ese nodo tiene elementos bajo
él, puede tener líneas o no. El estilo de presentación lo elegimos mediante la propiedad Style
del TreeView.
Propiedad Style.
Determina el estilo de presentación del TreeView. Es de lectura y escritura
Sintaxis NombredelTreeView.Style = Número (Establece el estilo)
Número = NombredelTreeView.Style (Devuelve el estilo)

El parámetro Número puede ser un número del 0 al 7. El estilo correspondienta a cada valor es:

0 = Sólo Texto 1 = Imagen y Texto 2 = +/- y Texto 3 = +/- imagen y texto


4 = Líneas y texto 5 = Líneas, imagen y Texto 6 = Líneas, +/- y texto
7 = Líneas, +/-, Imagen y Texto (Valor predeterminado)

Con lo visto hasta ahora ya podemos ver cómo introducimos nodos en un TreeView. Para poder
introducir nodos con gráficos, es necesario poner en el mismo formulario, un control ImageList
con todas las imágenes que queremos poner en los nodos (Observe en la Fig. 16.8 que

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 5


contiene todos los iconos que aparecen en la Fig. 16.9 Izda.) En ese ImageList hay que poner a
cada imagen un valor en su propiedad Key (En la Fig. 16.8, la imagen correspondiente a la
carpeta cerrada tiene en su propiedad Key la cadena “Cerrado”, la imagen con una carpeta
abierta, “Abierto”, la correspondiente al sobre tiene “Sobre” y la cara, “Cara”. Ya podemos
introducir los nodos mediante el método Add:

Método Add para la colección Nodes de un TreeView


Añade un nodo a la colección Nodes de un TreeView
Para añadir un nodo, primero debemos declarar una variable tipo Node. (Dim MiNodo As Node)
A continuación ejecutar el método Add, que tiene la siguiente Sintaxis
Set VariableTipoNode =
NombredelTreeView.Nodes.Add (RelativoA, TipodeRelacion, Key, Texto, Imagen1, Imagen2)
Donde:
VariableTipoNode es la variable declarada como tipo Node (MiNodo en el ejemplo)
NombredelTreeView es el nombre del TreeView
RelativoA es el Key o el Index del nodo del cual dependerá este nodo que estamos
introduciendo. Si el nodo no va a pertenecer a ningún otro (caso del nodo Raiz) este valor se
deja en blanco, pero recuerde que debe poner la coma de separación. Lógicamente el nodo
indicado en este parámetro ya debe estar introducido antes de introducir este.
TipodeRelacion es un valor o constante que determina la situación del nodo respecto al nodo
indicado en el parámetro RelativoA. Vea más abajo los valores aceptados en este parámetro.
Key es una cadena de caracteres que define a este nodo. Esta cadena de caracteres debe ser
única, es decir, no se puede repetir en dos o más nodos. Debe empezar por letra, aunque
puede contener números.
Texto es el texto que va a figurar en el nodo. Es un parámetro obligado.
Imagen1 es la propiedad Index o Key de la imagen que queremos poner en el nodo. Este Index
o Key es el que tiene esa imagen en el control ImageList asociado a este TreeView. Imagen1 es
la imagen que mostrará el TreeView para ese nodo cuando ese nodo NO está seleccionado.
Imagen2 es la propiedad Index o Key de la imagen que queremos que aparezca en ese nodo
cuando está seleccionado. Si no se pone este parámetro, la imagen del nodo cuando está
seleccionado, es la misma que cuando no lo está.
Los valores para TipoRelacion pueden ser:
Constante Valor Descripción
TvwFirst 0 Primero. El objeto Node se sitúa antes de todos los demás nodos al
mismo nivel que el especificado en RelativoA
TvwLast 1 Ultimo. El objeto Node se sitúa después de todos los demás nodos al
mismo nivel que el especificado en RelativoA. Los objetos Node que se
agregan secuencialmente se irán situando detrás del último agregado.
TvwNext 2 (Predeterminado) Siguiente. El objeto Node se sitúa después del
especificado en RelativoA.
TvwPrevious 3 Anterior. El objeto Node se sitúa antes del especificado en RelativoA
TvwChild 4 Secundario. El objeto Node es secundario con respecto al
nodoespecificado en RelativoA.

El Index de la colección Nodes comienza a numerar por el 1. Cada vez que se añade un nodo,
el Index de ese nodo será el Index del último + 1, independientemente de la posición que va a

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 6


ocupar ese nodo dentro del TreeView. No controlamos directamente esta propiedad. Por eso,
es mucho más práctico definir a los nodos mediante su propiedad Key.

Ya estamos en condiciones de rellenar un TreeView con varios nodos. El código para colocar
los nodos de la figura 16.9 es: (El nombre del TreeView es TreeV1)
Dim MiNodo As Node ‘Declaramos la variable tipo Node
TreeV1.Style = 7 ‘Hacemos que el estilo sea Líneas, +/-, Imagen y Texto
Set MiNodo = TreeV1.Nodes.Add(, , "R", "Raíz") ‘No tienen parámetro RelativoA
‘Los siguientes nodos,dependen del nodo Raiz, que tiene Key = “R”
Set MiNodo = TreeV1.Nodes.Add("R", tvwChild, "C1", "Secundario 1", "Cerrado")
Set MiNodo = TreeV1.Nodes.Add("R", tvwChild, "C2", "Secundario 2", "Cerrado")
Set MiNodo = TreeV1.Nodes.Add("R", tvwChild, "C3", "Secundario 3", "Sobre")
Set MiNodo = TreeV1.Nodes.Add("R", tvwChild, "C4", "Secundario 4", "Cerrado")
‘El siguiente nodo depende de Secundario 4, que tienen Key = “C4”, y además tiene un
‘icono distinto (Question) para cuando está seleccionado.
Set MiNodo = TreeV1.Nodes.Add("C4", 4, "C4b", "Terciario C41" , "Cara", "Question")
‘Ahora se introduce una propiedad a cada uno de los nodos todavía no explicada: la
‘imagen que va a tener cuando ese nodo esté expandido, es decir, cuando se ven los
‘nodos que dependen de él. Vea que se le pone un valor a esta propiedad incluso a los
‘nodos que no tienen otros nodos que dependan de ellos.
TreeV1.Nodes(1).ExpandedImage = "Abierto"
TreeV1.Nodes(2).ExpandedImage = "Abierto"
TreeV1.Nodes(3).ExpandedImage = "Abierto"
TreeV1.Nodes(4).ExpandedImage = "Abierto"
TreeV1.Nodes(5).ExpandedImage = "Abierto"
TreeV1.Nodes(6).ExpandedImage = "Abierto"
‘Y ahora otra propiedad no explicada. Con esto hacemos que se vean todos los nodos.
MiNodo.EnsureVisible
El resultado de este código es la Fig. 16.9. Y la
Fig. 16.10 es lo que pasa cuando se selecciona el
nodo cuyo texto es Terciario C41. Observe en el
código que al introducir este nodo habíamos
puesto un parámetro más, precisamente, el de la
imagen que tendrá cuando esté seleccionado.

Fig. 16.10
Propiedades de la colección Nodes
del TreeView
Propiedad ExpandedImage

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 7


Establece la imagen del nodo cuando está expandido, es decir, cuando se ven los nodos que
dependen de él. Es la propiedad Index o Key que tiene esa imagen en el control ImageList
asociado al TreeView.
Sintaxis NombredelTreeView.Nodes(Index).ExpandedImage = Valor
Donde Valor puede ser, o bien el Index o el Key de la imagen en el ImageList asociado al
TreeView.

Propiedad Expanded
Devuelve o establece un valor que determina si un objeto Node de un control TreeView se
encuentra expandido o contraído. Es una propiedad Booleana

Sintaxis NombredelTreeView.Nodes(Index).Expanded = True/False

Esta propiedad puede usarse para expandir por programa un objeto Node. Si un objeto Node no
tiene nodos secundarios, el valor de esta propiedad se pasa por alto.

Propiedad Children
Devuelve el número de objetos Node secundarios contenidos en un objeto Node. Esta
propiedad es solamente de lectura.

Sintaxis VariableNumerica = NombredelTreeView.Nodes(Index).Children

Propiedad FullPath
Devuelve la ruta completa de un objeto Node. El valor devuelto es una cadena de caracteres
que es el resultado de concatenar el texto de la propiedad Text del objeto Node referenciado
con los valores de las propiedades Text de todos sus predecesores. El valor de la propiedad
PathSeparator del TreeView determina el delimitador utilizado para separar el Text de uno y
otro nodo.

Sintaxis NombredelTreeView.Nodes(Index).FullPath

Esta propiedad puede usarse en el procedimiento NodeClick del TreeView, que ya pasa como
parámetro el nodo sobre el que hemos hecho click:

Private Sub TreeV1_NodeClick(ByVal Node As MSComctlLib.Node)


VariableTipoString = Node.FullPath
End Sub

Propiedad Count
Devuelve el número de elementos de la colección Nodes

Sintaxis VariableNumerica = NombredelTreeView.Nodes.Count

Propiedades Child, FirstSibling, LastSibling, Previous, Parent, Next y Root

Estas propiedades devuelven una referencia a otro objeto Node. Con esa referencia que nos
devuelve, podremos conocer los valores de las propiedades del nodo cuya referencia nos
devuelve (Text, Key, FullPath, etc)
Sintaxis NombredelTreeView.Nodes(Index).Xxxx

Donde Xxxx es la propiedad deseada de las mencionadas.

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 8


Dependiendo de la propiedad, nos devuelve la referencia de:

Child Primer elemento secundario


FirstSibling Primer nodo del mismo nivel
LastSibling Ultimo nodo del mismo nivel
Previous Nodo anterior del mismo nivel
Next Siguiente nodo del mismo nivel
Parent Nodo primario (Nodo del que depende)
Root Nodo Raiz

Propiedad Key
Esta propiedad establece o devuelve una cadena de caracteres que identifica unívocamente a
un nodo. Esta propiedad se le asigna normalmente durante la creación de ese nodo mediante
el método Add, pero puede cambiarse posteriormente por programa.
La propiedad Key puede usarse para nombrar al nodo, al tratarse de una cadena única. No
puede haber dos nodos con el mismo Key. Si la cadena no es única, se produce un error.

Sintaxis NombredelTreeView.Nodes(Index).Key = cadena

Es muy prudente usar la propiedad Key para "autodocumentar" su proyecto de Visual Basic si
asigna nombres significativos a los objetos de una colección.

Propiedad Sorted
Esta propiedad la tiene tanto el control TreeView como la colección Nodes. Si esta propiedad
está a True en el TreeView, se ordenan alfabéticamente los elementos de nivel superior de la
colección Nodes.

Cada elemento de la colección Nodes puede tener su propiedad Sorted a True. En este caso,
los nodos que dependen de ese nodo estarán ordenados por orden alfabético.

Puede tener nodos con la propiedad Sorted = True, y otros con esa propiedad = False.

Propiedad Image
Establece la imagen que presenta un nodo. El valor de esta propiedad es, o bien el Index de la
imagen dentro del ImageList asociado al TreeView, o su propiedad Key.

Sintaxis NombredelTreeView.Nodes(Index).Image= Valor

Propiedad SelectedImage
Es lo mismo que la propiedad anterior, pero en este caso se establece la imagen que presenta
el nodo cuando está seleccionado.

Recuerde que estas propiedades son de la colección Nodes del TreeView. Veremos ahora las
propiedades del TreeView.
Propiedades del Control TreeView
Ya se han visto algunas más atrás. Se comentan solamente aquellas propiedades que no son
comunes al resto de los controles.

Propiedad Checkboxes
Establece si se muestran las casillas de verificación. (True/False)

Sintaxis NombredelTreeView.Checkboxes = True/False

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 9


Estas casillas de verificación no se suelen usar en el TreeView porque no son precisamente
bonitas. Si esta propiedad está a True, es preciso usar una propiedad de la colección Nodes, la
propiedad Checked, que es también booleana. Si ese nodo tiene esa propiedad a True, su
casilla de verificación aparece marcada.

Propiedad FullRowSelect
Establece si al seleccionar un nodo se marca solamente el texto del nodo (False) o si se marca
toda la horizontal del mismo (True).

Propiedad HideSelection
Establece si el texto seleccionado aparece resaltado cuando un control pierde el enfoque.

Propiedad HotTracking
Determina si está activado el resalte sensible al puntero del ratón. Una línea por debajo del
texto cuando pasamos el ratón por encima.

Propiedad ImageList
Establece el control ImageList que está asociado al TreeView. El ImageList debe estar en el
mismo formulario que el TreeView al que se asocia, pero un mismo ImageList puede estar
asociado a más de un TreeView u otros controles.

El TreeView necesita un ImageList para tomar de él las imágenes que va a colocar en los
nodos. Esta propiedad se puede cambiar en tiempo de ejecución, y es este precisamente, el
truco que nos permite cambiar en el TreeView el tamaño de los iconos.

En la Fig. 16.9 (Página 5) puede ver el mismo TreeView con dos tipos de iconos. El TreeView
no nos permite cambiar de tipo de iconos, (tal como lo hace el ListView) por lo tanto hay que
inventar algo que permita cambiarlos y así obtener la misma estética que en el ListView. Esto
se logra colocando dos ImageList en el formulario con las mismas imágenes e idénticos Key
para ellas. En uno de ellos se pone la resolución de las imágenes a 32 x 32 y en el otro a 16 x
16 (Vea Fig. 16.7 Página 3) Cuando quiera usar iconos pequeños, se asocia al TreeView el
ImageList con la resolución de 16 x 16, mediante la sintaxis:
NombredelTreeView = ImageList1 ó Set NombredelTreeView = ImageList1
Y a continuación se añaden los nodos mediante el método Add. Si quiere cambiar los iconos
durante la ejecución del programa (es muy típico colocar en una línea del menú el tipo de
iconos a presentar) observará que al cambiar el ImageList desaparecen los iconos. No hay otro
remedio más que volver a cargarlos, usando los métodos de la colección Nodes Clear (para
vaciarla) y Add. Este es el código que he usado en el ejemplo que ilustra este capítulo:

Set TreeV1.ImageList = ImageList2


TreeV1.Nodes.Clear
cmdIntroducirNodos_Click ‘(cmdIntroducirNodos es un botón con el código para añadir los
‘nodos)
Propiedad Indentation
Establece el ancho de la sangría de los nodos. Afecta a todos los niveles de nodos. Puede
cambiarse en tiempo de ejecución.

Propiedad LabelEdit
Devuelve o establece un valor que determina si el usuario puede modificar la propiedad Text de
los objetos Node de un control TreeView.

Sintaxis NombredelTreeView.LabelEdit = entero

Donde entero puede ser:

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 10


Constante Valor Descripción
tvwAutomatic 0 Predeterminado) Automático. Se genera el evento
BeforeLabelEdit cuando el usuario hace clic en la etiqueta de
un nodo seleccionado.
TvwManual 1 Manual. El evento BeforeLabelEdit sólo se genera al invocar el
método StartLabelEdit.

La edición de la etiqueta de un objeto se inicia al hacer clic en un objeto seleccionado (si la


propiedad LabelEdit está establecida a Automatic). Es decir, el primer clic en un objeto lo
selecciona y un segundo clic (simple) inicia la operación de edición de la etiqueta.
La propiedad LabelEdit, junto con el método StartLabelEdit, permite determinar por programa
qué etiquetas se pueden modificar y cuándo hacerlo. Cuando LabelEdit tiene el valor 1, no
puede modificarse ninguna etiqueta, a menos que se invoque el método StartLabelEdit.

Propiedad LineStyle
Establece el estilo de las líneas que aparecen entre los objetos Node.

Sintaxis NombredelTreeView.LineStyle = número

Acepta los valores 0 (tvwTreeLines) con lo que presentará solamente las líneas entre los nodos
de un mismo nivel y su nodo primario, y 1 (tvwRootLines) que presenta, además de las
anteriores, líneas entre los nodos raiz.
Propiedad Nodes
Devuelve una referencia a la colección de objetos Node de un control TreeView
Parent (Propiedad)
Devuelve una referencia al formulario que contiene un control u otro objeto o colección.

Propiedad PathSeparator
Establece el carácter delimitador utilizado en la ruta devuelta por la propiedad FullPath. El
carácter predeterminado es "\".

Scroll (Propiedad)
Devuelve o establece un valor que especifica si se muestran barras de desplazamiento.

SelectedItem (Propiedad, controles ActiveX)


Devuelve la referencia al objeto Node seleccionado.

Propiedad SingleSel
Establece si un nodo debe expandirse cuando se selecciona. Un nodo, con otros nodos
dependiendo de él, se expande al hacer doble clic sobre él, o al hacer clic sobre el + asociado a
ese nodo. Se contrae volviendo a realizar la misma operación. Si esta propiedad está a True,
se expande o contrae cuando se hace clic sobre él.

Propiedad Sorted
Ya explicada para la colección Nodes.

Métodos del TreeView.

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 11


Método GetVisibleCount
Devuelve el número de objetos Node que caben en el área interna de un control TreeView.

El número de objetos Node viene determinado por la cantidad de líneas que caben en una
ventana. El número total de líneas posibles lo determina el alto del control y la propiedad Size
del objeto Font. En este número se cuenta el elemento situado al final de la lista y que sólo es
visible parcialmente.
Puede usar la propiedad GetVisibleCount para asegurarse de que es visible un número
mínimo de líneas que permita al usuario hacerse una idea de la jerarquía. Si no es visible este
mínimo, puede restablecer el tamaño del control TreeView mediante la propiedad Height. Si un
determinado objeto Node debe ser visible, utilice el método EnsureVisible para desplazar y
expandir el control TreeView.

Método HitTest
Devuelve la referencia del objeto Node situado en las coordenadas x e y. Se utiliza sobre todo
en las operaciones de arrastrar y colocar para determinar si hay disponible en la ubicación
actual un elemento de destino de colocación. Si no hay ningún objeto en las coordenadas
especificadas, el método HitTest devuelve Nothing.
El método HitTest se utiliza casi siempre junto con la propiedad DropHighlight para resaltar un
objeto cuando se arrastra el mouse sobre él durante una operación de Drag & Drop. La
propiedad DropHighlight requiere una referencia a un objeto específico para resaltarlo. Para
determinar el objeto, se usa el método HitTest junto con un evento que devuelva las
coordenadas x e y, como DragOver, con el siguiente código:

Private Sub TreeV1_DragOver(Source As Control, x As Single, y As Single, State As Integer)


Set TreeV1.DropHighlight = TreeV1.HitTest(x, y)
End Sub

Método StartLabelEdit
Inicia el proceso de modificación de la propiedad Text de un nodo, cuando la propiedad
LabelEdit está puesta a 1 (Manual).

Sintaxis NombredelTreeView.StartLabelEdit

Cuando la propiedad LabelEdit está a 0 (Automático) la edición del texto comienza


automáticamente cuando se hace clic sobre un nodo ya seleccionado. Si esta propiedad está
en manual es cuando debemos forzar el inicio de la edición

Cuando se invoca el método StartLabelEdit para un objeto, también se genera el evento


BeforeLabelEdit.

Eventos del TreeView


Se mencionan solamente aquellos que no son comunes a otros controles ya estudiados.

Evento BeforeLabelEdit
Se produce cuando el usuario intenta modificar la etiqueta (Propiedad Text) de un Node.

Sintaxis Private Sub NombredelTreeView _BeforeLabelEdit(cancelar As Integer)

Donde Cancelar es un entero que si no es 0, cancela la operación de edición.

El evento BeforeLabelEdit se produce después del evento Click estándar.

Los eventos AfterLabelEdit y BeforeLabelEdit sólo se generan si el valor de la propiedad


LabelEdit es 0 (Automática) o si se invoca el método StartLabelEdit.

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 12


Para comenzar a modificar una etiqueta, el usuario debe hacer clic primero en el objeto para
seleccionarlo y hacer clic una segunda vez para iniciar la operación. El evento BeforeLabelEdit
se produce después del segundo clic.
Para determinar a qué objeto pertenece la etiqueta que se va a modificar, utilice la propiedad
SelectedItem. En el ejemplo siguiente se comprueba el índice de un objeto Node antes de
permitir su edición. Si el índice es 1, se cancela la operación.
Private Sub TreeView1_BeforeLabelEdit(Cancel As Integer)
If TreeView1.SelectedItem.Index = 1 Then
Cancel = True ' Se cancela la operación
End If
End Sub

Evento AfterLabelEdit
Se produce cuando se termina de modificar la etiqueta (Propiedad Text) de un Node

Sintaxis
Private Sub NombredelTreeView_AfterLabelEdit(cancelar As Integer, nuevaCadena As String)

Donde cancelar es un entero que, si no es 0, se cancela la operación de edición, y


NuevaCadena es la cadena de caracteres que el usuario ha escrito en esa etiqueta, o Null si se
ha cancelado la operación de edición.

El evento AfterLabelEdit se genera después de que el usuario termina la operación de edición,


lo que ocurre cuando hace clic en otro objeto Node o cuando presiona la tecla ENTRAR.

Para cancelar una operación de edición de etiqueta, establezca True o cualquier valor distinto
de cero en cancelar. Al cancelar la operación, se restaurará la etiqueta existente anteriormente.
El argumento nuevaCadena puede usarse para comprobar una condición antes de cancelar una
operación. Por ejemplo, el código siguiente cancela la operación si nuevaCadena es un
número:
Private Sub TreeView1_AfterLabelEdit(Cancel As Integer, NewString As String)
If IsNumeric(NewString) Then
MsgBox "No se permiten números"
Cancel = True
End If
End Sub

Los eventos AfterLabelEdit y BeforeLabelEdit sólo se generan si el valor de la propiedad


LabelEdit es 0 (Automática) o si se invoca el método StartLabelEdit.

Evento Collapse
Se genera al contraer cualquier objeto Node de un control TreeView, es decir, cuando sus
nodos secundarios se ocultan.

Sintaxis Private Sub NombredelTreeView _Collapse(ByVal nodo As Node)

El evento Collapse se produce antes del evento Click estándar.


Existen tres formas de contraer un objeto Node: establecer a False su propiedad Expanded,
hacer doble clic en un objeto Node y hacer clic en una imagen más/menos cuando la propiedad
Style del control TreeView se ha establecido a un estilo que incluye estas imágenes. Todos
estos métodos generan el evento Collapse.

Evento Expand
Se produce al expandir un objeto Node de un control TreeView, es decir, cuando sus nodos
secundarios se hacen visibles.

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 13


Sintaxis Private Sub NombredelTreeView _Expand(ByVal nodo As Node)

El evento Expand se produce después de los eventos Click y DblClick.


El evento Expand se puede generar de tres formas: cuando el usuario hace doble clic en un
objeto Node que tiene nodos secundarios, cuando se establece a True la propiedad Expanded
de un objeto Node y cuando se hace clic en la imagen más/menos.

Evento NodeClick
Se produce al hacer clic en un objeto Node.

Sintaxis Private Sub NombredelTreeView _NodeClick(ByVal nodo As Node)

Cuando el usuario hace clic en cualquier punto de un control TreeView, fuera de un objeto
nodo, se genera el evento Click estándar. El evento NodeClick se genera cuando el usuario
hace clic en un objeto Node determinado y devuelve una referencia al objeto Node que puede
usarse para validarlo antes de realizar alguna otra acción.
El evento NodeClick se produce antes del evento Click estándar.

Evento Validate
Ocurre cuando el foco cambia a otro control que tiene su propiedad CausesValidation
establecida a True. (Este evento es común a todos los controles ActiveX)

Sintaxis Private Sub NombredelTreeView _Validate(mantenerFoco As Boolean)

Donde mantenerFoco es un Booleano que si es True, fuerza al TreeView a recuperar el foco.


Se emplea para evitar que un control pierda el foco hasta que se cumplan ciertas condiciones.

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 14


El control ListView
Este control es el complemento ideal para el TreeView. En el TreeView se presentaban datos
de forma jerárquica. Es el control ideal para presentar, por ejemplo, los departamentos de una
empresa u organismo.

Pero el TreeView solamente presenta un pequeño texto, acompañado generalmente de un


icono. Si seguimos hacia abajo por la estructura jerárquica del TreeView que muestra los
departamentos de un organismo, llegaremos al final a las personas. Y aquí ya será necesario
introducir más datos. Supongamos que estamos haciendo una lista de todas las personas, y
que la información de éstas será su nombre, puesto de trabajo, despacho que ocupa, teléfono,
etc. El TreeView no es control aconsejado para mostrar esa cantidad de datos. Estaría muy
bien poder mostrar todos los datos de esa persona en un control que también permita gráficos y
textos, de forma que el domicilio figure al lado de un icono con una casa, el teléfono al lado de
un icono con un teléfono, etc. Esto lo vamos a lograr mediante el TreeView.

El ListView puede presentar los datos de cuatro formas distintas:

- Iconos. Cada información se presenta con un icono y un texto. La posición de


los iconos puede cambiarse por el usuario. El texto puede editarse. Al
hacer clic sobre uno de los iconos, se produce el evento ItemClick en el
que podemos desencadenar otras operaciones tomando como dato el
icono sobre el que se ha hecho clic (presentar más datos, por ejemplo)
- SmallIcons (Iconos pequeños). Igual que el anterior, pero puede presentar más
iconos.
- Lista Presenta la información en líneas, acompañada de un icono. El texto de
cada línea puede editarse, pero no puede cambiarse el orden de las
líneas.
- Report (Informe) La información se divide en varios campos (SubItems) y se
presenta en columnas encabezadas por un texto indicativo.

Fig. 16.11 Las 4 formas de presentación del ListView: Iconos grandes, pequeños, Lista y Report

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 15


Propiedades del ListView
Propiedades Icons y SmallIcons

El ListView necesita DOS ImageList para almacenar los iconos. Uno para los iconos grandes y
otro para los iconos pequeños. Las imágenes en cada uno de ellos pueden (deben) ser las
mismas, con el mismo truco explicado para el TreeView: el de los iconos grandes con una
resolución de 32 x 32
y el de los iconos
pequeños con una
resolución de 16 x 16.
Esta propiedad puede
establecerse en
tiempo de diseño,
mediante el cuadro de
propiedades
personalizado, o en
tiempo de ejecución
mediante las
propiedades Icons y
SmallIcons
Fig. 16.12 Página de
propiedades del ListView mostrando los ImageList

ListView1.Icons = IMList1
ListView1.SmallIcons = IMList2

Las propiedades Icons y SmallIcons deben estar puestas antes de añadir elementos a la
colección ListItems del ListView. Si no es así, dará un error que dice que es necesario
inicializarlas.

Propiedad ListItems (Colección ListItems)

Esta propiedad es la equivalente a la propiedad Nodes del TreeView. Pero en este caso, un
elemento de esta colección no solamente contiene un dato, sino que además puede tener
dentro de sí otra colección de datos. Por ejemplo, pensando en una agenda, un elemento de la
colección puede tener como propiedad Text el alias de una persona, y como subitems de ese
elemento, el nombre y apellidos de la persona a la que se refiere el alias, su teléfono y su
domicilio. Un elemento de la colección ListItems puede tener tantos subitems como queramos.

Los elementos de la colección ListItems se añaden mediante el método Add, con la siguiente
sintaxis

NombreDelListView.ListItems.Add(índice, clave, texto, icono, iconoPequeño)

Donde

NombreDelListView es el nombre del ListView al que pertenece la colección ListItems


Indice es el índice de ese elemento. Comienzan por 1. No es obligatorio poner este parámetro,
y en ese caso, pone el número siguiente al mayor Index que tenga.
Clave Es una cadena de caracteres por la que se puede nombrar a ese elemento. Esta
cadena es única para cada elemento de la colección. Puede contener números, pero el
primer carácter debe ser una letra
Texto Es el texto que se va a ver en el ListView, bien solo, bien acompañado de un icono
Icono Es una cadena de caracteres con la propiedad Key, dentro del ImageList destinado a
los iconos grandes, del icono que queremos poner en ese elemento, cuando el
ListView está en modo de presentación Iconos grandes. También podemos poner aquí
el número del índice de ese icono dentro del mismo ImageList.
IconoPequeño Idéntica a la anterior, pero referida al icono mostrado cuando el ListView está
en modo de presentación de iconos pequeños.

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 16


Propiedades de la colección ListItems
La colección ListItems también tiene sus propiedades. Se enumeran a continuación las más
importantes.

Propiedad ListSubItems (Propiedad de la colección ListItems)


Una colección ListSubItems pertenece a cada uno de los elementos de la colección ListItems.
Cada ListItem puede tener varios ListSubItems, que son los elementos de información relativos
al ListItem del que dependen. Los ListSubItems se añaden a la colección mediante el método
Add, con la suguiente sintaxis:

ListView1.ListItems(1).ListSubItems.Add (Index, Key, Texto, ReportIcon, TextToolTip

Donde

ListView1 Es el nombre del control ListView


ListItems(1) Significa que ese ListSubItem se agrega al ListItem con Index = 1
Index Es el índice dentro de la colección ListSubItems
Key Es una cadena de caracteres que define a este ListSubIndex. Esta cadena de
caracteres debe ser única para cada elemento.
Texto Es la información que contienen ese ListSubItem
ReportIcon Es el Key del icono (dentro del ImageList que contienen los SmallIcons) que
aparecerá al lado del texto cuando el ListView está con la forma de
presentación Report (Informe).
TextToolTip Es la información que presentará en una etiqueta cuando acerquemos el
puntero del ratón sobre la zona donde está el texto.

Propiedad Ghosted (Propiedad)


Devuelve o establece un valor Booleano que determina si el icono de un objeto ListItem de un
control ListView aparece atenuado. Esta propiedad no afecta al funcionamiento normal de ese
ListItem, solamente es un efecto gráfico.

Sintaxis ListView.ListItems(5).Ghosted = True


Propiedad Selected

Devuelve un valor que determina si un elemento ListItem está seleccionado. Es una propiedad
solamente de lectura, por lo que no puede usarse para seleccionar un elemento.

Métodos de la colección ListItems

Add

Agrega nuevos elemento a la colección ListItems.

Sintaxis NombreDelListView.ListItems.Add(índice, clave, texto, icono, iconoPequeño)

Clear
Quita todos los objetos que hay en una colección.

Sintaxis ListView1.ListItems.Clear
Remove
Quita un miembro específico de una colección.

Sintaxis NombredelListView.ListItems.Remove Indice

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 17


Indice puede ser un número con la propiedad Index del elemento a quitar, o una cadena de
caracteres con su propiedad Key

CreateDragImage
Crea una imagen de arrastre con una versión difuminada de la imagen asociada a un elemento
de la colección ListImages. Normalmente, esta imagen se utiliza como DragIcon en las
operaciones de arrastrar y colocar.

Sintaxis ListView1.DragIcon = ListView.SelectedItem.CreateDragImage

EnsureVisible
Asegura que el objeto ListItem especificado sea visible.

Propiedades del control ListView (Continuación)

Propiedad Arrange
Establece cómo se organizan los iconos en la vista Iconos o Iconos pequeños de un control
ListView.

Sintaxis NombredelListView.Arrange = valor

Valor puede tomar uno de los siguientes valores o constantes

Constante Valor Efecto


LvwNone 0 Ninguna. Los iconos pueden colocarse arrastrándolos con el
ratón en cualquier parte del ListView.
LvwAutoLeft 1 Izquierda. Los elementos se alinean automáticamente a lo largo
de la parte izquierda del control.
LvwAutoTop 2 Superior. Los elementos se alinean automáticamente a lo largo
de la parte superior del control.

Propiedad Checkboxes
Establece si se muestran las casillas de verificación.

Sintaxis NombredelListView.Checkboxes = True / False

Propiedad ColumnHeaderIcons
Es similar a la propiedad Icons o SmallIcons, pero ésta se refiere al ImageList que contiene los
iconos que se van a poner en las cabeceras de las columnas (cuando está en vista Report)

Sintaxis NombredelListView.ColumnHeaderIcons = NombredelImageList

Puede ponerse también en tiempo de diseño (Fig. 16.12) en la casilla Encabezado de


Columnas

Propiedad ColumnHeaders (Colección CulumnHeader del control ListView)


La colección ColumnHeaders representa las columnas que tiene el ListView en el modo de
presentación Informe

El número de columnas del ListView debe ser igual al número de ListSubItems de cada
elemento ListItems. De esta forma, cada ListSubItem se presentará en una columna. Para
añadir columnas al ListView se usa el método Add aplicado a la colección ColumnHeaders

Sintaxis

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 18


ListView1.ColumnHeaders.Add Index, Key, TextoCabecera, Ancho, Alineamiento, Icono

Index Indice de esa columna


Key Cadena de caracteres única que identifica esa columna
TextoCabecera Texto que figurará en la cabecera de la columna
Ancho Ancho de la columna en unidades del Formulario que contiene al ListView
Alineamiento 0 = izquierda, 1 = Derecha, 2 = Centrado
Icono Key del icono a introducir en la cabecera de la columna

La colección ColumnHeaders tienen también sus propiedades y métodos. Vamos a citar las
más destacables:

Propiedades de la colección ColumnHeaders

Propiedad Alignment

Establece la alineación del texto en la cabecera de un ColumnHeader. Acepta 3 valores:


0 = izquierda, 1 = Derecha, 2 = Centrado

Sintaxis ListView1.ColumnHeaders(Indice). Alignment = Valor

Propiedad Position
Devuelve o establece la posición de una columna.

Sintaxis ListView1.ColumnHeaders(Index) = entero

Donde entero es un número entre 1 y n (n = número de columnas) que especifica la posición


de esa columna. Index es, o bien el índice, o el Key de la columna. Utilice esta propiedad para
reorganizar el orden de las columnas.

El control ImageCombo

Este control es un combo en el que se pueden introducir elementos. Estos elementos forman la
colección ComboItems. Cada elemento ComboItem puede tener un texto y una imagen. Este
combo presenta una enorme ventaja sobre el combo normal visto en capítulos anteriores: cada
elemento tiene una propiedad Index o Key que le distingue de los demás elementos, y se puede
utilizar una de esas dos propiedades para actuar sobre el programa, dependiendo del
ComboItem seleccionado. Tienen la misma apariencia que un combo normal.

Fig. 16.13 ImageCombo

Los elementos ComboItem se añaden con el método Add, que hemos visto en los controles
TreeView y ListView, con una sintaxis idéntica. No va a ser difícil para el alumno trabajar con
este control, una vez conocida la forma de trabajar con los dos controles citados anteriormente.

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 19


LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 20
Mas controles avanzados: El grupo de controles de Microsoft
Windows Common Controls-2 6.0 (SP3)
Estos son los controles integrados en el paquete Mscomct2.Ocx. Son cinco controles:

- MonthView
- Animation
- DTPicker
- UpDown
- FlatScrollBar

Control MonthView

El control MonthView permite crear aplicaciones donde los usuarios pueden elegir una fecha
mediante una interfaz parecida a un calendario.

Fig. 16.14 Control MonthView

Este control permite seleccionar de una forma muy sencilla


una fecha o un intervalo de fechas. Puede tener el aspecto
mostrado en la Fig. 16.14 o mostrar varios meses a la vez.
Esto puede lograrse mediante las propiedades MonthColumns
y MonthRows. Las fechas mínimas y máximas a presentar se
pueden establecer con las propiedades MinDate y MaxDate.

Este control está enlazado a datos. De esta forma puede


presentar un dato fecha hora existente en una base de datos.

Para permitir a los usuarios del programa seleccionar un intervalo continuo de fechas, asigne a
la propiedad MultiSelect el valor True y especifique con MaxSelProperty el número de días
que podrán seleccionar. Las propiedades SelStart y SelEnd devuelven las flechas del principio
y el final de una selección.
Existen muchas formas de personalizar la apariencia de un control MonthView. Existen varios
atributos de colores, como MonthBackColor, TitleBackColor, TitleForeColor y
TrailingForeColor, que le permiten crear combinaciones de colores exclusivas para el control.
Establezca las propiedades MonthRows y MonthColumns para mostrar más de un mes a la
vez (hasta 12 meses) en un control MonthView. El número total de propiedades MonthRows y
MonthColumns debe ser inferior o igual a 12.

Es un control enlazado a datos, por lo que puede presentar o introducir una fecha de una base
de datos a través de este control, previamente enlazado a la base de datos mediante un control
Data.

Propiedades del control MonthView


Propiedad Day
Devuelve o establece un valor numérico que especifica el número del día actual.

Sintaxis NombredelMonthView.Day = número


ó Variable = NombredelMonthView.Day

La propiedad Day puede tomar cualquier valor entero entre 1 y 31.

Propiedad DayBold
Devuelve o establece un valor Booleano que determina si la fecha indicada se muestra en
negrita

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 21


Sintaxis NombredelMonthView.DayBold(fecha) = True/False
La propiedad DayBold es una matriz que corresponde a la propiedad VisibleDays. Cada
elemento booleano indica si la fecha correspondiente debe mostrarse o no en negrita.
Son válidas únicamente las fechas mostradas actualmente. Las fechas válidas pueden
buscarse en la propiedad VisibleDays.
A medida que pasa de un mes a otro, no se conserva la información de la propiedad.

Propiedad DayOfWeek
Devuelve o establece un valor que especifica el día de la semana actual.

Sintaxis objeto.DayOfWeek = número

Los valores admitidos para número son:


Constante Valor Descripción
mvwSunday 1 (Predeterminado) Domingo
mvwMonday 2 Lunes
mvwTuesday 3 Martes
mvwWednesday 4 Miércoles
mvwThursday 5 Jueves
mvwFriday 6 Viernes
mvwSaturday 7 Sábado

La propiedad DayOfWeek puede tomar cualquier valor entero entre 1 y 7.

Propiedaddes MaxDate, MinDate


Devuelve o establece la primera y la última fecha permitida por el calendario.
Sintaxis objeto.MaxDate = fecha
objeto.MinDate = fecha

La propiedades MaxDate y MinDate sirven para definir los límites superior e inferior del
calendario.

Propiedad MaxSelCount
Devuelve o establece el número máximo de días consecutivos que se pueden seleccionar de
una vez.

Sintaxis objeto.MaxSelCount = número

Obviamente esta propiedad solamente tiene sentido cuando la propiedad MultiSelect tiene el
valor True. Además, el valor asignado a la propiedad MaxSelCount debe ser superior a la
diferencia entre las propiedades SelStart y SelEnd. Por ejemplo, si selecciona el periodo del
15/9 al 18/9, MonthView.SelEnd - MonthView.SelStart = 3. Sin embargo, son cuatro los días
seleccionados realmente, por lo que MaxSelCount debe tener asignado el valor 4.
El valor predeterminado de la propiedad es una semana (7 días).

Propiedad Month
Devuelve o establece un valor que especifica el mes actual.

Sintaxis objeto.Month = número

Valores admitidos.

La propiedad Month puede tomar cualquier valor o constante de las expresadas en la tabla
siguiente:

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 22


Los valores admitidos para número son:
Constante Valor Descripción
mvwJanuary 1 Enero
mvwFebruary 2 Febrero
mvwMarch 3 Marzo
mvwApril 4 Abril
mvwMay 5 Mayo
mvwJune 6 Junio
mvwJuly 7 Julio
mvwAugust 8 Agosto
mvwSeptember 9 Septiembre
mvwOctober 10 Octubre
mvwNovember 11 Noviembre
mvwDecember 12 Diciembre

Propiedad MonthBackColor
Devuelve o establece un valor que especifica el color de fondo mostrado para un mes.

Sintaxis objeto.MonthBackColor = color

Color es una variable numérica Long comprendida entre el entre 0 y 16.777.215, o la expresión
del color mediante el esquema de color RGB.

Propiedades MonthColumns, MonthRows


Devuelve o establece un valor que especifica el número de meses que se muestran en sentido
horizontal o vertical.

Sintaxis objeto.MonthColumns = número


objeto.MonthRows = número

El control puede mostrar hasta doce meses.

Proiedad MultiSelect
Devuelve o establece un valor que determina si es posible realizar una selección múltiple de
fechas.

Sintaxis objeto.MultiSelect = booleano

Los valores admitidos para booleano son:


True: Permite seleccionar múltiples días (Predeterminado)
False: permite seleccionar solamente un día

Propiedad Parent
Devuelve el formulario, objeto o colección que contiene un control u otro objeto o colección.

Sintaxis objeto.Parent

Utilice la propiedad Parent para tener acceso a las propiedades, los métodos o los controles del
primario de un objeto. Por ejemplo:

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 23


MiBotón.Parent.MousePointer = 4

Propiedad ScrollRate
Devuelve o establece un valor que especifica el número de meses que se desplazará cuando el
usuario haga clic en uno de los botones de desplazamiento. La propiedad ScrollRate permite al
usuario realizar desplazamientos de más de un mes cada vez.

Propiedad ShowToday
Devuelve o establece un valor Booleano que determina si se muestra la fecha actual en la parte
inferior del control.

Propiedades SelEnd, SelStart


Devuelve o establece los límites inferior y superior del intervalo de fechas seleccionado.

Sintaxis objeto.SelEnd = fecha


objeto.SelStart = fecha

Las propiedades SelStart y SelEnd definen el límite inferior y superior del intervalo de fechas
seleccionado. El intervalo de fechas seleccionado puede abarcar varios meses. Es posible
incluir fechas que no están visibles actualmente.
Para que la selección múltiple de fechas funcione correctamente, asigne a la propiedad
MaxSelCount un valor superior a la diferencia de los valores de las propiedades SelStart y
SelEnd.
Los valores SelStart y SelEnd sólo son válidos cuando la propiedad MultiSelect tiene el valor
True.

Propiedad ShowWeekNumbers
Devuelve o establece un valor que determina si los números de semana aparecen junto a la
semana.

Sintaxis objeto.ShowWeekNumbers = booleano

Propiedad StartOfWeek
Devuelve o establece un valor que especifica el primer día de la semana.

Sintaxis objeto.StartOfWeek = entero

Los valores admitidos para entero son iguales que para la propiedad DayOfWeek

Propiedades TitleBackColor, TitleForeColor


Devuelven o establecen valores que especifican los colores de fondo y primer plano del área de
título del control.

Sintaxis objeto.TitleBackColor = color


objeto.TitleForeColor = color

Utilice las propiedades TitleBackColor y TitleForeColor con las propiedades


MonthBackColor y TrailingForeColor para personalizar los colores del control.

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 24


Propiedad TrailingForeColor
Devuelve o establece un valor que especifica el color de primer plano de las fechas restantes
visibles actualmente.

Sintaxis objeto.TrailingForeColor = color

Propiedad Value
Devuelve o establece la fecha que se muestra actualmente. El valor devuelto es de tipo Date

Sintaxis objeto.Value = fecha


VariableTipoDate = Objeto.Value

La propiedad Value es la propiedad por defecto.

Propiedad Week
Devuelve o establece un valor que especifica el número de la semana actual.

VariableNumerica = NombredelControl.Week
NombredelControl.Week = VariableNumerica

La propiedad Week puede tomar cualquier valor entero entre 1 y 52.

Propiedad Year
Devuelve o establece un valor que especifica un año de calendario.

VariableNumerica = NombredelControl.Year
NombredelControl.Year = VariableNumerica

Es posible asignar a la propiedad Year cualquier entero comprendido entre 1601 y 9999.

DataBindings, DataChanged, DataField, DataFormat, DataMember, DataSource,

Métodos del control MonthView


Método ComputeControlSize
Devuelve el ancho y el alto de un control MonthView para un número determinado de filas y
columnas.

Sintaxis objeto.ComputeControlSize(Rows, Columns, Width, Height)


Este método se utiliza antes de cambiar el tamaño del control MonthView restableciendo sus
propiedades MonthColumns o MonthRows, para ajustar el tamaño del formulario si fuese
necesario.
Para usar el método ComputeControlSize, declare primero dos variable con tipo Single. A
continuación, llame al método pasando como argumentos las variables Width y Height. Una vez
ejecutado el método podrá obtener el ancho y el alto del control leyendo estas variables.

Método HitTest
Devuelve la fecha ubicada en conjunto de coordenadas determinado. Se suele usar en
operaciones de arrastrar y colocar para determinar si existe un elemento en la ubicación de
destino de la operación.

Sintaxis objeto.HitTest(x as Single, y As Single, Date As Date)

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 25


Mediante el método HitTest puede obtener una fecha del control MonthView simplemente
haciendo clik encima de ella. El método HitTest devuelve Null si no existe ninguna fecha en las
coordenadas especificadas.

Private Sub MonthView1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As


Single)
Dim FechaElegida As Date
MonthView1.HitTest X, Y, FechaElegida
LabelFecha = FechaElegida
End Sub

Eventos del control MonthView

DateClick (Evento)
Ocurre cuando se hace clic en una fecha del control.

Private Sub objeto_DateClick([Index As Integer], DateClicked As Date)

Se utiliza este evento para determinar la fecha en la que se hizo clic.

Private Sub MonthView1_DateClick(ByVal DateClicked As Date)


LabelFecha = MonthView1.Value
End Sub

Private Sub MonthView1_DateClick(ByVal DateClicked As Date)


LabelFecha = DateClicked
End Sub

DateDblClick (Evento)
Ocurre cuando el usuario hace doble clic en una fecha del control.

Private Sub objeto_DateDblClick([Index As Integer], DateDblClicked As Date)

Tiene la misma aplicación que la anterior, pero esta vez haciendo doble click

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 26


Control DTPicker1
Este control es una especie de ComboBox, pero en vez de mostrar cuando está expandido una
lista, muestra el control MonthView. Funciona de forma análoga al MonthView, y cuando
seleccionamos una fecha en el calendario, deposita la fecha en la casilla desplegable y se
cierra. Este control nos permite ahorrar un buen espacio en el formulario sin perder
prestaciones. Estas son las formas de presentarse recogido y ampliado.

Se deja al alumno el estudio exahustivo de este control, que no se separa mucho del
MonthView visto anteriormente.

Control Animation
Este control nos permite introducir en nuestra aplicación un elemento muy elegante:
visualización de ficheros .avi Existen en Windows muchos fichero .avi aplicados para distintas
funciones: copiar ficheros, bajar ficheros de Internet, y otros empleados como elemento
tranquilizador en procesos lentos. Veamos un par de ejemplos:

Para probar este control basta con poner un controlen el


formulario, un CommonDialog (CD1) y dos botones, uno
para arrancar y otro para parar la presentación del fichero
avi. El tamaño que se le de en el formulario debe ser
suficientemente grande para que quepa la presentación en
su tamaño real. No acepta zoom.

En el procedimiento click del botón de arrancar basta con poner este código:

CD1.Filter = "avi (*.avi)|*.avi"


CD1.ShowOpen
With Animation1
.Open CD1.FileName
.Play
End With

Para parar la ejecución:


Animation1.Stop

El control Animation tienen pocas propiedades distintas de los demás controles. Podemos citar
estas:

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 27


Propiedad Center
Establece si el fichero .avi se presenta en el centro del control (Center = True) o si se presenta
en las coordenadas 0,0 del mismo (Center = False)

Propiedad AutoPlay
Devuelve o establece un valor que determina si el control Animation empezará a reproducir un
archivo .avi cuando éste se cargue en el control.

Métodos del control Animation

Play Ejecuta la animación.


Stop Detiene la animación. No se puede ejecutar este método si la propiedad AutoPlay está
a True.

Control UpDown
Este control sirve para introducir saltos de un paso en otros controles o en cualquier
parte del código de la aplicación.

Este control es tan sencillo que no se va a explicar. Solamente citar que sus dos
procedimientos más importantes son el DownClick y el UpClick

Control FlatScrollBar
Es un control de scroll. Tiene como todos los
controles de este tipo, una propiedad Max para darle
el valor máximo, Min para ajustar el valor mínimo,
SmallChange y LargeChange para fijar las variaciones al hacer click en la fkecha o en el cuerpo
respectivamente, y unna propiedad Value para leer el valor actual.

Solamente tienen el procedimiento Scroll que se produce al variar la posición del cursor.

Dejamos aquí el estudio de controles avanzados. No es que no haya más, sino que el curso
debe tener un final. Para conocer a fondo los controles lo mejor es tomar un control de la lista
que sale del menú de VB Proyecto | Componentes, y ponerse con el. No voy a decir que sea
más fácil que estudiarlos con la ayuda de la Guía del Estudiante. Eso sí, le va a resultar
bastante más divertido. Le recomiendo que si estudia a fondo algún control interesante para
Vd. apunte todo lo que vaya aprendiendo de él. Por experiencia puedo decirle que se olvida.
Créese su propia Guía del Estudiante. A final de cuentas esta comenzó así y ya va bastante
adelantada.

LSB Visual Basic Guía del Estudiante Capitulo 16 Pág. 28


Visual Basic Guía del Estudiante Capítulo 17
Funciones API de Windows
Las APIs de Windows son un serie de funciones que Windows tienen implementadas al servicio
del programador. Estas funciones se llaman API (Interfaz para Programación de Aplicaciones)
y están en las innumerables DLLs que tiene Windows. Las APIs tienen la virtud de acceder a
partes de la máquina o del sistema operativo a las que no podríamos acceder mediante Visual
Basic. Las APIs pertenecen como decíamos a Windows, por lo que pueden ser usadas por
programas escritos en cualquier lenguaje de programación. Es muy interesante utilizarlas, pues
reducen el tamaño del programa ejecutable frente a otras posibilidades con controles, aparte
de darle mayor rapidez de ejecución, al tratarse de código ya compilado.

Dado que este libro tiene lógicamente un alcance limitado, y el tema de APIs es enorme, se
recomienda recurrir a un libro específico de APIs. Este no puede ser otro que el siguiente :

TITULO API de Win32. Guía del Programador de Visual Basic


AUTOR Daniel Appleman. Editorial InforBooks - Barcelona
ISBN 84-89700-22-2
Citaremos este libro repetidas veces a lo largo de este capítulo.

Daniel Appleman es el fundador de Desaware Inc. http://www.desaware.com/ Su página es


visita obligada.

Nota introducida en el 2001 - Aparte de este libro, existe un recurso en Internet que incluso le
supera, y que tiene la gran ventaja de que se trata de un sistema informático donde puede
copiar y pegar código. Puede encontrarlo en http://www.allapi.net/
Desde que lo he descubierto he dejado el Libro de Appleman un poco aparcado. Sin embargo
las explicaciones aportadas en ese libro son difícilmente sustituibles.

Para usar una función API lo primeros que tenemos que hacer es declararla en nuestra
aplicación. La declaración debe hacerse en la sección de declaraciones de un formulario o
módulo. Si la declaramos en un formulario, necesariamente debemos declararla como privada.

Una declaración sencilla podría ser la de la función API Sleep :

Declare Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)

Aquí se ha declarado como pública. Es lo mismo que decir:

Public Declare Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)

En un formulario no se puede declarar como pública. Deberemos poner

Private Declare Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)

En esta declaración lo que le estamos diciendo es que, en la librería kernel32 está escrita una
función llamada Sleep (Es el nombre que figura entre comillas en la declaración) y que le
tenemos que pasar un parámetro, el tiempo que queremos que se pare la ejecución de la
aplicación, expresado en milisegundos. Nos dice la declaración que el parámetro se le pasa
Por Valor (ByVal) y que ese dato debe ser un Long, es decir, si se lo pasamos como una
variable, esa variable debe ser del tipo Long. Una vez declarada esta función, en la sección de
declaraciones de un módulo o de un formulario, podremos acceder a ella en cualquier parte de
la aplicación (las partes de la aplicación donde se puede usar dependerá del ámbito de la
declaración, que es idéntica que para las variables) usando una línea de código como esta :

Sleep (500) y la aplicación se detendrá medio segundo cuando llegue a esa línea

ó Sleep (tiempo) donde tiempo es una variable tipo Long que contiene el tiempo (en
milisegundos) que queremos detener el programa.

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 1


Esta API es muy sencilla. Por eso comenzamos por ella. La hay mas complicadas. Por ejemplo,
la que obtiene el número de serie del disco duro : GetVolumeInformation

Declare Function GetVolumeInformation Lib "kernel32" Alias "GetVolumeInformationA" (ByVal _


lpRootPathName As String, ByVal lpVolumeNameBuffer As String, ByVal nVolumeNameSize _
As Long, lpVolumeSerialNumber As Long, lpMaximumComponentLength As Long, _
lpFileSystemFlags As Long, ByVal lpFileSystemNameBuffer As String, ByVal _
nFileSystemNameSize As Long) As Long

Aquí ya se ha complicado un poco la cosa. Pero tras un análisis detenido veremos que esa
complicación es sólo aparente.

En primer lugar vemos que la librería donde está esta función es, como en la función Sleep, el
kernel32 . Esto quiere decir que la librería kernel32 contiene varias funciones. Pero ¿qué es la
librería kernel32 ? Ni mas ni menos que una DLL llamada kernel32.dll que puede encontrar en
el directorio C :\WINDOWS\SYSTEM, y que es el alma de Windows. (Kernell significa, como
muy bien sabrá, núcleo)

En segundo lugar, vemos que el nombre de esta función dentro de la DLL kernel32.dll es
GetVolumeInformationA, que es lo que figura entre comillas en la declaración. El nombre
GetVolumeInformation que figura como nombre de la función, al principio de la declaración,
es el nombre por el que nos vamos a referir a la función en nuestra aplicación. Ese nombre
puede cambiarse, cambiando también el nombre con el que vamos a llamar a esta función a lo
largo de nuestra aplicación. Esto se lo digo solamente a nivel informativo. No lo haga. Su
aplicación no podría ser interpretada por otra persona. No es profesional y quien mas perderá
por ello es Vd. Le hago especial hincapié en esto, porque es una forma de proteger sus
programas por parte de algunos programadores. Pero un analista experto encuentra enseguida
el truco. Y algunos no perdonan. Seamos profesionales

En tercer lugar, vemos que la declaración de esta función termina con la expresión As Long.
Esto significa que esta función devuelve un dato, y es concretamente, un Long. Por lo tanto, si
ese dato nos sirve para algo, podemos obtenerlo. Verá que no es necesario, pero en muchas
ocasiones, ese dato nos va a indicar si la función se ejecutó correctamente. Concretamente,
esta función devuelve un 0 si ha existido algún problema para obtener el número del disco, o
un número distinto de 0 si lo ha obtenido. Las demás constantes deberemos declararlas en el
procedimiento donde vamos a usar la función (o en otro lugar, si así lo exige el ámbito que les
queramos dar, pero generalmente, en el mismo procedimiento), e invocar la función pasándole
los parámetros correctos.

La sintaxis de las Apis va a ser distinta si deseamos obtener el valor que devuelve o no. Por
ejemplo, para la función anterior podemos poner perfectamente estas dos expresiones

Dim Respuesta as Long


Respuesta = GetVolumeInformation("C:\", volbuf, 255, serialnum, componentlength, sysflags, _
sysname, 255)

GetVolumeInformation("C:\", volbuf, 255, serialnum, componentlength, sysflags, _


sysname, 255)

En el ejercicio realizado para hacer estos apuntes, este código se metió en el procedimiento
click de un botón de comando.

‘Declaramos las variables. Observe que no tienen por qué tener el mismo nombre que en la
‘declaración de la función.

Dim volbuf As String


Dim sysname As String

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 2


Dim serialnum As Long ‘esta variable será la que contenga el número del disco
Dim sysflags As Long ‘lpFileSystemFlags
Dim componentlength As Long ‘lpMaximumComponentLength
Dim res As Long
volbuf = String(256, 0)
sysname = String(256, 0)

Estas variables son las que se van a pasar como parámetros a la función. La correspondencia
entre el nombre del parámetro y cada una de las variables es la siguiente :

lpRootPathName Se lo metemos directamente : “C :\” - no olvidar la barra \


lpVolumeNameBuffer volbuf Label del disco
nVolumeNameSize Tamaño del buffer anterior. Directamente 255
lpVolumeSerialNumber serialnum. Contendrá el número del disco
lpMaximumComponentLength componentlength
lpFileSystemFlags sysflags
lpFileSystemNameBuffer sysname
nFileSystemNameSizeTamaño buffer anterior. Directo, 255

res = GetVolumeInformation("C:\", volbuf, 255, serialnum, componentlength, sysflags, _


sysname, 255)

If res = 0 Then ' ha ocurrido un error y no puede leer el VOL


MsgBox ("Ha ocurrido un error al intentar arrancar la aplicación.")
Else 'lo ha leído perfectamente
VOLUM = Trim(Str(serialnum)) 'convertimos un Long en String
'si tiene menos de 12 caracteres, le añadimos los ceros necesarios por la izquierda
If Len(VOLUM) < 12 Then VOLUM = String(12 - Len(VOLUM), "0") & VOLUM
' lo presentamos en el TextBox TBVOL
TBVOL.Text = VOLUM
End If

Repasemos la declaración y veamos que es cada una de sus partes

Función GetVolumeInformation
Declare Function GetVolumeInformation Lib "kernel32" Alias "GetVolumeInformationA" (ByVal
lpRootPathName As String, ByVal lpVolumeNameBuffer As String, ByVal nVolumeNameSize
As Long, lpVolumeSerialNumber As Long, lpMaximumComponentLength As Long,
lpFileSystemFlags As Long, ByVal lpFileSystemNameBuffer As String, ByVal
nFileSystemNameSize As Long) As Long

lpRootPathName
Es un string que contiene el directorio raíz del disco a analizar. Si es te parámetro es Null, se
toma el directorio raíz del directorio actual. Esta parámetro puede indicar el disco de un
servidor, en cuyo caso debe indicarse con dos backslash. (\\Servidor\Disco)

lpVolumeNameBuffer
Apunta a una variable que va a recibir el nombre del Label del disco. Hay que declararla con un
tamaño predeterminado, siempre mayor que el que va a tener el dato
p.e. Dim VolBuf As String * 255

nVolumeNameSize
Especifica la longitud de la variable anterior. No importa que la hayamos declarado ya con
determinado tamaño. Hay que poner aquí otra vez ese tamaño, que será el mismo que tenía
declarado la variable.

lpVolumeSerialNumber
Apunta a una variable tipo Long, donde se va a meter el número del disco.

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 3


lpMaximumComponentLength
Apunta a una variable Long (En realidad se mete en esta variable el resultado de la
concatenación de dos bytes) donde se va a poner el número máximo de caracteres permitido
por el sistema de ficheros. Eeste número de caracteres corresponde con los caracteres
comprendidos entre dos backslahs. Si ese valor es 255 indica que el sistema de ficheros
soporta nombres largos. Si indica 8.3 solamente acepta nombres cortos

lpFileSystemFlags
Apunta a una variable tipo Long, (Igual que la anterior, concatenación de dos bytes) que
especifican los Flags asociados al sistema de ficheros. Puede ser la combinación de dos de los
siguientes parámetros (Excepción: FS_FILE_COMPRESSION y FS_VOL_IS_COMPRESSED
son mutuamente excluyentes).
FS_CASE_IS_PRESERVED
If this flag is set, the file system preserves the case of filenames when it places a name on disk.
FS_CASE_SENSITIVE
El sistema de ficheros diferencia mayúsculas y minúsculas.
FS_UNICODE_STORED_ON_DISK
FS_PERSISTENT_ACLS
FS_FILE_COMPRESSION
FS_VOL_IS_COMPRESSED
El disco especificado se trata de un disco comprimido. Por ejemplo, es un disco al que se le ha
aplicado DoubleSpace.

lpFileSystemNameBuffer
Apunta a una variable tipo string, donde se mete el sistema de ficheros soportado (FAT or
NTFS). Esta variable debe declararse con un número prefijado de caracteres, siempre superior
al que vaya a tener realmente (p.e. Dim SysName As String * 255)

nFileSystemNameSize
Especifica el número de caracteres de la variable anterior. Debe introducirse el mismo número
con el que se ha declarado la longitud de esa variable. (255 en el ejemplo).

Ya vamos viendo que las APIs no son tan difíciles de entender. Vamos a ver otra, la inversa de
la anterior, que pone el valor al parámetro Label del disco. Observe que el resto de los
parámetros no pueden variarse ya que vienen marcados en el disco (número) o implícitos en el
sistema operativo.

Función SetVolumeLabel
Private Declare Function SetVolumeLabel Lib "kernel32" Alias "SetVolumeLabelA" (ByVal
lpRootPathName As String, ByVal lpVolumeName As String) As Long

lpRootPathName
Variable tipo string donde se introduce el directorio raíz del disco al que se le va a poner o
cambiar el Label. Si este parámetro es Null, se entiende que es el raíz del directorio actual.

lpVolumeName
Variable tipo string que contienen el Label a poner. Si es Null, borra el Label actual.

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 4


Vemos que no es tan complicado operar con funciones API. Para trabajar con APIs solamente
es necesario conocer la sintaxis exacta de la declaración. Pero parece en principio un poco
difícil, a sabiendas de que deben existir varios cientos de APIs. SOLUCION : Que VB nos
aporte un chuleta con todas las declaraciones.

Esta chuleta no es otro que el Visor de Texto API (API Text Wiever en Inglés). Este es un
programa que se distribuye con Visual Basic y que se instala al tiempo que este, formando
parte del mismo grupo de programas. Haciendo clic en su icono aparece esta ventana :

Haciendo Click sobre la palabra Archivo de la Barra de Menú, aparecen unos ficheros que
contienen las declaraciones de las funciones API :

Win32Api.txt
Winmmsys.txt

Estos dos ficheros son los que suministra Microsoft con VB6. El primero contiene las
declaraciones de las funciones API no relacionadas con el tema multimedia. El segundo
contiene las declaraciones de las API relacionadas con este tema de multimedia.

Si ha adquirido el libro de Appleman puede tener otro fichero : Api32.txt. El autor de este libro
asegura que es mucho mas completo que el fichero que entrega Microsoft. De hecho contiene
bastantes mas declaraciones.

API-Guide presenta también la declaración del API para ser copiada directamente
en el portapapeles y pegada en nuestra aplicación. Últimamente es la única que
uso, ya que al tiempo, se obtienen una explicación de cada uno de los parámetros.

Estos ficheros están en ASCII. Puede convertirlos a una base de datos ACCESS y el acceso
será un poco más rápido. No olvide que también le ocupará un sitio respetable en el disco duro
de su ordenador.

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 5


Para obtener una o varias declaraciones, seleccione las funciones en la ventana de arriba del
visor, haga click en Agregar y esa función le pasará para la ventana de abajo. Una vez que
tenga en esa ventana todas las funciones que necesita, haga click en el botón Copiar y las
declaraciones completas le pasarán al portapapeles.

Una vez que ya sabemos donde se pueden copiar las declaraciones de las APIs, veamos una
que nos permitirá obtener la hora desde el sistema operativo :

Declare Sub GetSystemTime Lib "kernel32" Alias "GetSystemTime" (lpSystemTime _


As SYSTEMTIME)

Ahora nos surge una duda ¿Qué es SYSTEMTIME ? Es una variable que hay que declararla
con la instrucción Type, igual que hacíamos con las variables con varios campos en los
ficheros tipo Random. Repase este capítulo si no lo tiene claro.

Para poder declarar esta variable, podemos obtener su declaración del mismo Visor de Texto
API

Para ello, en la ventana Tipo API en vez de figurar Declaraciones debe poner Tipos. Busque
esta opción desplegando la ventana con la flecha que tiene a la derecha. Busque ahora la
variable cuya declaración quiere conocer. Repitiendo el proceso anterior, se llevará en el
portapapeles la declaración de la variable :

Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type
Haga un pequeño ejercicio para obtener la fecha y hora usando un API :

Para ello debemos introducir un módulo donde definiremos la variable SYSTEMTIME y donde
podemos declarar la función GetSystemTime :

Módulo 1 Declaraciones

Option Explicit
Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type

Declare Sub GetSystemTime Lib "kernel32" (lpSystemTime As SYSTEMTIME)

Ahora en un Formulario, ponemos 8 TextBox (uno para cada datos) y un botón de comando,
donde ponemos el siguiente código:

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 6


Private Sub Command1_Click()
Dim Pepe As SYSTEMTIME ‘Pepe es una variable del tipo SYSTEMTIME
GetSystemTime Pepe
Text1 = Str(Pepe.wYear)
Text2 = Str(Pepe.wMonth)
Text8 = (Pepe.wDayOfWeek)
Text3 = Str(Pepe.wDay)
Text4 = Str(Pepe.wHour)
Text5 = (Pepe.wMinute)
Text6 = (Pepe.wSecond)
Text7 = (Pepe.wMilliseconds)
End Sub

Este programa nos mostrará la hora (hasta milésimas de segundo), la fecha y el día de la
semana.

Aún queda otro apartado en la ventana Tipo API : Las constantes.

En muchas declaraciones de funciones API se utilizan constantes, bien numéricas o


expresiones. El Visor de testo API nos muestra también las constantes que nos podemos
encontrar en las declaraciones. Vayan un par de Ejemplos

Public Const SCROLLLOCK_ON = &H40 ' The scrolllock light is on.


Public Const SE_ASSIGNPRIMARYTOKEN_NAME = "SeAssignPrimaryTokenPrivilege"

Verá más adelante mucho más profusamente las declaraciones de constantes.

Vamos a entretenernos a lo largo de este capítulo, en el estudio de varias APIs, relacionadas


con el registro de Windows y con la presentación del icono en el System Tray. Se han puesto
estas porque son interesantes unas y llamativas las otras. Pero no son las más importantes, ni
las más difíciles. La más importante es la del día a día, que es la que nos va a proporcionar la
solución de nuestro programa. La más difícil siempre está por llegar.

Cuando necesite un API nuevo para su programa no se conforme con salir del paso. Eso se
logra con el libro de Appelman o con el API-Guide. Por experiencia propia, le recomiendo que
haga una pequeña aplicación para emplear esa o esas APIS que necesita. Estúdielas,
documéntelas y guárdelas donde guarda sus tesoros más preciados. Hágalo, pues al cabo de
una año sin volver a usarlas se le van a olvidar, y tendrá que ponerse nuevamente al día. Hay
APIs caprichosas, declaraciones que tienen que ser así, sin ninguna razón ni criterio para ello.
No duplique su trabajo. Créese una libreta de APIs y con el tiempo, llegará a dominarlas como
el mismísimo Appleman. Por mi parte, dejo como botón de muestra las que presento a
continuación.

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 7


APIS DE WINDOWS Función Shell_NotifyIcon
Cómo presentar el icono de una aplicación en la zona de acceso rápido de la barra de tareas
(System Tray)

La zona de acceso rápido de la barra de tareas es la parte derecha de esta barra en la que se
encuentra el reloj. En el inglés original se denomina System Tray, y no encuentro en español
una palabra del argot informático que la defina.

Es muy cómodo, sobre todo para los programas que se deben estar ejecutando continuamente,
poner su icono en esta parte de la barra de tareas, ya que ocupan menos espacio que un
programa minimizado normalmente. Solamente se ve el icono representativo del programa.
Por ello es necesario elegir un icono que defina de forma sencilla e inequívoca la aplicación.
Generalmente se le pone un PopUp menú que muestra las opciones de restaurar (Muestra la
aplicación en su tamaño normal) y Salir. También se suele poner un TextToolTip para mostrar
de forma literal el nombre del programa minimizado en ese icono.

Fig. 1 - Icono del programa Wsk colocado en el System Tray con su ToolTipText y PopupMenú

Este sistema permite comunicar la aplicación con el icono creado en el System Tray.
Lógicamente, primero debe crearse el icono (Se crea normalmente en el Load del formulario
inicial de la aplicación), y permanece ahí mientras dura la ejecución de la aplicación. Si se
minimiza la aplicación, no aparece su icono en la barra de tareas. Por lo tanto se necesitará
algún artilugio para poder poner otra vez la aplicación en su estado normal. Esto se hace
mediante una comunicación entre el icono del System Tray y la aplicación. Esa comunicación
es lo que llamaremos mensaje de retorno. Al recibir ese mensaje de retorno, el formulario va a
tratarlo en uno de sus procedimientos. El procedimiento donde lo va a tratar se le especifica en
la llamada a la API como se verá mas adelante. El mensaje de retorno va a depender de lo
que se haga sobre el icono del System Tray, (Tecnología Windows) y es en principio un poco
complicado, pero verá también más adelante una breve explicación sobre este valor devuelto.
Para que el icono no siga en el System Tray una vez hayamos salido de la aplicación, es
necesario eliminarlo en el procedimiento Unload del formulario inicial.

El icono puede cambiarse en tiempo de ejecución, y es una de las aplicaciones más vistosas
de este sistema. Puede, por ejemplo, cambiar el color del icono para indicar que se ha recibido
un mensaje, que se está conectado, etc.

El API encargada de realizar esta función es Shell_NotifyIcon, cuya declaración es:

Public Declare Function Shell_NotifyIcon Lib "shell32" _ Alias "Shell_NotifyIconA" _


(ByVal dwMessage As Long, pnid As NOTIFYICONDATA) As Boolean

Vemos que la declaración incluye una variable definida por el usuario: NOTIFYCONDATA. Se
define de esta forma

Public Type NOTIFYICONDATA


cbSize As Long
hwnd As Long
uId As Long
uFlags As Long
uCallBackMessage As Long
hIcon As Long
szTip As String * 64
End Type

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 8


El primer parámetro que se le pasa a la función (dwMessage) le va a indicar la operación que
debe realizar, y puede tomar uno de los tres siguientes valores (Se indica también el nombre
de la constante que suele sustituir a esos valores):

Constante Valor Operación que realiza


NIM_ADD 0 Añade un icono al System Tray
NIM_MODIFY 1 Cambia el icono actual por otro
NIM_DELETE 2 Quita el icono del System Tray

El segundo parámetro (pnid) es una variable tipo NOTIFYICONDATA tal como se definió más
atrás. Vemos a continuación cada componente de esta variable:

CbSize Contiene el tamaño de la variable pnid. Generalmente se le pasa este valor


mediante la función Len aplicada a la propia variable. (Vea ejemplo)

Hwnd Es el controlador de la ventana sobre la que se va a aplicar la función


Shell_NotifyIcon. Si el código donde se llama a esta función está en el
formulario que se va a minimizar o restaurar, en esta parte basta con poner
Me.Hwnd.

UId Es el identificador del icono del System Tray. Puede ser cualquier número
Long. Solamente será necesario usar un número si hace falta identificar ese
icono para una operación posterior. Si no se va hacer ninguna operación con él,
caso más habitual, basta con poner vbNull como valor de esta parte.

UFlags Un Long que va a indicar la validez de las tres partes siguientes de la variable
NOTIFYICONDATA. (uCallBackMessage, hIcon y szTip) Puede tomar uno de
estos valores (Se especifica el valor, la constante con la que se le suele
denominar y el resultado de usarla):

Constante Valor Resultado


NIF_MESSAGE 1 El identificador del mensaje de retorno será el
especificado en uCallBackMessage
NIF_ICON 2 El icono que se pone en el System Tray es el
que se le indica en hIcon.
NIF_TIP 4 El ToolTipText del icono del System Tray será
el especificado en szTip.

Uflags puede contener los tres valores, validando de esta forma las tres condiciones anteriores.
Es muy tipico ver que UFlags toma el valor:

.uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE

Lo que estamos haciendo es que Uflags tome el valor de 2 Or 4 Or 1, siendo Or el operador


lógico Or. Esta operación nos lleva al resultado de 7.

Resumiendo: Uflags es en realidad un conjunto de tres banderas, que puede tomar el valor 1, 3
ó 7, según se haya aplicado NIF_MESSAGE (Pesa 1), NIF_ICON (Pesa 2) y NIF_TIP (Pesa 4)

uCallBackMessage Identificador del mensaje de retorno. Este valor va determinar en que


procedimiento del formulario se va a procesar la información enviada
desde el icono. Si pone el valor Hexadecimal 200 (&H200) ese valor
enviado se procesará en el procedimiento MouseMove. Puede hacerlo
en otros. Puede ver en la siguiente lista el número que define a varios
procedimientos del formulario, y la constante con la que se definen
normalmente

El valor del mensaje de retorno va a depender de lo que se haga sobre


el icono del System Tray. Y es concretamente, el valor que

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 9


corresponde al evento que se realice sobre el icono (Mouse down,
Mouse Up, doble clic, etc) según los valores de la tabla siguiente. Eso
sí, estos valores se multiplican por el valor de la propiedad
TwipsPerPixelX del objeto Screen. Insisto, tecnología Windows que
queda fuera de este manual de Visual Basic.

Los valores de la siguiente tabla son aplicables para establecer en que


procedimiento va a procesar la información del mensaje de retorno,
como para conocer el valor de ese mensaje.

Constante Valor Procedimiento del formulario


WM_MOUSEMOVE &H200 MouseMove
WM_LBUTTONDOWN &H201 Mouse Down (botón izquierdo)
WM_LBUTTONUP &H202 MouseUp (botón izquierdo)
WM_LBUTTONDBLCLK &H203 Doble click (botón izquierdo)
WM_RBUTTONDOWN &H204 MouseDown (botón derecho)
WM_RBUTTONUP &H205 Mouse Up (botón derecho)
WM_RBUTTONDBLCLK &H206 Doble click (botón derecho)

HIcon Icono que presentará en el System Tray. Es muy normal poner el icono
del formulario inicial de la aplicación. Si el código de creación del icono
está es ese formulario (cosa muy normal) basta con poner aquí,
Me.Icon
SzTip Aquí debe poner el ToolTipText que quiere que aparezca cuando
mantiene el cursor del ratón unos instantes sobre el icono del System
Tray.

En la definición del la variable NOTIFYICONDATA se establecía que la longitud de SzTip era


de 64 caracteres (szTip As String * 64) No intente cambiar ese 64 por otro número porque no
funciona. Esto nos lleva a que si la cadena elegida para el ToolTipText no tiene 64 caracteres,
aparecerán unos espacios en blanco detrás de la cadena elegida. Para evitar este efecto,
añada a la cadena, la expresión & vbNullChar. Quedrá de esta forma:

.szTip = "Este es el ToolTipText" & vbNullChar

Una vez explicada la teoría de funcionamiento de esta función, vayamos directamente a un


ejemplo. Este ejemplo está metido en el mismo ejercicio del control Winsock (Wsk) y se ha
extraído aquí lo que se refiere a la aplicación de esta API. Puede cortarse y pegarse el código
a otra aplicación, con garantía total de funcionamiento.

EJERCICIO PRACTICO

En un módulo del programa, en la sección de declaraciones, debemos introducir la definición


de la variable NOTIFYICONDATA

Public Type NOTIFYICONDATA


cbSize As Long
hwnd As Long
uId As Long
uFlags As Long
uCallBackMessage As Long
hIcon As Long
szTip As String * 64
End Type

En el mismo módulo introducimos las constantes que va a requerir, tanto la llamada a la


función Shell_NotifyIcon como las que vamos a necesitar para analizar el mensaje de retorno:

Public Const NIM_ADD = &H0

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 10


Public Const NIM_MODIFY = &H1
Public Const NIM_DELETE = &H2
Public Const NIF_MESSAGE = &H1
Public Const NIF_ICON = &H2
Public Const NIF_TIP = &H4

Public Const WM_MOUSEMOVE = &H200


Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONUP = &H202
Public Const WM_LBUTTONDBLCLK = &H203
Public Const WM_RBUTTONDOWN = &H204
Public Const WM_RBUTTONUP = &H205
Public Const WM_RBUTTONDBLCLK = &H206

Y en ese mismo módulo declaramos la función Shell_NotifyIcon

Public Declare Function Shell_NotifyIcon Lib "shell32" Alias "Shell_NotifyIconA" _


(ByVal dwMessage As Long, pnid As NOTIFYICONDATA) As Boolean

Declaramos otra API, con la que podemos hacer que un formulario tome el foco, y se coloque
en primer plano: SetForegroundWindow

Public Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long

Ahora declaramos una variable llamada Nid, que será del tipo NOTIFYICONDATA

Public Nid As NOTIFYICONDATA

Ya hemos terminado con el código del módulo. Vayamos ahora al procedimiento Load del
formulario inicial. Además de todo lo que debamos hacer en ese procedimiento, le añadiremos
esta parte, correspondiente a la creación del icono en el System Tray

Procedimiento Load del formulario inicial:

Con estas dos líneas garantizamos que se va a presentar el formulario, si se hubiese abierto
con la instrucción Load

Me.Show
Me.Refresh

‘Damos los valores apropiados a cada una de las partes de la variable Nid

With Nid
.cbSize = Len(Nid)
.hwnd = Me.hwnd
.uId = vbNull
.uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE
.uCallBackMessage = WM_MOUSEMOVE
.hIcon = Me.Icon
.szTip = "SEAE - Conexión vía IP" & vbNullChar
End With

Llamamos a la función para crear el icono (Parámetro NIM_ADD) y le pasamos la variable Nid
con las características del icono

Shell_NotifyIcon NIM_ADD, Nid


Veamos una a una las líneas de esta variable tipo NOTIFYICONDATA

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 11


cbSize = Len(Nid) Tal como se dijo más atrás, cbSize contiene un Long con el tamaño de
la variable tipo NOTIFYICONDATA. Al poner cbSize = Len(Nid) se lo estamos pasando
mediante el cálculo que realiza la función Len.

hwnd = Me.hwnd Le pasa el .hwnd del formulario. Así Windows ya sabe a qué formulario
debe enviar el mensaje de retorno.

uId = vbNull Se le pasa un Null ya que no se va a necesitar el identificador del icono

uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE Se le está indicando que los


valores de las tres líneas siguientes son válidos. Pero esta línea merece una explicación más
detallada.

NIF_ICON es una constante que vale 2, NIF_TIP es otra constante que vale 4 y
NIF_MESSAGE es otra que vale 1. Por lo tanto, esta línea es exactamente igual a otra que
pusiese

uFlags = 2 Or 4 Or 1 Si realizamos esta operación matemática, el resultado es 7.

Por lo tanto, también sería igual poner

uFlags = 7

La razón de poner una constante en vez del valor es solamente a efectos didácticos durante la
programación. Es más sencillo acordarse de un neumónico que de un número. Es costumbre
de programación solamente. Y recuerde que esas constantes deben estar declaradas, cosa
que hicimos en el módulo, cuya declaración se repite aquí por facilidad de comprensión:

Public Const NIF_MESSAGE = &H1


Public Const NIF_ICON = &H2
Public Const NIF_TIP = &H4

uCallBackMessage = WM_MOUSEMOVE Con esta línea le estamos indicando el


Identificador del mensaje de retorno. Y concretamente le estamos diciendo que ese valor es
Hex 200 (Recuerde que declaramos la constante WM_MOUSEMOVE = &H200). Al ponerle
este valor, la información del mensaje de retorno la tratará en el procedimiento MouseMove del
formulario. Habría dado lo mismo poner uCallBackMessage = &H200 (O si lo prefiere
uCallBackMessage = 512 y así lo expresaríamos en decimal) Volvemos a lo de antes, es
costumbre utilizar constantes y no valores durante la programación. ¿Será porque parece que
eleva el nivel del programador?

hIcon = Me.Icon Con esta línea le decimos que el icono que debe presentar en el
System Tray es precisamente el icono de este formulario. Podríamos indicarle otro icono,
pasándole la propiedad Icon de otro objeto, o la propiedad picture de un picture box o control
image, siempre y cuando en esa propiedad hayamos puesto un icono.

szTip = "SEAE - Conexión vía IP" & vbNullChar Este es el ToolTipText que va a
aparecer cuando dejemos unos instantes el puntero del ratón encima del icono. Esta variable
tiene 64 caracteres, pues así se declaró – y no funciona si se declara de otro tamaño – en la
definición de la variable tipo NOTIFYICONDATA. Para evitar que aparezcan como espacios los
caracteres no usados, cosa que deja muy fea la presentación del ToolTipText, basta con poner
& vbNullChar tras el texto deseado.

Con el código introducido en el Load del formulario inicial ya hemos puesto el icono en el
System Tray. Ahora ya podemos hacer clic sobre este icono (y otros eventos) para que el
icono envíe al formulario el mensaje de retorno. Ese mensaje será tratado en el procedimiento

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 12


MouseMove, puesto que así se lo hemos indicado a la función Shell_NotifyIcon con
uCallBackMessage = WM_MOUSEMOVE. En este procedimiento prevemos todos los
mensajes de retorno que puede recibir.

Evento MouseMove del formulario receptor de mensajes de retorno.

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

Este procedimiento espera recibir 4 parámetros, sin embargo solamente va a recibir 3. Por lo
tanto, el valor de Y será siempre nulo a lo largo de este procedimiento.

Dim Result As Long


Dim msg As Long
'El valor recibido en la posición X varía dependiendo del ScaleMode (Cosas de Windows)

If Me.ScaleMode = vbPixels Then


msg = X
Else
msg = X / Screen.TwipsPerPixelX
End If

El mensaje recibido del icono contiene un número. Si la propiedad ScaleMode del formulario
estuviese en Pixels, ese número coincidiría con el que genera el icono. Si ScaleMode no está
en Pixels, el valor generado lo multiplica por el valor de la propiedad TwipsPerPixelX. Las
líneas anteriores detectan el valor de la propiedad ScaleMode y actúan en consecuencia. Al
final tenemos un número que es el que metemos en la variable msg. Hacemos un Select Case
para obtener un resultado distinto en función del valor de msg

Select Case msg

Case WM_LBUTTONUP '514 (&H202) restaura el formulario


Me.WindowState = vbMaximized
Result = SetForegroundWindow(Me.hwnd)
Me.Show

Case WM_LBUTTONDBLCLK '515 (&H203) restaura el formulario


Me.WindowState = vbMaximized
Result = SetForegroundWindow(Me.hwnd)
Me.Show

Case WM_RBUTTONUP '517 (&H205) Presenta el PopUp Menú


Result = SetForegroundWindow(Me.hwnd)
Me.PopupMenu Me.mnuPopUpSys

End Select

End Sub

Solamente nos queda ver que números genera el icono para el mensaje de retorno. Son unos
valores que Windows ya tiene predispuestos, y que para mayor facilidad de programación ya
hemos introducido en unas constantes. Repetimos aquí el código de declaración de esas
constantes:

Public Const WM_MOUSEMOVE = &H200


Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONUP = &H202
Public Const WM_LBUTTONDBLCLK = &H203
Public Const WM_RBUTTONDOWN = &H204

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 13


Public Const WM_RBUTTONUP = &H205
Public Const WM_RBUTTONDBLCLK = &H206

(Recuerde que estos valores están en Hexadecimal). Por ejemplo, cuando hacemos clic en el
icono con el botón derecho (R), en el instante de bajar el botón (ButtonDown) se genera como
mensaje de retorno el número 204 en hexadecimal. Ese valor, que no depende de la
programación, sino que es un valor que Windows tiene prefijado, se lo asociamos a una
constante llamada WM_RBUTTONDOWN (La podríamos haber llamado de otra forma, pero
Microsoft la llama así, y si todos la llamamos así existirá cierta semejanza entre el código de
todos los programadores). Luego, en el procedimiento MouseMove del formulario, en vez de
preguntar si el mensaje de retorno vale &H204, preguntamos si vale WM_RBUTTONDOWN

Podemos hacer que el icono del System Tray cambie en determinadas circunstancias. Por
ejemplo, si el programa minimizado es un correo electrónico, podemos hacer que cambie de
color intermitentemente cuando se ha recibido un mensaje nuevo. Esto podemos hacerlo con
un control Timer, donde pondríamos un código parecido a esto:

Picture1 es un array de Pictures con Index del 0 al 3, y cada uno con una imagen del icono
distinta, para producir un efecto agradable. El código siguiente cambia el icono con 4 imágenes
distintas.

Private Sub Timer1_Timer()


If mnuOn.Checked Then
I = I + 1: If I > 4 Then I = 0
t.hIcon = Picture1(I).Picture
Shell_NotifyIcon NIM_MODIFY, t
End If
End Sub

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 14


VISUAL BASIC Y LAS APIS DE WINDOS – LAS APIS DEL
REGISTRO DE WINDOWS
El registro de Windows es sin duda el gran tabú de los programadores. Hay quien cree que si
se toca el registro, el PC nunca más va a volver a trabajar correctamente. Y desde luego no le
falta razón a quien así opina. No le falta razón, le falta matizar: Si se toca el registro de
Windows sin saber, es muy probable que el PC no vuelva a trabajar bien.

El único secreto que tiene el registro de Windows es NO TOCAR lo existente. Podemos


introducir cosas nuevas y borrar estas cosas nuevas. Y quédese tranquilo que Visual Basic,
solamente hará lo que le digamos que haga, por lo tanto podemos estar seguros que no tocará
nada de lo que nosotros no le hayamos indicado.

El registro puede manejarse mediante dos instrucciones de VB ya explicadas en capítulos


anteriores: SaveSettings y GetSettings. Y es lo que se dice en un curso básico de VB.
Cuando termine de leer este capítulo Vd. Mismo se convencerá que esas instrucciones son
solamente para empezar. Un programador profesional siempre usa APIS para leer y escribir el
Registro de Windows.

Va a encontrar en este capítulo una palabra muy repetida: Clave del registro. (Key) Una clave
del registro es una de las muchas informaciones que existen en el registro. Por ejemplo:

HKEY_CURRENT_USER/Software/VB And VBA Program Settings/AgendaTel/Colores/Fondo

Esta clave contiene el color de fondo del formulario de la aplicación AgendaTel, y debe
contener un valor, concretamente el número que expresa el color de fondo citado. En el caso
del ejemplo, mi PC contenía el valor “8454016”, (contiene la cadena de caracteres 8454016, no
el número 8.454.016, por eso va entre comillas). Por eso, al tratar ese dato, debe hacerse
pensando que es un string.

Dim VarColor As String


VarColor = GetSetting(AppName:="AgendaTel", Section:="Colores", Key:="Fondo")
Me.BackColor = CLng(VarColor)

Lo mismo ocurre cuando se trate de una fecha.

Las claves se expresan con una estructura similar a la de las carpetas (directorios) del
explorador de Windows. No es que sea así, ya que el registro es un fichero único, pero su
estructura jerárquica es similar. Por eso, hablaremos de Claves y Subclaves, lo mismo que
hablamos de directorios y subdirectorios (Carpetas y Subcarpetas). Una clave tendrá subclaves
si hay más claves por debajo de su nivel jerárquico. En el ejemplo anterior, la clave

HKEY_CURRENT_USER/Software/VB And VBA Program Settings/AgendaTel

tiene la subclave Colores y esta a su vez tiene la subclave Fondo. La clave Fondo no tiene
subclaves.

Los datos de una clave pueden ser cadenas de


caracteres o numéricas. Puede diferenciar unas
de otras mediante el icono que aparece a su lado
al editar el registro. Una clave puede tener varios
datos. Cada dato tienen un nombre y un valor
(Nombre = fonts.fon y su valor vgafix.fon)

El valor de las claves numéricas puede ponerse


como binario puro, o como un Long (32 bits), y en
este caso, con estructura Big Endian (El byte de mayor peso está en último lugar) o Little
Endian. (El byte de menor peso está en último lugar). En cualquier caso las claves numéricas

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 15


el editor del registro las presenta en Hexadecimal. En la Fig. anterior, Hex(00000060) = 96 en
decimal. Las claves que son cadenas de caracteres las presenta entre comillas dobles.

Se enumeran a continuación las APIS relacionadas con el registro de 32 bits. Se incluye la


declaración de cada una de ellas y la explicación de cada uno de sus parámetros. Se omiten
aquellas que solamente funcionan en Windows 3.11 o que existen por compatibilidad con
Windows 3.11.

Podríamos clasificarlas en dos grupos, uno la de aquellas que sirven para leer y guardar
valores, y otro, con aquellas Apis que sirven para mantenimiento del registro.

La primera operación que debemos hacer para trabajar sobre una clave es abrirla
(Exceptuando lógicamente la operación de crearla). Para abrir una clave se usa el API
RegOpenKeyEx. Al final, una vez realizadas todas las operaciones deseadas, hay que
cerrarla. Se cierra mediante el API RegCloseKey

Handle = Manejador en español, pero esta es una de estas palabras que es mejor no
traducirlas. Utilizaremos la expresión Handle durante todo este capítulo.

Función RegOpenKeyEx
Abre la clave especificada. Es la primera operación que hay que hacer para trabajar con una
clave. (Es similar, en ficheros, a Open NombreFichero For xxx As #n)

Declaración:
Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" (ByVal hKey As
Long, ByVal lpSubKey As String, ByVal ulOptions As Long, ByVal samDesired As Long,
phkResult As Long) As Long

HKey es el Handle de la clave de nivel superior. Hkey acepta cualquiera de los valores
predefinidos:

HKEY_CLASSES_ROOT (= Hex 80000000)


HKEY_CURRENT_USER (= Hex 80000001)
HKEY_LOCAL_MACHINE (= Hex 80000002)
HKEY_USERS (= Hex 80000003)

(Observe en la declaración que Hkey es un Long. ¿Cómo podemos poner la cadena


HKEY_LOCAL_MACHINE en vez de un Long? Es que esa cadena es el nombre de una
constante que habrá que declarar. Lo que ocurre es que en Windows, esa constante siempre
tiene el mismo valor (Concretamente Hex 80000002). No declare una constante con ese mismo
nombre con un valor distinto a ese.)

LpSubKey es una variable que contiene el nombre de la subclave a abrir. Esta


variable es una cadena de caracteres, que indica la ruta total de la clave a abrir, desde
la clave expresada en el parámetro anterior. Si este parámetro es nulo o la cadena
vacía, la función creará un nuevo handle de la clave definida por el parámetro Hkey .
En este caso, la función no cierra el handle creado previamente.

UlOptions Reservado. Debe ser 0.

samDesired Especifica la máscara de seguridad para el acceso a esa clave. Puede


ser una combinación de los siguientes parámetros:

KEY_ALL_ACCESS, que es una combinación de KEY_QUERY_VALUE,


KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_SUB_KEY,
KEY_CREATE_LINK, y KEY_SET_VALUE.
KEY_CREATE_LINK, permiso para crear un enlace simbólico.
KEY_CREATE_SUB_KEY, permiso para crear subclaves
KEY_ENUMERATE_SUB_KEYS, permiso para enumerar subclaves

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 16


KEY_EXECUTE, permiso para acceso de lectura.
KEY_NOTIFY, permiso para cambiar la notificación
KEY_QUERY_VALUE, permiso para obtener el valor de una subclave
KEY_READ, combinación de KEY_QUERY_VALUE,
KEY_ENUMERATE_SUB_KEYS, y KEY_NOTIFY.
KEY_SET_VALUE, permiso para escribir el valor de una subclave.
KEY_WRITE, combinación de KEY_SET_VALUE y KEY_CREATE_SUB_KEY

PhkResult, es una variable (Long) que va a recibir el Handle de la clave abierta.

Función RegCloseKey
Cierra el Handle de la clave que estamos utilizando. Es la operación que finaliza cualquier
operación de lectura o escritura en el registro. Si hacemos un símil con los ficheros
secuenciales, sería el Close #n

Declaración
Declare Function RegCloseKey Lib "advapi32.dll" Alias "RegCloseKey" (ByVal hKey As Long)
As Long

HKey es el Handle de la clave abierta. Es un Long. Este número es el que nos


devuelve la función RegOpenKeyEx (y la función RegCreateKeyEx) en el parámetro
PhkResult. (cuando abrimos o creamos una clave). Hkey acepta también cualquiera de
los valores predefinidos

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
(Estos valores son las constantes citadas en la función anterior.)

Función RegCreateKeyEx
Crea la clave especificada. Si existe ya esa clave, la abre.

Declare Function RegCreateKeyEx Lib "advapi32.dll" Alias "RegCreateKeyExA" (ByVal hKey


As Long, ByVal lpSubKey As String, ByVal Reserved As Long, ByVal lpClass As String, ByVal
dwOptions As Long, ByVal samDesired As Long, lpSecurityAttributes As
SECURITY_ATTRIBUTES, phkResult As Long, lpdwDisposition As Long) As Long

hKey es el handle visto en las funciones anteriores.

LpSubKey es una variable tipo string que contiene el nombre de la subclave a crear.
La subclave no debe empezar por el carácter \. Este parámetro no puede ser nulo.

Reserved Reservado. Debe ser cero.

LpClass Variable tipo string que especifica el tipo de esta clave. Puede poner una
cadena vacía y el tipo de la clave se especificará cuando le introduzca el valor. Este
parámetro se ignora si la clave ya existe.

dwOptions Especifica las opciones especiales de la clave. Puede ser uno de los
siguientes valores:

REG_OPTION_NON_VOLATILE La clave es no volátil. Esta clave y su valor se


guardarán en el disco (al invocar la función RegSaveKey)
REG_OPTION_VOLATILE (Windows NT) Esta clave es volátil, es decir, no se
guarda en el disco. Solamente existe en la memoria RAM y una vez que se apaga el
ordenador se extingue. Este valor se ignora si ya existe la clave. (Windows 95) En
W95 este parámetro se ignora.

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 17


REG_OPTION_BACKUP_RESTORE (Windows NT) Si se pone este valor, la función
ignora el parámetro samDesired. Este valor se pone para imponer restricciones de
acceso a la clave, tanto para hacer backup como para modificarla. (Windows 95)
EnW95 este valor se ignora, ya que el registro de W95 no soporta esa seguridad.

SamDesired Igual que en la función RegOpenKeyEx ya vista.

LpSecurityAttributes Es una variable del tipo SECURITY_ATTRIBUTES que


determina si las propiedades pueden ser heredadas por un proceso hijo. Si este valor
es Null (0) las propiedades no pueden ser heredadas. Este parámetro es típico verlo a
0.
La variable SECURITY_ATTRIBUTES tienen esta forma:
Public Type SECURITY_ATTRIBUTES
Length As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type

PhkResult Apunta a una variable que devuelve un Long con el Handle de la clave
creada o abierta, en caso de que ya existiera.

lpdwDisposition Apunta a una variable que devuelve un Long con uno de los
siguientes valores:

REG_CREATED_NEW_KEY ( = 1) si la clave no existía y se ha creado


REG_OPENED_EXISTING_KEY ( = 2) La clave ya existía y ha sido abierta
(Si este valor es 0 es que la operación no se ha completado con éxito)

Función RegDeleteKey
Borra una clave del registro de Windows. Funciona de forma distinta en W95 que en WNT. En
W95 borra esa clave y todas sus subclaves. En WNT no permite borrar una clave que tenga
subclaves.

Declare Function RegDeleteKey Lib "advapi32.dll" Alias "RegDeleteKeyA" (ByVal hKey As


Long, ByVal lpSubKey As String) As Long

HKey Es el Handle de una clave abierta. Puede ser también una de las siguientes
constantes:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

LpSubKey Es la subclave a borrar. Esta subclave debe estar dentro de la clave


especificada en el parámetro Hkey . Este parámetro no puede ser nulo. En WNT, la
clave a borrar no puede tener subclaves.

Aplicación práctica de lo visto hasta aquí: Crear una clave y eliminarla

Para crear una clave, primero hay que abrir todas las claves jerárquicamente superiores a esa
clave a crear. En este ejemplo vamos a crear una clave de la siguiente forma:

HKEY_CURRENT_USER/Software/GuiadelEstudiante/Colores

La clave HKEY_CURRENT_USER existe, ya que es una de las de más alto nivel. La clave
Software también existe, ya que vienen predeterminada. La que posiblemente no existe es la
de GuiadelEstudiante, y tampoco la de Colores dentro de ella. Estas claves no existirán en
principio, pero una vez que las hayamos creado, ya pueden existir. Por lo tanto deberemos

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 18


comprobar si existen. Esta clave va a tener varios valores. Se refiere a los valores del color de
un programa, y tendrá los colores de Fondo, Etiquetas, Letras y Desplegables. Aunque el color
se expresa con un número, aquí lo vamos a introducir de momento como una cadena de
caracteres.

El código para crear la clave lo introducimos en un botón de nombre cmdCrearClave

Private Sub cmdCrearClave_Click()


Dim LpClass As String
Dim Manejador1 As Long, Manejador2 As Long, Manejador3 As Long, Disposicion As Long
'Abre la clave HKEY_CURRENT_USER/Software y obtiene el handle (Manejador1)
RegOpenKeyEx HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, Manejador1
'Crea la clave GuiadelEstudiante como subclave de HKEY_CURRENT_USER/Software. Si ya
‘existe. la abre
RegCreateKeyEx Manejador1, "GuiadelEstudiante", 0, LpClass, _
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, Manejador2, Disposicion
'Si ha ocurrido algún error, Manejador2 sería 0
If Manejador2 = 0 Then
MsgBox "Error durante la creación de la clave!"
Exit Sub
End If
'Si no ha fallado (Manejador2 <> 0) creamos la clave Colores dentro de la clave
‘GuiadelEstudiante
RegCreateKeyEx Manejador2, "Colores", 0, LpClass, REG_OPTION_NON_VOLATILE, _
KEY_ALL_ACCESS, 0, Manejador3, Disposicion
'Si ha ocurrido algún error, Manejador3 sería 0
If Manejador2 = 0 Then
MsgBox "Error durante la creación de la clave!"
Exit Sub
End If
'Cierra la clave HKEY_CURRENT_USER/Software/GiadelEstudiante/Colores
RegCloseKey Manejador3
'Cierra la clave HKEY_CURRENT_USER/Software/GiadelEstudiante
RegCloseKey Manejador2
'Cierra la clave HKEY_CURRENT_USER/Software
RegCloseKey Manejador1
End Sub

Para eliminar una clave debemos utilizar la función RegDeleteKey. La clave inmediatamente
superior a la clave a borrar debe abrirse previamente con RegOpenKey. Y para abrir una
clave, debemos abrir previamente todas las claves jerárquicamente superiores. Para borrar una
clave con subclaves, borramos primero las subclaves. Deberemos ir borrando en orden
ascendente. Una vez borradas las claves, cerramos las claves superiores a la borrada. En el
siguiente ejemplo se borra la clave GuiadelEstudiante y su subclave, Colores

Private Sub cmdEliminarClave_Click()


Dim Manejador1 As Long, Manejador2 As Long, Manejador3 As Long, Disposicion As Long
'Abre la clave HKEY_CURRENT_USER/Software y obtiene el handle (Manejador1)
RegOpenKeyEx HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, Manejador1
'comprueba que la función se ha ejecutado correctamente. Si no es así, sale del
‘procedimiento
If Manejador1 = 0 Then Exit Sub
'Abre la clave GuiadelEstudiante que es subclave de la anterior
RegOpenKeyEx Manejador1, "GuiadelEstudiante", 0, KEY_ALL_ACCESS, Manejador2
If Manejador2 = 0 Then Exit Sub
'Borra ya la clave Colores
RegDeleteKey Manejador2, "Colores"
'Cerramos la clave GuiadelEstudiante. Podríamos no cerrarla
RegCloseKey Manejador2
'Borramos la clave GuiadelEstudiante

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 19


RegDeleteKey Manejador1, "GuiadelEstudiante"
'Cerramos la clave HKEY_CURRENT_USER
RegCloseKey Manejador1
End Sub

Para que todas estas funciones puedan trabajar es necesario haberlas declarado previamente.
La declaración puede hacerse, o bien en la sección de declaraciones de un módulo, donde las
declararemos como Públicas, o en la sección de declaraciones de un formulario, donde deben
declararse como privadas. Las constantes también se declararán en el mismo sitio que las
funciones. En este caso, se declararon en el formulario:

Option Explicit
Const HKEY_CLASSES_ROOT = &H80000000
Const HKEY_CURRENT_USER = &H80000001
Const HKEY_LOCAL_MACHINE = &H80000002
Const HKEY_USERS = &H80000003
Const HKEY_CURRENT_CONFIG = &H80000005
Const ERROR_NO_MORE_ITEMS = 259&
Const REG_OPTION_NON_VOLATILE = 0
Const KEY_SET_VALUE = &H2
Const REG_OPTION_BACKUP_RESTORE = 4
Const REG_OPTION_VOLATILE = 1
Const STANDARD_RIGHTS_ALL = &H1F0000
Const SYNCHRONIZE = &H100000
Const READ_CONTROL = &H20000
Const STANDARD_RIGHTS_READ = (READ_CONTROL)
Const STANDARD_RIGHTS_WRITE = (READ_CONTROL)
Const KEY_CREATE_LINK = &H20
Const KEY_CREATE_SUB_KEY = &H4
Const KEY_ENUMERATE_SUB_KEYS = &H8
Const KEY_NOTIFY = &H10
Const KEY_QUERY_VALUE = &H1
Const KEY_READ = ((STANDARD_RIGHTS_READ Or KEY_QUERY_VALUE Or _
KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY) And (Not SYNCHRONIZE))
Const KEY_WRITE = ((STANDARD_RIGHTS_WRITE Or KEY_SET_VALUE Or _
KEY_CREATE_SUB_KEY) And (Not SYNCHRONIZE))
Const KEY_EXECUTE = (KEY_READ)
Const KEY_ALL_ACCESS = ((STANDARD_RIGHTS_ALL Or KEY_QUERY_VALUE Or _
KEY_SET_VALUE Or KEY_CREATE_SUB_KEY Or KEY_ENUMERATE_SUB_KEYS Or _
KEY_NOTIFY Or KEY_CREATE_LINK) And (Not SYNCHRONIZE))

Private Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" (ByVal _


hKey As Long, ByVal lpSubKey As String, ByVal ulOptions As Long, ByVal samDesired As _
Long, phkResult As Long) As Long
Private Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long _
Private Declare Function RegOpenKey Lib "advapi32.dll" Alias "RegOpenKeyA" (ByVal hKey _
As Long, ByVal lpSubKey As String, phkResult As Long) As Long
Private Declare Function RegEnumKeyEx Lib "advapi32.dll" Alias "RegEnumKeyExA" (ByVal _
hKey As Long, ByVal dwIndex As Long, ByVal lpName As String, lpcbName As Long, ByVal _
lpReserved As Long, ByVal LpClass As String, lpcbClass As Long, lpftLastWriteTime As Any) _
As Long
Private Declare Function RegEnumValue Lib "advapi32.dll" Alias "RegEnumValueA" (ByVal _
hKey As Long, ByVal dwIndex As Long, ByVal lpValueName As String, lpcbValueName As _
Long, ByVal lpReserved As Long, lpType As Long, lpData As Any, lpcbData As Long) As Long
Private Declare Function RegCreateKeyEx Lib "advapi32.dll" Alias "RegCreateKeyExA" _
(ByVal hKey As Long, ByVal lpSubKey As String, ByVal Reserved As Long, ByVal LpClass _
As String, ByVal dwOptions As Long, ByVal samDesired As Long, lpSecurityAttributes As _
Long, phkResult As Long, lpdwDisposition As Long) As Long
Private Declare Function RegDeleteKey Lib "advapi32.dll" Alias "RegDeleteKeyA" (ByVal _
hKey As Long, ByVal lpSubKey As String) As Long

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 20


Vamos a ver ahora como se introducen los datos en las claves. Para introducir cada dato,
debemos introducir el nombre y el valor de cada uno de ellos.

Función RegSetValueEx

Guarda un dato en una clave previamente abierta. Con esta función, puede también modificar
el valor y el tipo de información que almacena ese dato.

Declaración
Declare Function RegSetValueEx Lib "advapi32.dll" Alias "RegSetValueExA" (ByVal hKey As
Long, ByVal lpValueName As String, ByVal Reserved As Long, ByVal dwType As Long, lpData
As Any, ByVal cbData As Long) As Long

(Si declara el parámetro lpData como String, debe pasarlo por valor - By Val lpData As String)

hKey es el Handle de la clave. Será el valor devuelto por la función RegOpenKeyEx


en el parámetro phkResult.

lpValueName es el nombre del dato que va a introducir o modificar

Reserved debe ponerse a 0

dwType Tipo de información almacenada. Acepta estos valores

REG_BINARY ( = 3) Cualquier tipo de datos binarios


REG_DWORD ( = 4) Un número de 32 Bits (Long)
REG_DWORD_LITTLE_ENDIAN (= 4) Un número de 32 bits, en formato Little-endian.
(El byte más significativo es el byte de mayor orden) Este es el formato utilizado
por los ordenadores que utilizan W 95 o W NT. Por eso el valor es el mismo (4)
que para un Long
REG_DWORD_BIG_ENDIAN ( = 5) Un número de 32 bits, ordenado según el formato
Big-endian. (El byte más significativo es el byte de menor orden)
REG_EXPAND_SZ ( = 2) Una cadena de caracteres que representa variables de
entorno (Por ejemplo, “%PATH%”). Debe terminar con el carácter nulo.
REG_LINK ( = 6) Un link simbólico Unicode.
REG_MULTI_SZ ( = 7) Un array de cadenas de caracteres. Debe terminar con el
carácter nulo.
REG_NONE ( = 0) Valor sin definir
REG_SZ ( = 1) Una cadena de caracteres

lpData Variable que contiene el valor del dato a almacenar

cbData Especifica el número de caracteres que tiene el dato pasado en el


parámetro lpData. Cuando el dato termina en el carácter nulo, cbData
debe incluir este carácter nulo.

Función RegQueryValueEx
Devuelve el tipo y el valor de un dato almacenado en una clave abierta.

Declaración
Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" (ByVal hKey
As Long, ByVal lpValueName As String, ByVal lpReserved As Long, lpType As Long, lpData As
Any, lpcbData As Long) As Long
(Si se declara el parámetro lpData como String, debe pasarse por Valor -By Val).

hKey Es el handle de una clave abierta.

lpValueName Variable que contienen el nombre del dato a obtener

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 21


lpReserved Reservado. Debe ser Null

lpType Apunta a una variable que va a recibir el tipo de dato que contiene. Es un Long,
y devolverá uno de los valores descritos para el valor dwType de la función
RegQueryValueEx. Este valor debe ponerse a Null si no se necesita conocer el tipo de
dato.

lpData Apunta a una variable que recibirá el valor del dato. Esta variable, cuando es
tipo string, hay que declararla con un tamaño prefijado, siempre mayor que el tamaño
del dato que va a recibir (Por ejemplo, Dim MiVariable as String * 100 Se entiende que
el dato que se va a meter en MiVariable nunca será superior a 100 caracteres)
También puede declararse como String sin tamaño, y ponerle posteriormente el tamaño
igual a lpcbData. Vea la explicación de esto en el ejemplo. Si no se necesita conocer el
valor del dato, debe ponerse Null

lpcbData Apunta a una variable que guardará el tamaño del copiado en lpData.
Si la variable lpData no tienen tamaño suficiente para almacenar el valor del dato,
lpcbData devolverá el valor ERROR_MORE_DATA ( = 234)

NOTA: Esta función tiene un comportamiento un poco irregular. Cuando se ejecuta la primera
vez no lee el valor de lpData. Sí lee los demás parámetros. Hay que ejecutarla 2 veces
seguidas para que pueda leer ese parámetro.

Sigamos con el ejemplo práctico. Vamos a introducir y leer valores en una clave.

Para poner el valor a un dato de una clave, esa clave debe estar abierta. Se irán abriendo las
claves de forma jerárquica hasta llegar a la clave deseada. Una vez abierta esa clave, se
utilizará la función RegSetValueEx. Luego se cierran todas las claves en orden inverso a la
apertura.

Private Sub cmdPonerValor_Click()

Dim Manejador1 As Long, Manejador2 As Long, Manejador3 As Long


Dim Var_lpValueName As String, Var_lpData As String, Var_cbData As Long

Var_lpValueName = TbNombreDato ‘TbNombreDato y TbValorClave son dos TextBox


Var_lpData = TbValorClave ‘donde se introducen el nombre del dato y su
Var_cbData = Len(Var_lpData) ‘valor respectivamente.

RegOpenKeyEx HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, Manejador1


If Manejador1 = 0 Then Exit Sub ‘Comprueba que se ha abierto correctamente
RegOpenKeyEx Manejador1, "GuiadelEstudiante", 0, KEY_ALL_ACCESS, Manejador2
If Manejador2 = 0 Then Exit Sub
RegOpenKeyEx Manejador2, "Colores", 0, KEY_ALL_ACCESS, Manejador3
RegSetValueEx Manejador3, Var_lpValueName, 0, REG_SZ, ByVal Var_lpData, ByVal _
Var_cbData

RegCloseKey Manejador3
RegCloseKey Manejador2
RegCloseKey Manejador1

End Sub

Para leer un dato hay que proceder de forma similar, abriendo jerárquicamente las claves hasta
llegar a la clave a leer, y una vez abierta, proceder con la función RegQueryValueEx.
Recuerde que esta función hay que ejecutarla 2 veces para conseguir el valor del dato.

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 22


Private Sub cmdLeerValor_Click()
Dim Manejador1 As Long, Manejador2 As Long, Manejador3 As Long
Dim Var_lpValueName As String, Var_lpType As Long, Var_lpData As String * 100,
Var_lpcbData As Long
Dim Resp As Long
Var_lpValueName = Trim(TbNombreDato)
Var_lpType = 1
RegOpenKeyEx HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, Manejador1
If Manejador1 = 0 Then Exit Sub
RegOpenKeyEx Manejador1, "GuiadelEstudiante", 0, KEY_ALL_ACCESS, Manejador2
If Manejador2 = 0 Then Exit Sub
RegOpenKeyEx Manejador2, "Colores", 0, KEY_ALL_ACCESS, Manejador3
If Manejador3 = 0 Then Exit Sub

RegQueryValueEx Manejador3, Var_lpValueName, 0, Var_lpType, ByVal Var_lpData, _


Var_lpcbData
'Esto es la irregularidad de este API. La primera vez no lo lee. Hay que repetir la función
RegQueryValueEx Manejador3, Var_lpValueName, 0, Var_lpType, ByVal Var_lpData, _
Var_lpcbData

RegCloseKey Manejador3
RegCloseKey Manejador2
RegCloseKey Manejador1

LValorClaveRet = Trim(Var_lpData)
LTamanoValor = Var_lpcbData

End Sub

Podemos aprovechar la primera ejecución de la función para leer el dato lpcbData que nos
indica el tamaño de lpData. A continuación hacemos que la variable Var_lpData tenga ese
tamaño, rellenando tantos caracteres con espacios. Es otra forma de hacer lo mismo.

Private Sub cmdLeerValor2_Click()


Dim Manejador1 As Long, Manejador2 As Long, Manejador3 As Long
Dim Var_lpValueName As String, Var_lpType As Long, Var_lpData As String, Var_lpcbData As
Long
Dim Resp As Long
Var_lpValueName = Trim(TbNombreDato)
Var_lpType = 1
RegOpenKeyEx HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, Manejador1
If Manejador1 = 0 Then Exit Sub
RegOpenKeyEx Manejador1, "GuiadelEstudiante", 0, KEY_ALL_ACCESS, Manejador2
If Manejador2 = 0 Then Exit Sub
RegOpenKeyEx Manejador2, "Colores", 0, KEY_ALL_ACCESS, Manejador3
If Manejador3 = 0 Then Exit Sub
'Leemos el valor de Var_lpcbData
RegQueryValueEx Manejador3, Var_lpValueName, 0, Var_lpType, ByVal Var_lpData,
Var_lpcbData
'Hacemos que Var_lpData tenga el tamaño obtenido en Var_lpcbData
Var_lpData = String(Var_lpcbData, " ")
RegQueryValueEx Manejador3, Var_lpValueName, 0, Var_lpType, ByVal Var_lpData,
Var_lpcbData
RegCloseKey Manejador3
RegCloseKey Manejador2
RegCloseKey Manejador1
LValorClaveRet = Var_lpData
LTamanoValor = Var_lpcbData
End Sub

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 23


Vamos a ver ahora como podemos borrar un valor. Se usa para ello la función RegDeleteValue

Función Function RegDeleteValue


Elimina un valor dentro de una clave.

Declaración
Declare Function RegDeleteValue Lib "advapi32.dll" Alias "RegDeleteValueA" (ByVal hKey As
Long, ByVal lpValueName As String) As Long

HKey Es el handle de una clave abierta. (Es el valor phkResult obtenido en la


función RegOpenKeyEx)

LpValueName Es una variable que contienen el nombre del valor a eliminar.

En este ejemplo, se elimina el valor cuyo nombre esté escrito en TbNombreDato

Private Sub cmdEliminarValor_Click()


Dim Manejador1 As Long, Manejador2 As Long, Manejador3 As Long
Dim Var_lpValueName As String
Var_lpValueName = TbNombreDato
RegOpenKeyEx HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, Manejador1
RegOpenKeyEx Manejador1, "GuiadelEstudiante", 0, KEY_ALL_ACCESS, Manejador2
RegOpenKeyEx Manejador2, "Colores", 0, KEY_ALL_ACCESS, Manejador3
RegDeleteValue Manejador3, Var_lpValueName
RegCloseKey Manejador3
RegCloseKey Manejador2
RegCloseKey Manejador1
End Sub

RegEnumValue
Esta función devuelve el nombre y el valor de cada uno de los datos contenidos dentro de una
clave previamente abierta. Esta función devuelve el nombre y valor de uno solo de los datos,
por lo que será necesario recurrir a una serie de llamadas en un bucle para obtenerlos todos.

Declaración
Declare Function RegEnumValue Lib "advapi32.dll" Alias "RegEnumValueA" (ByVal hKey As
Long, ByVal dwIndex As Long, ByVal lpValueName As String, lpcbValueName As Long,
lpReserved As Long, lpType As Long, lpData As Any, lpcbData As Long) As Long

hKey Handle de la clave abierta.

DwIndex Es una variable donde le indicamos el Indice correspondiente al valor a


devolver. El primero debe ser el 0, y se irá incrementando en 1 en cada lectura. Dado
que los datos no están ordenados, puede devolverlos en cualquier orden.

lpValueName Apunta a una variable que recibe el nombre del dato, incluido el
carácter nulo de terminación.

lpcbValueName Apunta a una variable Long que va a recibir el dato con el


tamaño del parámetro lpValueName. Este dato incluye el carácter nulo de terminación.

lpReserved Reservado. Debe ser Null

lpType Apunta a una variable que va a contener el tipo de dato que se va a


obtener. Los valores que se pueden obtener son los mismos que los
indicados para el parámetro dwType de la función RegSetValueEx
lpData Apunta a una variable que va a recibir el valor del dato.

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 24


lpcbData Apunta a una variable Long que va a recibir el tamaño del dato a
devolver en lpData.

Esta función devuelve el valor 0 cuando se ha desarrollado correctamente, y el valor 259


cuando no hay valores que mostrar en el índice indicado. Aprovecharemos el valor devuelto
para saber cuándo debemos dejar el bucle de lectura.

En el siguiente ejemplo, se muestran en un ListBox (List1) el índice, el nombre del dato y el


valor del dato. Esta función tienen algunas particularidades (Hay muchas APIs con
particularidades similares). Las variables que van a contener datos tipo string hay que
declararlas con un tamaño superior al que van a tener (P.e. Var_lpValueName As String * 255)
o rellenarlas previamente con un número de caracteres superior al tamaño que van a tener. El
carácter ideal son los espacios, ya que luego se pueden eliminar con Trim [Se realiza en las
líneas Var_lpValueName = Space(255) y Var_lpData = Space(255)] y las variables Long que
almacenan el tamaño de las variables string hay que darles un valor superior al que van a tener
en la función (Var_lpcbValueName = 255 y Var_lpcbData = 255) Observe que se usó la
sintaxis de VarLong = Función (Parámetros) para que pueda devolvernos el número 0 ó 259,
dependiendo de si hay o no hay elementos con ese índice.

Private Sub cmdVerValores_Click()


Dim Manejador1 As Long, Manejador2 As Long, Manejador3 As Long
Dim I As Long, Var_lpValueName As String, Var_lpcbValueName As Long
Dim Var_lpType As Long, Var_lpData As String, Var_lpcbData As Long
Dim Resp As Long
RegOpenKeyEx HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, Manejador1
RegOpenKeyEx Manejador1, "GuiadelEstudiante", 0, KEY_ALL_ACCESS, Manejador2
RegOpenKeyEx Manejador2, "Colores", 0, KEY_ALL_ACCESS, Manejador3

Do While Resp = 0
Var_lpValueName = Space(255)
Var_lpData = Space(255)
Var_lpcbValueName = 255
Var_lpcbData = 255
Resp = RegEnumValue(Manejador3, I, Var_lpValueName, Var_lpcbValueName, 0, Var_lpType,
ByVal Var_lpData, Var_lpcbData)
Var_lpValueName = Left(Var_lpValueName, Var_lpcbValueName)
Var_lpData = Left(Var_lpData, Var_lpcbData)
List1.AddItem I & " - " & Trim(Var_lpValueName) & " - " & Trim(Var_lpData)
I=I+1
Loop

RegCloseKey Manejador3
RegCloseKey Manejador2
RegCloseKey Manejador1
End Sub

Función RegEnumKeyEx

Devuelve los nombres de las subclaves de una clave del registro previamente abierta. Esta
función obtiene el nombre de una única subclave cada vez que se le llama, por lo que para
leerlos todos, es necesario recurrir a llamadas en bucle.

Declaración
Declare Function RegEnumKeyEx Lib "advapi32.dll" Alias "RegEnumKeyExA" (ByVal hKey As
Long, ByVal dwIndex As Long, ByVal lpName As String, lpcbName As Long, lpReserved As
Long, ByVal lpClass As String, lpcbClass As Long, lpftLastWriteTime As FILETIME) As Long

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 25


hKey Manejador de la clave bajo la cual están las subclaves a enumerar

dwIndex Es el índice de la subclave a investigar. Como esta función obtiene


solamente el valor de una de las subclaves, será necesario recurrir a un bucle para
investigarlas todas. El índice pasado para la primera llamada debe ser el 0, ya que los
índices van de 0 a n-1. El orden de los índices dentro de las subclaves es arbitrario,
por lo que también será arbitrario el orden con el que nos va a devolver esta función los
valores de las subclaves.

lpName Es el buffer donde la función nos devolverá el nombre de la subclave.


(Incluye un carácter nulo como terminación) Este buffer va a contener solamente el
nombre de la clave, no su dirección jerárquica completa.

lpcbName Es el buffer donde se le indica a la función el tamaño del buffer lpName, y


una vez que la función se ha ejecutado, contendrá el número de caracteres real (sin el
carácter nulo de terminación) del valor almacenado en lpName.

LpReserved Reservado. Debe ser siempre Nulo.

LpClass Es el buffer que contiene la clase del subclave a devolver. Este es el


mismo valor introducido en el parámetro LpClass en la función RegCreateKeyEx. Si no
se necesita que el valor devuelto sea una clase, este valor debe ponerse Null.

LpcbClass Es el buffer que contiene el tamaño (en caracteres) previsto para LpClas.
Una vez ejecutada la función, contiene el tamaño exacto de LpClas sin contar el
carácter nulo de terminación. Este parámetro debe ser Null solamente cuando
LpClass sea Null

LpftLastWriteTime Es el buffer donde devolverá la fecha y hora del último cambio de


la subclave. Sale un número incomprensible. No es fácil ver que sea la fecha del
cambio de la clave

Esta función devuelve 0 si se ha ejecutado perfectamente, y 259 si la posición correspondiente


al índice no tienen clave alguna.

En el siguiente ejemplo se ve como obtener en nombre de las subclaves de una clave.

Private Sub cmdVerClaves_Click()


Dim Manejador1 As Long, Manejador2 As Long
Dim I As Long, Val_lpName As String, Val_lpcbName As Long
Dim Var_lpftLastTime As Long, Var_LpClass As String, Var_lpcbClass As Long
Dim Resp As Long
RegOpenKeyEx HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, Manejador1
RegOpenKeyEx Manejador1, "GuiadelEstudiante", 0, KEY_ALL_ACCESS, Manejador2
Do While Resp = 0
Val_lpName = Space(255)
Var_LpClass = Space(255)
Val_lpcbName = 255
Var_lpcbClass = 255
Resp = RegEnumKeyEx(Manejador2, I, Val_lpName, Val_lpcbName, 0, Var_LpClass,
Var_lpcbClass, Var_lpftLastTime)
Val_lpName = Left(Val_lpName, Val_lpcbName)
List1.AddItem I & " - " & Trim(Val_lpName)
I=I+1
Loop
RegCloseKey Manejador2
RegCloseKey Manejador1
End Sub

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 26


Hay más APIS para el control del registro. En este curso creemos que ya hay materia suficiente
para tener una idea del manejo del registro (Creación de claves, eliminación, Lectura y
escritura) Con los ejemplos descritos en este capítulo hay materia suficiente para poder
realizar todas las funciones que una aplicación normal pueda hacer sobre el registro.

El uso de Apis en una aplicación la hace generalmente más rápida ya que aprovecha recursos
ya existentes en Windows y además compilados. Tiene un pequeño inconveniente cuando se
hace un desarrollo que va a funcionar sobre distintas versiones de Windows. No es normal que
ocurra, pero hay que comprobar que un programa diseñado en W95 corre perfectamente en
W2000. Y es que algunas Apis no son exactamente iguales.

APIS PARA EL CONTROL DE LA IMPRESORA. EnumPrinters


Por otra parte, programar con Apis, aunque es muy elegante y aporta mucho caché al
programador, tampoco hay que pasarse. En el ejemplo que sigue se utilizan Apis para el
control de la impresora (Hay varias) y una de ellas nos permite conocer las impresoras
disponibles en el sistema: EnumPrinters

Función EnumPrinters

Declaración
Declare Function EnumPrinters Lib "winspool.drv" Alias "EnumPrintersA" (ByVal flags As Long,
ByVal name As String, ByVal Level As Long, pPrinterEnum As Long, ByVal cdBuf As Long,
pcbNeeded As Long, pcReturned As Long) As Long

Vamos a necesitar definir un tipo de variable:


Private Type PRINTER_INFO_1
flags As Long
pDescription As String
pName As String
pComment As String
End Type

Y declarar una constante


Const PRINTER_ENUM_LOCAL = &H2

El procedimiento donde ensayamos esta función permite presentar en un ListBox (LbPrinters)


todas las impresoras disponibles:

Esta rutina ha sido copiada, traducida, y ligeramente modificada de:


KPD-Team 1999
URL: http://www.allapi.net/
E-Mail: KPDTeam@Allapi.net
Gracias

Private Sub cmbListarPrintersLocales_Click()

Dim LongBuffer() As Long


' Array que almacena los punteros del búffer donde se encuentra la información de la impresora
Dim PrintInfo() As PRINTER_INFO_1
'Array con estructura tipo PRINTER_INFO_1 donde se guardarán los valores de cada
parámetro de las impresoras
Dim NumBytes As Long
'Este es el tamaño que le asignamos al buffer donde la API almacenará los datos. Debe ser
mayor que los bytes que vamos a obtener
Dim NumNecesario As Long
'Variable donde se introducirá el número exacto de bytes necesario para el buffer

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 27


Dim NumPrinters As Long
'Variable donde se introducirá el número de impresoras encontradas
Dim C As Integer, RetVal As Long
'C = Contador variable, RetVal = Valor de retorno de la función
'Obtiene la información de las impresoras locales (PRINTER_ENUM_LOCAL)
NumBytes = 3000
'Debe ser suficientemente largo para contener la información de todas las impresoras (Sin
pasarse)
ReDim LongBuffer(0 To NumBytes / 4) As Long
'ReDimensiona el array. Observe que un Long son 4 bytes
RetVal = EnumPrinters(PRINTER_ENUM_LOCAL, "", 1, LongBuffer(0), NumBytes,
NumNecesario, NumPrinters)
If RetVal = 0 Then
'RetVal será 0 si la función no se ha podido realizar correctamente. o más probable es que
hayamos puesto un número muy pequeño para NumBytes. Ahora ya conocemos el número de
Bytes necesario para contener toda la información ese número es NumNecesario. Hacemos
que NumBytes sea igual a NumNecesario
NumBytes = NumNecesario
ReDim LongBuffer(0 To NumBytes / 4) As Long 'Ahora ya es suficientemente largo
RetVal = EnumPrinters(PRINTER_ENUM_LOCAL, "", 1, LongBuffer(0), NumBytes,
NumNecesario, NumPrinters)
If RetVal = 0 Then ' Si vuelve a fallar ya es por otro motivo!
MsgBox "No se pueden enumerar las impresoras"
Exit Sub ' Se sale de este procedimiento
End If
End If
' Ahora mete el contenido de LongBuffer() en PrintInfo()
If NumPrinters <> 0 Then ReDim PrintInfo(0 To NumPrinters - 1) As PRINTER_INFO_1
'PrintInfo contiene a su vez 4 variables que almacenan toda la información de la impresora
'Recordamos la definición de PrintInfo
'Private Type PRINTER_INFO_1
' flags As Long
' pDescription As String
' pName As String
' pComment As String
'End Type

For C = 0 To NumPrinters - 1 'Bucle que coloca cada juego de información de LongBuffer() en


cada elemento de PrintInfo.Longbuffer(4 * c) = .flags, longbuffer(4 * c + 1) = .pDescription, etc.
'Para los valores tipo String, previamente se rellenan de espacios con la función Space y luego
les introduce el valor obtenido mediante la función lstrcpy.
PrintInfo(C).flags = LongBuffer(4 * C)
PrintInfo(C).pDescription = Space(lstrlen(LongBuffer(4 * C + 1)))
RetVal = lstrcpy(PrintInfo(C).pDescription, LongBuffer(4 * C + 1))
PrintInfo(C).pName = Space(lstrlen(LongBuffer(4 * C + 2)))
RetVal = lstrcpy(PrintInfo(C).pName, LongBuffer(4 * C + 2))
PrintInfo(C).pComment = Space(lstrlen(LongBuffer(4 * C + 3)))
RetVal = lstrcpy(PrintInfo(C).pComment, LongBuffer(4 * C + 3))

Next C
' Presenta el nombre de las impresoras
For C = 0 To NumPrinters - 1
LbPrinters.AddItem PrintInfo(C).pName
Next C
End Sub

El código no está nada mal. Aunque lleva comentarios con


el fin de entender el funcionamiento de esta función, hay
que reconocer que es largo. El resultado puede verse en la
figura. Están todas las impresoras disponibles.

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 28


Pero vamos a ver otro código que hace lo mismo sin usar Apis.

Private Sub cmdBuscarPrinters_Click()


Dim I As Integer
For I = 0 To Printers.Count - 1
LbBuscaPrinters.AddItem Printers(I).DeviceName
Next I
End Sub

El resultado es el de la figura de la izquierda. Seis


líneas frente a dos páginas. El buen programador usa
la sencillez de código como su mejor arma. Y si se
pueden usar 6 líneas en vez de 30, hay que usar 6
líneas.

La razón de que la propiedad DeviceName del objeto


Printer nos dé el nombre de las impresoras es que ese
código largo de la página anterior ya está
implementado en Visual Basic.

Solamente nos falta satisfacer la curiosidad de cómo


se selecciona una impresora (botón inferior) ¿Con Apis? Se puede. ¿Desea escribir otras dos
páginas de código, o le es suficiente con este?

Private Sub cmdSeleccionarPrinter_Click()


If LbBuscaPrinters = "" Then
MsgBox "Debe elegir una impresora"
Exit Sub
End If

Dim sImpresora As String, pPrinter As Printer


sImpresora = LbBuscaPrinters.Text
' Buscamos la impresora selecionada en la lista entre todas las impresoras existentes
For Each pPrinter In Printers
If UCase(pPrinter.DeviceName) = UCase(sImpresora) Then
Set Printer = pPrinter
'A partir de ahora, pPrinter será la impresora elegida a la que VB dirigirá la
‘impresión cada vez que citemos Printer.Print.
Exit For
End If
Next
End Sub

De las APIs queda mucho por estudiar. Pero ya debe ser el alumno quien ahonde en ello según
sus propias necesidades. Creo que con lo expuesto hay suficiente para empezar.

LSB Visual Basic Guía del Estudiante Cap. 17 Pág. 29


Visual Basic - Guía del Estudiante Cap. 18
Visual Basic e Internet

Internet es la tentación en la que actualmente todos los estudiantes quieren caer. Y tienen motivos para
ello. Internet ofrece unas posibilidades de comunicación como nunca las ha habido, lo que brinda unas
oportunidades inmensas al programador si analiza de forma pausada lo que la red le puede ofrecer.
Y digo si las analiza de forma pausada porque esa tentación en la que caen todos los estudiantes es
pretender crear un navegador similar al Internet Explorer o al Netescape, un correo que supere al
Eudora y un programa de FTP que sea capaz de bajarle la Enciclopedia Británica en menos de media
hora. Pero hay que ponerse con los pies en la tierra y comprender que esos programas llevan mucho
trabajo de muchos programadores, mucho tiempo de prueba y unos medios económicos y comerciales
tras ellos que hacen que esos productos tengan que ser necesariamente mejores que lo que puede
hacer un estudiante, por mucho interés e ilusión que ponga.

Sin embargo sí puede ser muy ilustrativo que en este curso nos propongamos la meta de hacer un
programa que sea al tiempo el mejor navegador, el mejor correo (por dos procedimientos), y el mejor
FTP que se pueda concebir, y encima que pueda hacer chat, ping y Telnet. Será el mejor, sin duda,
porque será el único que nos permita aprender a manejar los controles que Visual Basic nos tienen
reservados para los entornos IP.

Nota para alumnos expertos. Si de verdad es Ud. un experto y se lo sabe todo sobre IP puede saltar
directamente al tema Controles de Visual Basic para las redes IP. La colección Guía del Estudiante
está escrita pensando en quien no sabe y quiere saber. Por eso no puedo pasar pos alto conceptos de
nomenclatura de redes IP que se repetirán a lo largo del capítulo, y que seguro que a más de un alumno
le aportarán nuevos conocimientos. Si pese a ser un experto, su humildad le aconseja leérselo, verá que
a lo mejor se le aclara más de un concepto.

Redes IP. Protocolos de comunicación en redes IP


Una red IP es una red de comunicación basada en la transmisión bidireccional de paquetes. Cuando
decimos esto queremos expresar que la comunicación entre dos puntos de la red (entre dos ordenadores
conectados a la red) no es continua, sino que la información se parte en origen en pequeños trozos que
se envían por la red hasta el destino. Una vez allí, se vuelven a poner cada uno de los paquetes en su
sitio para volver a formar el bloque de información que teníamos en origen. Esta técnica permite
compartir al mismo tiempo los recursos de la red por muchos usuarios, sin que ninguno de ellos pueda
bloquear la red por el hecho de enviar una gran cantidad de información. Cada usuario podrá enviar el
mismo número de paquetes por unidad de tiempo (más o menos) por lo tanto quien deba enviar más
información tardará más tiempo que otro que tenga menos información. Y todo sin llegar a bloquear la
red. Eso sí, cuantos más usuarios estén presentes en un determinado momento, más lenta la veremos,
ya que nos corresponderá menos número de paquetes por unidad de tiempo.

El hecho de que la información original se trocee en paquetes que se envían a la red implica poner una
dirección de destino a cada uno de esos paquetes (para saber a quien van dirigidos) y la dirección del
origen, (para saber quien lo envía). De esta forma, la red sabe a quien debe entregar el paquete y el
destino sabe de quien procede. Todo esto lo hace el protocolo IP (Internet Protocol) Esto es como si IP
trabajase solamente de cartero. Coge paquetes en un buzón y los envía a su destinatario sin importarle
el contenido del paquete. Luego veremos lo de la dirección. Lo cierto es que el paquete llega al destino.

A este “nivel” de comunicación le llamaremos Nivel de Red. Si lo prefiere, también le puede llamar Nivel
de Enlace. Es problema de terminología. No se complique la vida. Al protocolo IP le podemos denominar
por tanto, Protocolo de Red.

Lo que no sabe el destino es el orden en el que tiene que colocar el paquete dentro del bloque total de
información. Debido a que el camino seguido por los paquetes no tiene porqué ser el mismo para todos,
es posible que se reciba primero un paquete que se ha transmitido con posterioridad. Por lo tanto será
necesario poder establecer el número de orden de cada uno de los paquetes dentro del grupo total de
LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 1
paquetes que se han generado para la transmisión. También será necesario en ciertos casos conocer si
el destino ha recibido correctamente el paquete. Estas cosas las hace el Protocolo de Transporte.

El protocolo IP tiene dos protocolos de transporte: el TCP y el UDP.

El TCP establece una comunicación en la que el origen envía un paquete y espera la confirmación del
receptor de que lo ha recibido. Si pasa un determinado tiempo sin recibir esa confirmación vuelve a
enviar el mismo paquete. Pudo haberse perdido el paquete que había enviado o también pudo perderse
la confirmación. En cualquier caso el origen vuelve a enviar y el receptor puede saber perfectamente lo
que ha ocurrido y colocar el paquete en su sitio si se había perdido inicialmente, o descartarlo si la
repetición se ha debido a que se había perdido la contestación. Cada paquete lleva un número que
indica el número de orden de ese paquete dentro del bloque total. El protocolo TCP es muy seguro.
Porque además de lo expuesto, tiene un procedimiento de cálculo de una Checksum que permite saber
si un paquete ha llegado sin ningún tipo de error. Si detecta error en un paquete, pide repetición.
También lleva el número del puerto por el que debe entrar esa información. Verá mas adelante lo que es
un puerto. Mediante el protocolo TCP podemos transportar un fichero enorme sin ningún tipo de error. Es
el que se usa normalmente en las redes IP. Por cierto, ¿Sabe que significa TCP? Transmision Control
Protocol , o como diría Cervantes, Protocolo de Control de Transmisión.

El protocolo UDP (que significa User Datagram Protocol) o Protocolo de Datagramas de Usuario es un
protocolo que envía paquetes sin esperar respuesta. No le preocupa que los paquetes se pierdan. UDP
usa menos recursos y por lo tanto es más rápido. Dependiendo del tipo de información que se envíe, a lo
mejor resulta más práctico enviar paquetes UDP que paquetes TCP. Sobre todo cuando son
informaciones muy cortas, que no sobrepasan la capacidad de un paquete. Dicen que no es un sistema
seguro, pero eso dependerá en gran medida del programa que hagamos. Dado que no es un sistema
seguro, deberemos implementar en el programa la secuencia de envío - confirmación de recibido que
tiene el TCP. Obviamente eso lo va a complicar un poco. Quizás por eso el protocolo usado
generalmente para transmisión de información es el TCP.

Le será muy familiar el TCP/IP. Es la combinación del protocolo TCP con IP. Y es momento ahora de
explicar con un ejemplo simulado como funciona TCP/IP. Imagínese que TCP coge el bloque de
información a transmitir y lo trocea en varios paquetes. A cada uno de ellos le añade el número de orden
que tiene ese paquete dentro del bloque total de información, calcula el Checksum que le corresponde y
se lo anexa. Con esos datos ya somos capaces de volver a restituir el bloque de información completo.
Pero hace falta todavía enviarlo al destinatario. Para ello se lo entregamos al protocolo IP, que lo mete
en un "sobre" donde le apunta la dirección y el remitente. Y lo suelta a la red. La red solamente ve la
dirección y el remitente (Por favor que nadie se lo crea a pies juntillas, no es así exactamente, esto es
solamente un ejemplo) y reencamina el paquete a través de los enrutadores (routers) para hacerlo llegar
a su destino. El destinatario abre el sobre, analiza el Checksum, mira el número de paquete que es,
comprueba que no lo tiene todavía, y entonces crea un pequeño paquete en el que dice que ha recibido
correctamente el paquete con ese número. Lo mete en un sobre IP donde pone como dirección el
remitente del paquete recibido y como remite su propia dirección, y lo envía a la red. Ya se encargará la
red de hacerlo llegar a su destino. Al recibirlo (lo recibe el terminal que estamos llamando origen) ve que
le dan conformidad al paquete enviado, y se despreocupa ya de ese paquete. Otro tema sería que el
destino hubiera recibido el paquete y le saliera el Checksum erróneo. Le mandaría un paquete al origen
comunicándoselo. Entonces el origen se lo volvería a enviar. Lo mismo ocurriría si el origen, pasado
cierto tiempo, no ha recibido confirmación de recibo de un paquete, sea afirmativa o negativa esta
confirmación. El origen vuelve a enviar el paquete, hasta que reciba confirmación de que fue bien
recibido. ¿Se da cuenta ahora de porque, de vez en cuando, parece que se paraliza la red? El orden de
envío de paquetes no tiene porqué ser estricto. No es necesario haber recibido la conformidad del
paquete anterior para enviar el siguiente.

Veamos ahora lo de la dirección. Decíamos que IP pone la dirección del destinatario y del remitente.
Esas direcciones son un conjunto de cuatro números del 0 al 255, separados por un punto. Por ejemplo,
podría ser 195.236.12.56 Así de frías son las direcciones de Internet. Como cada número puede tomar
los valores del 0 al 255, la numeración total de Internet puede llegar a 4.228.250.625 No son mucho
esos cuatro mil doscientos millones. Piense que somos seis mil millones de personas en el mundo. Por
eso ha habido que buscar formas de aprovechar al máximo las direcciones IP. No es objeto de este
curso su estudio, pero digamos que se logra a base de que las redes de área local conectadas a Internet

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 2


se conectan solamente con un número, e internamente tienen otro (el número interno no coincide con
ninguno de Internet, pero se repite en todas las redes de área local). Otra forma de aprovechar la
numeración es asignar números dinámicamente. Eso ocurre cuando nos conectamos a Internet desde
nuestras casas. Mientras dura la conexión, nuestro ISP (Proveedor de Servicio de Internet) nos cede un
número IP de los que le han asignado a él. Cuando nos desconectamos, ese número se lo da al
siguiente que se conecte. Por eso, en nuestras casas, cuando nos conectamos a través de la conexión
telefónica a redes, no tendremos siempre el mismo número IP.

Esta Dirección IP la usa el Protocolo de Red, es decir El Internet Protocol, que como decíamos antes,
era como un cartero que recoge una carta del Origen y la pone en el Destino sin saber que es lo que
contiene. Ese origen y destino son máquinas, es decir, ordenadores que están conectados a la red.

Nota acerca de las direcciones IP. Existe una serie de direcciones IP que no se pueden usar en
Internet debido a que están reservadas para redes de área local. Esto se hace así para que nunca pueda
haber error entre direcciones. Si asignamos a un equipo interior a una red un número posible en Internet,
un Router que esté separando la red de área local del mundo Internet podría equivocarse y enviar hacia
fuera un paquete interno a nuestra red. Por eso se han reservado esas direcciones. Son estas

De la 10.0.0.0 a la 10.255.255.255
De la 172.16.0.0 a la 172.31.255.255
De la 192.168.0.0 a la 192.168.255.255

Tampoco se pueden usar las direcciones:

0.0.0.0 a la 0.255.255.255 Se usan para llamar al ordenador local principal


255.0.0.0 a la 255.255.255.255 Son direcciones de difusión (transmisión hacia todos los equipos)
127.0.0.0 a la 127.255.255.255 que se usan para funciones internas a la máquina. Técnicamente
hablando se dice que estas direcciones son para LoopBack

IP Versión 6
Como esto de Internet lo único que puede hacer es subir, y los 4.200 millones de direcciones se van a
quedar cortas tarde o temprano, se está definiendo una nueva versión de direcciones IP, la esperada
versión 6, que consistirá en direcciones de 128 bits, frente a los 32 actuales. Si pensamos que cada bit
que ampliemos doblamos la capacidad, vemos que la cifra de direcciones posibles sobrepasa las
necesidades actuales. (Por sobrepasar, sobrepasa la capacidad de mi calculadora y el resultado es
Overflow). Esta solución de 128 bits permitirá conectar cualquier ordenador de una RAL con un número
IP verdadero, es decir, un número de la red Internet. Pero eso ya lo veremos en la próxima Guía del
Estudiante.

Puertos de Comunicación.
Vamos a ver un concepto nuevo: el Puerto de Comunicación. Hasta ahora hemos hablado de
direcciones de máquina que son las que ve el protocolo IP. Dentro de una máquina podemos tener
varios servicios (Correo, Ftp, www, o cualquier otro programa que nosotros hagamos) Cuando llega uno
de esos paquetes que contienen información, la máquina debe saber reconocer a que servicio está
destinado. Eso lo sabe mediante el Puerto de Comunicación al que va dirigido el paquete.

El puerto de Comunicación no es un puerto físico. Volvemos a lo de siempre: es una forma de hablar. Lo


mismo que la dirección IP nos conduce a una máquina, un puerto nos lleva a un servicio dentro de esa
máquina. Cuando enviamos una carta, el cartero (Protocolo IP) la lleva al domicilio indicado en el sobre.
Imagínese que ese domicilio es en edificio de oficinas. Debemos saber ahora el número de la oficina
donde la debemos entregar. Pero el trabajo del cartero ya finalizó cuando nos ha entregado la carta en
portería. Para saber el número de la oficina debemos abrir el sobre y ver a que oficina está dirigida. De
esto se encarga el Protocolo de Transporte (TCP o UDP) que analiza el contenido del paquete y mira el
valor de dos bytes que indican el número del puerto. Esos dos bytes son los que indicarían el número de
la oficina en ese edificio de nuestro símil postal. Pero tenga en cuenta siempre que el puerto no indica
por donde entra la información a la máquina (entra por la placa de red, que tiene asociado una dirección
IP) sino el servicio (un programa) al que va destinada la información. Dado que el número del puerto se
expresa con dos bytes, los números de puerto posibles son del 1 al 65536.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 3


Los 1024 primeros puertos están reservados para distintos servicios de comunicación dentro de la
máquina. No los use para sus aplicaciones. Los servicios más conocidos utilizan los siguientes puertos:

1 - tcpmux 5 - rje 7 - echo 9 - discard 11 - systat 13 - daytime


15 - netstat 17 - qotd 18 - send/rwp 19 - chargen 20 - FTP (data) 21 - FTP (control)
22 - ssh, pcAnywhere 23 - Telnet 25 - SMTP 27 - ETRN 29 - msg-icp
31 - msg-auth 33 - dsp 37 - time 38 - RAP 39 - rlp
42 - nameserv/WINS 43 - whois, nickname 49 - TACACS/Login Host Protocol
50 - RMCP 53 - DNS 57 - MTP 59 - NFILE 63 - whois++ 66 - sql*net
67 - bootps 68 - bootpd/dhcp 69 - Trivial File Transfer Protocol (tftp)
70 - Gopher 79 - finger 80 - www-http 88 - Kerberos, WWW 95 supdup
96 – DIXIE 98 - linuxconf 101 - HOSTNAME 102 - ISO, X.400, ITOT
105 - cso 106 – poppassd 109 - POP2 110 - POP3
111 - Sun RPC Portmapper 113 - identd/auth 115 - sftp 117 - uucp
119 - NNTP 120 - CFDP 123 – NTP 124 - SecureID 129 - PWDGEN
133 - statsrv 135 loc-srv/epmap 137 - netbios-ns 138 - netbios-dgm (UDP)
139 - NetBIOS 143 – IMAP 144 NewS 152 BFTP 153 - SGMP 161 - SNMP
175 – vmnet 177 - XDMCP 178 -NextStep Window Server 179 - BGP 180 - SLmail admin
199 - smux 210 - Z39.50 218 – MPP 220 - IMAP3 259 - ESRO 264 -FW1_topo
311 Apple WebAdmin 350 - MATIP type A 351 - MATIP type B
363 - RSVP tunnel 366 - ODMR (On-Demand Mail Relay)
387 - AURP (AppleTalk Update-Based Routing Protocol) 389 - LDAP 407 - Timbuktu
434 - Mobile IP 443 – ssl 444 - snpp, Simple Network Paging Protocol 445 - SMB
458 - QuickTime TV/Conferencing 468 - Photuris 500 - ISAKMP, pluto
512 - biff, rexec 513 who, rlogin 514 - syslog, rsh 515 - lp, lpr, line printer
517 - talk 520 - RIP (Routing Information Protocol) 521 – RIPng 522 - ULS
543 - KLogin, AppleShare over IP 545 – QuickTime 548 AFP
554 - Real Time Streaming Protocol 555 - phAse Zero 563 NNTP over SSL
575 - VEMMI 581 Bundle Discovery Protocol 593 - MS-RPC 608 - SIFT/UFT
626 Apple ASIA 631 - IPP (Internet Printing Protocol) 635 - mountd (Linux)
636 – sldap 642 - EMSD 648 - RRP (NSI Registry Registrar Protocol)
660 - Apple MacOS Server Admin 666 - Doom 674 - ACAP
687 - AppleShare IP Registry 705 - AgentX for SNMP 901 - ISS Real Secure Sensor Port
993 - s-imap 995 - s-pop 1080 - SOCKS 1085 - WebObjects 1243 - SubSeven
1338 - Millennium Worm 1352 - Lotus Notes 1381 - Apple Network License Manager
1417 - Timbuktu 1418 - Timbuktu 1419 - Timbuktu 1433 - Microsoft SQL Server
1434 - Microsoft SQL Monitor 1503 - T.120 1521 - Oracle SQL 1525 - prospero
1526 - prospero 1527 - tlisrv 1645 - RADIUS Authentication
1646 - RADIUS Accounting 1680 - Carbon Copy 1701 - L2TP/LSF
1717 - Convoy 1720 - H.323/Q.931 1723 - PPTP control port
1755 - Windows Media .asf 1758 - TFTP multicast 1812 - RADIUS server
1813 - RADIUS accounting 1818 - ETFTP 1973 - DLSw DCAP/DRAP
1985 - HSRP 1999 - Cisco AUTH 2001 - glimpse 2049 - NFS
2064 - distributed.net 2065 - DLSw 2066 – DLSw 2106 - MZAP 2140 – DeepThroat
2301 Compaq Insight Management Web Agents 2336 - Apple UG Control
2427 - MGCP gateway 2504 – WLBS 2535 - MADCAP 2543 - sip
2727 - MGCP call agent 2592 netrek 2628 - DICT
2998 - ISS Real Secure Console Service Port 3000 - Firstclass 3031 - Apple AgentVU
3128 squid 3130 - ICP 3150 - DeepThroat 3283 - Apple NetAssitant
3288 COPS 3305 – ODETTE 3306 - mySQL 3389 - NT Terminal Server
4321 rwhois 4333 - mSQL 4827 - HTCP 5004 - RTP 5005 – RTP
5010 - Yahoo! Messenger 5060 - SIP 5190 – AIM 5500 - securid 5501 - securidprop
5423 - Apple VirtualUser 5631 - PCAnywhere data 5632 - PCAnywhere 5800 – VNC
5801 – VNC 5900 - VNC 5901 - VNC 6000 - X Windows 6667 – IRC
6670 - VocalTec Internet Phone, DeepThroat 6699 – napster 6776 - Sub7 6970 - RTP
7007 - MSBD, Windows Media encoder 7070 RealServer/QuickTime
7648 - CU-SeeMe 7649 - CU-SeeMe 8010 - WinGate 2.1 8080 - HTTP 8181 – HTTP
8383 - IMail WWW 13223 - PowWow 13224 – PowWow 14237 – Palm
LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 4
14238 - Palm 18888 - LiquidAudio 23213 – PowWow 23214 - PowWow 23456 – EvilFTP
26000 – Quake 27001 - QuakeWorld 27015 - Half-Life 27960 - QuakeIII
30029 - AOL Admin 31337 - Back Orifice 40193 – Novell
45000 - Cisco NetRanger postofficed Multicast hidden ICMP Type hidden
32773 - rpc.ttdbserverd 32776 - rpc.spray 32777 - rpc.walld 32779 - rpc.cmsd
38036 - timestep

(Si quiere una información mayor acerca del número de los puertos, busque en su ordenador un fichero
llamado Services. Ese fichero es el que tiene los números de los puertos correspondientes a cada
servicio instalado en su ordenador.

Dominios. Administración de dominios. Servidores de DNS


Dado que el número 217.126.179.96 no nos dice nada, Internet ha previsto que podamos poner una
dirección más amigable. Podría ser por ejemplo, laguiadelestudiante.es y seguro que todo el mundo
sabría a quien se refiere esa dirección. A esa dirección le denominamos DNS (Sistema de Nomenclatura
de Dominios) Y ahora le vendrá la pregunta siguiente ¿Qué es un dominio?. Un dominio es una palabra
que define una parte de Internet. En la dirección anterior, un dominio es es que significa España. Dentro
de España, hay una parte llamada laguiadelestudiante. El DNS se compone en este caso de dos
palabras. Si algún día la Guía del Estudiante llega al sitio que se merece, puede haber varias partes
dentro de su dominio (editorial, correo, ventas) y tendríamos direcciones con tres palabras:

editorial.laguiadelestudiante.es correo.laguiadelestudiante.es ventas.laguiadelestudiante.es

Observe que las palabras van separadas uno de otro mediante un punto. Existe un dominio para cada
país. (es para España, cu para Cuba, ar para Argentina, etc.) Pero aparte existe una serie de dominios
que no corresponden a ningún país, que se refieren a organizaciones. Por ejemplo, com para
organizaciones comerciales, edu para organismos de educación, gov para organizaciones
gubernamentales, mil para organizaciones militares, int para organismos internacionales, org para otras
organizaciones, net para organizaciones que manejan recursos de la red. Lo de que no pertenecen a
ningún país concreto es solo teórico. La mayoría de ellas (edu, gov, mil) pertenecen a USA. Tampoco se
merecen ninguna crítica por ello. Han sido los artífices de Internet.

Buzones de correo. Un dominio identifica a una máquina. (Un ordenador conectado a la red)
Imagínese que ese ordenador es un servidor de correo. En el caso del ejemplo,
correo.laguiadelestudiante.es es el DNS del ordenador que gestiona el correo de empresa La Guía del
Estudiante. En ese ordenador hay varios buzones para varios usuarios. Uno de los usuarios es Luis
Suárez. Parece lógico que su buzón se llame suarez. Para saber que pertenece a la máquina de correo
citada, el nombre de ese buzón deberá llevar el DNS de esa máquina. No se podrá poner como nombre
del buzón suarez.correo.laguiadelestiante.es ya que suarez no es un dominio, es un buzón. El nombre
de un buzón se separa del DNS mediante el carácter @. Suarez@correo.laguiadelestudiante.es es el
nombre de un buzón único en el mundo. Vamos a avanzar un poco más. Imagínese que ese servidor
de correo tiene varios clientes cuyo apellido es suarez. Deberemos distinguir uno de otro. Para ello basta
con seguir el mismo método que con los dominios. Encadenar varios nombres separados con un punto.
Por ejemplo, podríamos poner cono nombre de buzón luis.suarez@laguiadelestudiante.es Ya puede enviar
tranquilamente sus mensajes a ese buzón. Los enrutadores de internet no se preocuparán de lo que hay
a la izquierda de la @. Buscarán la máquina correo.laguiadelestudiante.es. Una vez que la encuentren,
depositarán el mensaje y será esa máquina quien se encargue de meter ese mensaje en el buzón
luis.suarez de su propiedad.

¿Cómo se traduce el DNS correo.laguiadelestudiante.es al número 217.126.179.96? Mediante unos


aparatos conectados en la red que se denominan servidores de DNS o servidores de dominios. Cuando
una máquina quiere saber a que número corresponde ese DNS se dirige a su servidor de DNS (del que
necesariamente debe conocer su número IP). Le pregunta. Si lo conoce, se lo dice. Si no lo conoce, este
servidor de DNS lo buscará en otros servidores de DNS. Estos harán lo mismo. Hasta que uno de ellos
llegue al servidor de DNS que conoce todos los dominios de España (Hay varios. Uno lo tiene
Telefónica, otro una institución llamada RedIris, dependiente del Centro Superior de Investigaciones
Científicas CSIC que es quien tiene las competencias sobre dominios). Ese servidor se lo dirá. Y a partir
LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 5
de ahora ya puede meter los paquetes TCP en el sobre IP y poner en este la dirección correcta de 4
números que el servidor DNS le ha facilitado. ¿Se da cuenta por segunda vez de lo que puede hacer
que veamos que la red se paraliza por momentos?

(No me voy a extender más en esto. Ni le puedo remitir al libro Internet - Guía del estudiante, puesto
que ni existe ni existirá. Hay mucha bibliografía sobre el tema que puede consultar

El protocolo TCP/IP no se utiliza solamente en Internet. Las redes de Area Local en su gran mayoría lo
utilizan. Por lo tanto lo que se va a explicar en este capítulo no solamente le va a servir para Internet.
Puede hacer programas que trabajen sobre una red de área local que usa los mismos controles.

Forma de conectarse a Internet


Para conectarse a Internet se necesita que un suministrado de servicios de Internet (ISP) nos conecte.
Internet es una red muy grande, pero que se diferencia muy poco de una red de área local. Solamente
en su extensión. Igual que una red de área local tiene puntos de conexión, Internet también los tiene,
pero esos puntos no están en cualquier esquina. Están precisamente en las dependencias de los ISP,
conectados a la red a través de líneas de comunicación de datos suministradas por una empresa de
telecomunicaciones, que en España es casi con carácter de monopolio, Telefónica. Esos ISP que tienen
la conexión real a Internet deben suministrar una parte de esa conexión a cada usuario que se quiera
conectar. Existen varias formas de hacerlo: ADSL, Conexión telefónica a redes, conexión a través de una
red de área local. Veamos como se conecta de cada una de estas formas, utilizando palabras sencillas,
aunque ello vaya en detrimento de la rigurosidad técnica.

ADSL (Asimetric Data Suscriber Line). Aprovechando una línea telefónica existente, se envía
superpuesto al servicio telefónico unas señales de datos, que no interfieren para nada el uso del teléfono
conectado a esa línea. Esta técnica supone una modulación de los datos sobre dos portadoras a varios
cientos de kilociclos (la frecuencia de la portadora depende del ancho de banda contratado) por lo que
las pérdidas son elevadas. Esto implica que el módem ADSL instalado junto al terminal telefónico deberá
estar muy cerca de la central telefónica desde la que envían los datos (Creo que el máximo son unos 2
kilómetros) Por lo tanto, es difícil instalar esta opción en abonados rurales, o en zonas urbanas con
instalación de cables muy viejas. Pueden contratarse velocidades de 128 a 512 Kbytes en sentido
Usuario -> Internet, y de 256 a 2048 en sentido Internet -> Usuario. Esta asimetría se debe a que
normalmente son mas los datos que se “bajan” que los que se envían, y de esta forma se optimizan los
recursos del sistema. Mediante esta conexión, estamos conectados continuamente a Internet, y
generalmente se tiene un número IP real fijo, pero existen compañías que lo que están enviando a través
de esa conexión de alta velocidad es una toma de una red de área local que a su vez está conectada a
Internet. El número IP, en el caso que le den una número real de Internet, ninguna empresa le garantiza
que se lo vayan a conservar para siempre. Creo que ADSL es hoy por hoy el mejor sistema de conexión
a Internet.

Conexión mediante la Conexión Telefónica a redes. Para esta forma de conexión, los ISP disponen
de varias direcciones IP. Es muy normal que cada ISP tenga uno o varios paquetes 256 direcciones,
pero eso dependerá del trafico real que tenga. Este ISP se va a reservar algunas de esas direcciones
para su uso particular (Una al menos para que se le pueda llamar y comunicarse con otros servidores
desde dentro de la red, otra para el servidor de páginas Web, servidor de correo, servidor DNS si lo
tiene, etc.) y el resto las va a asignar durante el tiempo que dure la conexión a sus clientes. Esta
asignación de direcciones se le denomina asignación dinámica. Cuando nos conectamos a Internet a
través de la conexión telefónica a redes tendremos una dirección. La próxima vez tendremos otra. Por
eso, en el ámbito particular no podemos dar una dirección IP para que nos llamen, ya que es variable.
Deberemos pedir la conexión a nuestro ISP que nos pedirá el nombre de usuario y la contraseña. Esta
operación la realiza el acceso telefónico a redes de Windows. Si coinciden nombre y contraseña con las
que tiene el ISP en su banco de datos, nos asigna un número IP de los que tenga disponible y ya
estamos conectados.

Conexión a través de Red de Area Local. Este es el caso de conectarse mediante una RAL o
mediante la mayoría de las conexiones rápidas que nos brindan las compañías de telecomunicación por
cable. En este caso, la conexión a Internet se realiza en un punto de la red, mediante un ordenador o
LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 6
hub denominado Gateway, Puerta de Enlace o servidor Proxy. La puerta de enlace este tiene dos
entradas de red, una conectada a Internet (A través de un módem o directamente mediante una línea de
datos) y otra conectada a la RAL. En este caso, cada ordenador conectado a la RAL tiene un número IP,
pero no es un número IP de Internet, sino de la red interna. No podremos hacer ping a ese número
desde un puesto conectado directamente a Internet. La transferencia de los datos desde Internet a cada
uno de los ordenadores lo gestiona el software de la puerta de enlace, siendo completamente
transparente para el ordenador que se está conectando.

Una vez conectados, sea cual sea el medio utilizado para ello, ya estamos en la red. Ahora ya podemos
hacer Ping o Telnet a otro ordenador que también esté conectado. No se preocupe por no saber que es
hacer ping o telnet. Eso es cosa de los gurús informáticos. Algunos alumnos, afortunadamente los
menos, creían que estaban conectados a Internet solamente cuando se abría el navegador y les
mostraba la página Web de su ISP. Otros se creían plenamente conectados cuando eran capaces de
abrir su buzón de correo mediante el Outlook Express. Pero esos efectos no son por estar conectados,
sino por Abrir un Servicio.

Esto nos introduce en el concepto de servicio de Internet. La conexión TCP/IP que habíamos establecido
sólo es el soporte de comunicación para que pase por él un servicio. Uno de ellos puede ser el de
páginas Web.(http), otro el de correo, (POP3 y SMTP), otro el de FTP (ftp) , otro el Chat (irc).

Veamos cada uno de ellos.

http (hiper text transfer protocol Protocolo de transferencia de hipertexto) es el servicio para recibir
páginas Web. Las páginas Web están diseñadas de tal forma que contengan muy poca información
(para que se puedan bajar rápidamente) Existen lenguajes que pueden hacer eso (HTML), que con muy
poca información generan páginas preciosas. Pero la poca información que tienen se tiene que cubrir
con algo: con un navegador, que es como un editor de texto pero un poco más complicado, porque es
capaz de componer la página con toda su belleza a partir de esa información tan escasa.

ftp (File Transfer Protocol Protocolo de transferencia de ficheros) Se usa para enviar o recibir fichero
completos. Es el servicio que usa cuando se baja un programa de la red.

SMTP (Single Mail Tranfer Protocol Protocolo simple de transferencia de correo) Se utiliza para enviar
mensajes de correo desde el usuario al servidor de correo y para el tráfico de estos mensajes entre
servidores de correo.

POP 3 (Post Office Protocol 3 Protocolo de la Oficina de Correo) Se utiliza para que el servidor de
correo envíe los mensajes de correo al usuario.

Irc (Internet Relay Chat Reenvío de Chat por Internet) Mediante este protocolo una máquina a la que
han accedido varios usuarios recibe mensajes escritos de uno de ellos y lo retransmite a los demás.)

Cada uno de estos servicios tiene asignado un puerto. Esos puertos puede verlos en la lista que tiene
más atrás. Hay mas servicios, pero con esto creo que tenemos suficiente para comenzar a hablar de lo
que puede hacer Visual Basic con todos estos servicios.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 7


LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 8
Controles de Visual Basic para las redes IP
Hemos llegado por fin al Visual Basic puro. Vamos analizar los controles que nos tiene preparados para
explotar los recursos de la red. Para cada uno de los servicios anteriores existe un control. Podemos
resumirlos en la siguiente lista:

Para la conexión: Control Winsock (Puede implementar con él cualquier servicio)


Para http Control WebBrowser, Control Internet Transfer Control
Para FTP Control Internet Transfer Control
Para POP3, SMTP Controles auxiliares MapiSesion y MAPIMessages

Comencemos por el principio. Por el control que nos permite comunicarnos con otro ordenador mediante
TCP y UDP . El Control Winsock

Control Winsock
El control WinSock permite conectarse a un equipo remoto e intercambiar datos con los Protocolos UDP
y TCP. Ambos protocolos se pueden usar para crear la comunicación con cualquier servicio de los
expresados anteriormente. Podemos crear también aplicaciones que residan en un servidor al que
accedemos desde varios clientes. Estamos en ese caso creando aplicaciones Cliente - Servidor

El control Winsock podríamos decir que es el control más elemental de los controles que VB dedica a las
redes IP, ya que lo único que hace por sí es conectarnos. No implementa ningún servicio. Eso se lo
tenderemos que hacer nosotros con nuestro programa. Hay controles que nos dan directamente la
conexión y el servicio para el que han sido diseñados (WebBrowser, Internet Transfer Control) Con este
sólo tenemos la conexión, pero con muchos datos y mucho control sobre ella. Quizás por eso este es el
más bonito. Una vez con la conexión establecida, podemos establecer un servicio utilizando código puro
y duro. Tiene esa opción o usar los controles específicos que Microsoft y otras firmas le han preparado
para que Vd. trabaje menos.

El control Winsock hay que meterlo en la caja de herramientas. (Proyecto | Componentes) El nombre
del control es Microsoft Winsock Control 6.0 Solamente se ve en tiempo de diseño. Tiene esta forma:

Fig.1 Icono que representa el control winsock


La conexión con la red puede que esté establecida de antemano (caso de una Red de Area Local o
conexión a Internet a través de ADSL) o tenga que realizarla mediante la conexión telefónica a redes. En
cualquiera de los dos casos, el control Winsock comenzará a trabajar una vez que la conexión esté
establecida. Pero para poder comunicarse con el otro equipo, deberá conocer una serie de parámetros
de su PC, parámetros que posiblemente tenga que pasárselos al otro equipo para que le reconozca y le
permita establecer el diálogo. El control Winsock realiza esas tareas que le permiten conocer los
parámetros de su equipo. Se lo puede presentar simplemente leyendo algunas de sus propiedades.

Primera tarea ¿Qué dirección IP tiene mi equipo?


Esa es la primera pregunta que se le puede ocurrir. Decíamos más atrás que cuando nos conectamos a
Internet a través de conexión telefónica a redes no sabemos en principio que dirección IP tenemos.
Incluso cuando hacemos un programa para instalarlo en una Red de Area Local (RAL) que tiene un
número IP fijo, a lo mejor nos interesa obtener automáticamente ese número para evitar tener que
personalizar el programa para cada uno de los ordenadores. El control WinSock nos permite conocer el
número IP de nuestra conexión. Esto se logra mediante la propiedad LocalIP

Propiedad LocalIP
Devuelve la dirección IP de la máquina local en el formato xxx.xxx.xxx.xxx Es de sólo lectura y no está
disponible en tiempo de diseño.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 9


Sintaxis MiVariable = NombredelWinSock.LocalIP

MiVariable será una variable de tipo String. Si la dirección de su equipo es la 127.0.0.1 significa que no
está conectado.

Segunda tarea ¿Qué nombre tiene mi equipo?


Cuando nos conectamos a otro equipo, necesitaremos decirle quien somos. Esto se logra buscando el
nombre de nuestro equipo. Ese nombre se lo hemos introducido al instalar Windows. Vea un poco mas
adelante como se hace eso. Para leer el nombre de nuestro equipo utilizaremos la propiedad
LocalHostName del control Winsock.

Propiedad LocalHostName
Devuelve el nombre de la máquina local. Es de sólo lectura y no está disponible en tiempo de diseño.

Sintaxis MiVariable = NombredelWinsock.LocalHostName

(MiVariable será una variable tipo String)

Determinar el nombre del equipo


Para averiguar y cambiar el nombre del equipo

1.En la Barra de tareas del equipo, haga click en Inicio.


2.En el elemento Configuración, haga click en Panel de control.
3.Haga doble clic en el icono Red.
4.Haga clic en la pestaña Identificación.
5.El nombre del equipo aparecerá en el cuadro Nombre del equipo o Nombre del PC.

Si desea cambiarlo, teclee el nombre nuevo y haga click en Aceptar. Como es habitual en Windows,
deberá reiniciar el equipo para que tenga efecto el cambio.

Tercera tarea: Establecer el protocolo


El protocolo es el tipo de comunicación que se va a establecer, UDP o TCP. Esto se realiza mediante la
propiedad Protocol. Puede establecerse en tiempo de diseño, en la ventana de propiedades, o en tiempo
de ejecución. Normalmente una aplicación trabaja solamente en UDP o en TCP, por lo que esta
propiedad debe establecerse o bien en diseño, o inmediatamente después de iniciarse.

Propiedad Protocol
Devuelve o establece el protocolo, TCP o UDP

Sintaxis NombredelControlWinsock.Protocol = Valor

Donde Valor = 0 (sckTCPProtocol) para establecer protocolo TCP


Valor = 1 (sckUDPProtocol) para establecer protocolo UDP

El control debe estar cerrado para poder establecer esta propiedad. Si lo tiene abierto, debe cerrarlo
previamente mediante el método Close.

Cuarta tarea: Establecer los datos del equipo remoto

Aquí debemos distinguir si queremos enviar información o si deseamos recibirla. Ya tenemos que
comenzar a pensar en un concepto que seguro que le suena: cliente y servidor.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 10


Cuando un equipo quiere enviar información debe conocer la dirección completa del equipo al que va a
llamar. La dirección completa es su dirección IP y el puerto al que va dirigida la información. Si el equipo
va a recibir, lo único que debemos decirle es el puerto por el que debe estar escuchando. No necesita
conocer más datos, ya que la dirección IP propia ya la conoce y no necesita conocer ningún dato del
equipo que le va enviar información.

Una aplicación es servidor cuando está escuchando. Así de fácil. (Recuerde el capítulo donde vimos el
DDE, pues el concepto cliente servidor en el tema del establecimiento de la comunicación es el mismo).
Si una aplicación escucha es que otra puede querer enviarle información. Esa aplicación que quiere
enviar información será la aplicación cliente. A poco que nos esforcemos, con este concepto elemental
de aplicación cliente – servidor, una aplicación puede ser cliente en un momento y servidor en otro.
Cuando se hable de aplicación cliente, ya en términos de la función que realiza esa aplicación, se
denomina aplicación servidor a aquella que está dispuesta para enviar información al cliente, o realizar
alguna operación con los datos que el cliente le envía. Pero en este caso, estamos hablando de cliente –
servidor visto desde el punto de vista de las comunicaciones. No se extrañe por lo tanto, que esa
definición tan simple de que una aplicación será servidor cuando está escuchando y cliente cuando está
enviando información.

Para el equipo cliente.

Si queremos enviar información, es decir, si queremos que nuestra aplicación sea una aplicación cliente,
debemos indicarle al Winsock el número IP o el DNS de la máquina con la que queremos conectar. Esto
lo establecemos con la propiedad RemoteHost. También le debemos indicar el número del puerto en el
que nos está esperando esa máquina. Esta información se la introducimos con la propiedad
RemotePort. Nunca le debemos forzar el puerto propio.

Propiedad RemoteHost
Devuelve o establece el equipo remoto al que se van a enviar los datos, o el equipo del que los recibe. El
equipo remoto se le puede identificar por su número IP o por su DNS.

Sintaxis NombredelControlWinsock.RemoteHost = “217.126.179.96”


NombredelControlWinsock.RemoteHost = “FTP://ftp.laguiadelestudiante.com”

VariableTipoString = NombredelControlWinsock.RemoteHost

Esta propiedad puede cambiarse en tiempo de ejecución cuantas veces sea necesario, para encaminar
los datos transmitidos a uno u otro equipo remoto.

Otro parámetro que es necesario introducir al Winsock cuando nuestra aplicación es una aplicación
cliente (envía información) es el puerto del equipo remoto al que vamos a enviar información. El puerto
destino dependerá del servicio que estamos implementando en nuestra aplicación. Este parámetro se
introduce en la propiedad RemotePort.

Propiedad RemotePort
Devuelve o establece el número del puerto remoto con el que conectar. El valor pasado en esta
propiedad es un Long comprendido entre 1 y 65535. El numero predeterminado es el 80.

Sintaxis NombredelControlWinsock.RemotePort = puerto

En una aplicación cliente (recibe información) no se puede establecer esta propiedad.

Ya tenemos establecidas las propiedades que necesita un control Winsock para enviar datos a un equipo
remoto. Veamos ahora como se establece la comunicación.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 11


Para el equipo servidor

El equipo que va a recibir información solamente necesita conocer el puerto por el que debe escuchar.
Esto se lo decimos mediante la propiedad LocalPort.

Propiedad LocalPort
Devuelve o establece el puerto local que desea usar. Es de lectura y escritura, y está disponible tanto en
tiempo de diseño como en tiempo de ejecución.

Esta propiedad solamente debe utilizarse para poner Winsock a recibir. Cuando va a transmitir datos,
aunque puede asignar un puerto determinado para enviarlos es mucho mas prudente dejar al Winsock
que utilice el que quiera. De esta forma se asegura que siempre emitirá a través de un puerto libre.
(Experiencia propia: Si asigna un puerto determinado para transmitir lo mas probable que le va a pasar
es que se le cuelgue el ordenador) Para asegurarse de que no ha asignado ningún puerto, basta con
poner el valor 0 en esta propiedad.

El valor devuelto por esta propiedad es un Long.

Sintaxis NombredelWinsock.LocalPort = Número

Quinta tarea: Establecer comunicación con el equipo remoto


Para esta tarea también debemos distinguir si vamos a recibir información o a enviarla y el protocolo que
estemos usando (TCP o UDP)

Comunicación por UDP


Vamos a comenzar a ver como nos podemos comunicar con el Winsock a través de UDP. El protocolo
UDP permite enviar y recibir información sin establecer previamente una comunicación. Así de
simple. Una vez establecidos las propiedades descritas mas atrás, tanto el equipo transmisor como el
receptor están ya preparados para trabajar. No hace falta ni poner a escuchar al receptor ni ordenar al
transmisor que contacte con el receptor, cosa que como veremos mas adelante, es necesario cuando se
trata de una comunicación mediante el protocolo TCP.

Esta sencillez del protocolo UDP hace que sea muy válido para una aplicación en la que no sea
imprescindible la seguridad de la comunicación. Un ejemplo de aplicación con transmisión con protocolo
UDP podría ser el comprobar que ordenadores de están encendidos en un determinado momento,
envío de mensajería interna a través de Red de Area Local, etc. Pero eso sí, UDP no sirve para
conectarse a través de Internet, ya que los servidores de Internet cortan el paso a los paquetes UDP.
Pero el hecho de que no sirvan para Internet no debe hacernos olvidar este protocolo tan sencillo para
comunicaciones a través de una RAL interna.

Por lo tanto, para paquetes UDP no hace falta hacer nada para establecer la comunicación con el equipo
remoto, ni para transmitir ni para recibir.

Comunicación por TCP


Aquí sí debemos establecer previamente la conexión. De hecho, se dice de TCP que es un protocolo
orientado a conexión. Veamos que hay que hacer para transmitir y recibir con TCP

Para el equipo cliente (Transmisor)

El equipo que desea enviar datos debe solicitar la conexión. Si existe un equipo destino con dirección IP
y el puerto adecuado, este equipo le contestará. (Vea mas adelante el método Accept) También puede

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 12


ocurrir que el equipo destino o no existe, o reciba la solicitud de conexión y no la acepte. Veremos más
adelante qué ocurre en el caso de que nadie atienda la solicitud.

La solicitud de conexión se realiza mediante el método Connect

Método Connect
Solicita una conexión con un equipo remoto.

Sintaxis NombredelcontrolWinsock.Connect hostRemoto, puertoRemoto

Donde hostRemoto es la dirección IP o DNS del equipo remoto, y puertoRemoto es el puerto por donde
esperamos nos esté escuchando ese equipo remoto.

Este método no devuelve ningún dato.

Comentarios
Debe invocar el método Connect cuando intente establecer una conexión TCP.

Para el equipo servidor (Receptor)

Para recibir, primero hace falta poner el Winsock a escuchar, y una vez que reciba una comunicación de
un equipo llamante aceptarla. Para poner a escuchar al Winsock basta con invocar el método Listen.

Método Listen
Crea un socket y lo establece a modo de escucha. (Sólo para conexiones TCP).

Sintaxis NombredelWinsock.Listen

No lleva ningún argumento ni devuelve ningún valor. Simplemente pone a la escucha al Winsock.

Ya con el Winsock a la escucha, ya está dispuesto para recibir una comunicación. Y no le importará de
quien venga, basta con que lleve su dirección IP y el puerto en el escucha el Winsock.

Cuando el Winsock recibe un intento de conexión se produce el evento ConnectionRequest. Para


aceptarla hay que usar el método Accept, pero aquí es donde se empiezan a complicar (solo un poquito)
las cosas.

Un Winsock solamente puede recibir una comunicación. Por lo tanto, solamente podrá atender a un
corresponsal. Esto no es lo que se busca en la mayor parte de los casos, sino que lo que se pretende es
estar a la escucha, y atender a todas las llamadas que entren, pudiendo atender a dos o más
comunicaciones simultáneamente.

Para lograr esto lo que hacemos es tener un Winsock permanentemente a la escucha para recibir los
sucesivos intentos de conexión de los corresponsales, y una vez que se recibe uno, se crea una
instancia del winsock, y es, con esta instancia, con la que le invocamos el método Accept para
aceptarla. De esta forma tendremos tantas instancias (copias) del winsock como comunicaciones activas,
más el winsock original que es el que se queda a la escucha de nuevos intentos de conexión. Ni que
decir tiene que, una vez terminada la conexión, debe cerrarse la instancia correspondiente a esa
conexión.

La instancia debe crearse en el procedimiento ConnectionRequest del winsock original. La forma de


crear esta instancia es mediante el procedimiento Load. Para ello, el winsock original debe tener la
propiedad Index para que de esta forma sea una matriz de controles, aunque originalmente solo exista
un elemento de esa matriz, con Index = 0. Las instancias van a tener un nombre (Propiedad Name) igual
a la del original, y un índice (Propiedad Index) que tendremos que ponerle en el momento de crear ese
LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 13
nuevo winsock. Esto implica que deberemos llevar una lista con los índices de las instancias creadas
para no repetir ninguno. No sirve aumentar una unidad el número del índice, ya que no podemos dejar
que el número del índice crezca hasta el infinito.

Evento ConnectionRequest
Se produce en el equipo local cuando el equipo remoto solicita una conexión.

Sólo para aplicaciones de servidor TCP. El evento se activa cuando llega una solicitud de conexión. A
partir de la activación de este evento, las propiedades RemoteHostIP y RemotePort almacenan la
información acerca del cliente.

Este evento pasa como parámetro un número Long con el identificador de la solicitud de conexión. Este
identificador (IdSolicitud) lo genera el servidor (el equipo que recibe) y lo necesitaremos para aceptar la
conexión mediante el método Accept.

NombredelcontrolWinsock_ConnectionRequest (IdSolicitud As Long)

El parámetro idSolicitud va a identificar a esa conexión hasta que se cierre. La identificación la hace el
winsock analizando en el datagrama entrante la dirección IP del origen, puerto origen y puerto destino,
parámetros que no pueden coincidir al mismo tiempo con los de otra comunicación. Este mecanismo va
a permitir que el mismo winsock reciba varias comunicaciones simultáneas y sepa diferenciar una de otra

Metodo Accept

Este método se utiliza para aceptar una conexión entrante cuando se está tratando un evento
ConnectionRequest.. Sólo se usa con el protocolo TCP.

Sintaxis NombredelWinsock.Accept IdSolicitud

Donde IdSolicitud es el número identificador de la solicitud de conexión que pasa el evento


ConnectionRequest como parámetro.

El método Accept debe hacerse sobre una nueva instancia del control Winsock. No es estrictamente
necesario cuando se está utilizando una conexión en la que sabemos con certeza que no vamos a recibir
más de una llamada. En el caso de que se produzca un nuevo intento de conexión mientras atiende a
una conexión aceptada, además de no poder atenderlo, la experiencia nos dice que se producen
problemas, que terminan generalmente haciendo que el programa no responda e incluso colgando el
equipo, Recomiendo encarecidamente que la conexión se establezca con una nueva instancia del
winsock. Dicho en otras palabras, que el método Accept se ejecute sobre una nueva instancia, aunque la
información de Microsoft esté un poco indefinida en este aspecto.

Veamos como se crea una nueva instancia del control. Se usa el método Load. Para ello, en el Winsock
que colocamos en el proyecto le ponemos, en su propiedad Index el valor 0. Con esto le estamos
indicando que es una matriz de controles, pero solamente existe uno, cuyo índice es el 0. Cuando
utilizamos el método Load lo que hacemos es añadir un elemento más a esa matriz de controles.
Si el control que hemos introducido en el formulario se llamaba Wsk, y le hemos puesto su propiedad
Index = 0, para añadir el segundo elemento de esa matriz, que tendrá la propiedad Index = 1,
ejecutaremos la siguiente línea de código:

Load Wsk (1)

Ahora ya tenemos una matriz con dos controles. (Indices 0 y 1) Dejaremos el winsock con índice 0 para
seguir recibiendo peticiones de comunicación y ejecutaremos el método Accept sobre el segundo
winsock (el de Index = 1)

Wsk (1).Accept IdSolicitud

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 14


A partir de este momento, todo lo que tengamos que hacer para recoger la información recibida, enviar
respuestas al corresponsal, cerrar la comunicación lo haremos con la instancia creada para esa
conexión. No se nos puede olvidar cerrar el winsock una vez terminada la conexión y descargarlo a
continuación. Para descargarlo utilizamos la instrucción Unload

Unload Wsk(1)

El winsock original lo seguiremos dedicando a recibir nuevas solicitudes de conexión, que a su vez
crearán nuevas instancias del winsock.

En principio no hay problema para que cada nueva instancia lleve un Index incrementado en 1 respecto
a la conexión anterior. Basta con declarar una variable tipo Long para introducir ese índice, y
previsiblemente nunca llegaremos a superar los límites del Long. Ahora bien, es mucho mas elegante
reutilizar los números de las instancias que se van cerrando. Para esto es necesario utilizar una variable
o una matriz, donde llevemos la cuenta de las instancias todavía abiertas del winsock original.

Cada una de las instrucciones anteriores se deberán hacer en los eventos apropiados del winsock. Así,
el crear un nuevo winsock lo haremos en el evento ConnectionRequest, y el descargarlo lo haremos en
el evento Close.
Ya tenemos la conexión establecida. Veamos ahora otras propiedades y métodos que nos permitirán
conocer la identidad del corresponsal y lo que hay que hacer para enviar y recibir información.

Una vez establecida la conexión, mediante el método Connect por parte del cliente, y el método Accept
por parte del servidor, ya podemos conocer la identidad del corresponsal mediante la propiedad
RemoteHostIP

Evento Connect
Este evento ocurre en el Winsock que ha solicitado la conexión, cuando ésta se ha completado. Ocurre
por lo tanto cuando el winsock remoto invoca el método Accept. Puede usar este evento parta conformar
que se ha realizado la conexión.

Propiedad RemoteHostIP
Devuelve una cadena de caracteres con la dirección IP del equipo remoto.

NOTA. Esta propiedad es distinta de la de RemoteHost vista mas atrás. La propiedad RemoteHost
es la que se debe introducir antes de realizar la conexión, y puede ser, bien una dirección IP de
cuatro números, o una DNS. RemoteHostIP devuelve el valor de la dirección IP de cuatro
números, una vez que ya se ha establecido la comunicación. Puede consultarse esta propiedad
para conocer el número IP real de un sitio, conociendo solamente su DNS.

En las aplicaciones de cliente, después de establecer la conexión con el método Connect, esta
propiedad contiene la cadena IP del equipo remoto.

En las aplicaciones de servidor, después de la llegada de una solicitud de llamada (evento


ConnectionRequest), esta propiedad contiene la cadena IP del equipo remoto que inició la conexión.

Cuando utiliza el protocolo UDP, después de producirse el evento DataArrival, esta propiedad contiene
la dirección IP del equipo que ha enviado los datos UDP.

Propiedad State
Permite conocer el estado del winsock y de la conexión que está realizando. Es sólo de lectura y no está
disponible en tiempo de diseño. Devuelve un integer

Siantaxis Variabletipointeger = NombredelWinsock.State


LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 15
Nos puede devolver uno de los siguientes valores que corresponden a las siguientes constantes

Valor Constante Estado

0 sckClosed Cerrado
1 sckOpen Abierto
2 sckListening Escuchando
3 sckConnectionPending Conexión pendiente
4 sckResolvingHost Resolviendo Host
5 sckHostResolved Host resuelto
6 sckConnecting Conectando
7 sckConnected Conectado
8 sckClosing Cerrando la conexión
9 sckError Ha detectado un error

Propiedad SocketHandle
Esta propiedad se usa para utilizarla con las Apis de Windows. Devuelve el manipulador del Winsock. Es
de sólo lectura y no está disponible en tiempo de diseño.

Sintaxis VariableTipoLong = NombredelWinsock(I).SocketHandle

Donde I es el índice del Winsock. Como se decía más atrás, esta propiedad solamente se emplea
usando APIS

Propiedades, Métodos y Eventos del control Winsock usados en la


comunicación
Hemos visto varias propiedades, métodos y eventos del control Winsock. Hasta ahora hemos visto:

Propiedades: LocalIP, LocalHostName, Protocol, RemoteHost, RemotePort, LocalPort, State


Métodos: Connect, Listen y Accept.
Eventos ConnectionRequest, Connect

Mediante estas propiedades y métodos establecemos la conexión. Nos falta ahora por ver aquellos
métodos usados durante la transmisión o recepción de datos.

Método SendData
Envía datos a un equipo remoto. Se emplea tanto en UDP como en TCP. No devuelve ningún valor.

Sintaxis NombredelWinsock(I).SendData datos

Donde NombredelWinsock es el nombre del winsock que debe enviar los datos, I es el índice de ese
control (en el caso de que el winsock sea una instancia de un winsock original, como se explicó más
atrás) y Datos son los datos a enviar, por ejemplo el nombre de una variable que los contiene o la
propiedad text de un textbox donde se han escrito los datos a enviar.

Si los datos a enviar son binarios, deberán enviarse como una matriz de bytes.
Cuando pasa una cadena UNICODE, se convierte a cadena ANSI antes de enviarla a la red.

Método GetData
Recupera los datos existentes en el búffer de recepción del winsock, lo almacena en una variable y borra
el contenido del búffer.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 16


Sintaxis NombredelWinsock(I).GetData datos, [tipo,] [longMáx]

Donde datos es el nombre de la variable donde se almacenarán los datos recogidos


tipo (Opcional) es el tipo de datos a recuperar (Vea tabla)
longMáx (Opcional) Tamaño en bytes a recuperar. Si se omite este parámetro, se
recuperan todos los datos existentes en el búffer de recepción. Si se
especifica un número inferior a los bytes existentes en el búffer, el resto
de los datos se perderán.

Los tipos de datos que se pueden usar en el parámetro tipo son:

Byte VbByte Entero vbInteger Long vbLong


Single vbSingle Simple vbDouble Double vbDouble
Moneda vbCurrency Fecha vbDate Booleano vbBoolean
Cadena vbString Matriz de bytes vbArray + vbByte

El método GetData se suele usar con el evento DataArrival, que incluye el argumento bytesTotales. Si
especifica una longMáx menor que el argumento bytesTotales, obtendrá el mensaje de advertencia
10040, que indica que se perderán los bytes restantes.

Evento DataArrival
Se produce cuando llegan nuevos datos. Pasa como parámetro un Long con el número de bytes
recibidos. (NombredelWinsock_DataArrival (bytesTotales As Long)

Este evento no se producirá si no recupera todos los datos con una llamada GetData. Sólo se activa
cuando hay datos nuevos. Utilice la propiedad BytesReceived para comprobar la cantidad de datos
disponibles en cualquier momento.

Propiedad BytesReceived
Devuelve un Long la cantidad de datos recibidos (que están actualmente en el búffer de recepción).
Lógicamente es sólo de lectura y no está disponible en tiempo de diseño.

Sintaxis NombredeWinsock.BytesReceived

Método PeekData
Este método es similar a GetData, pero no elimina los datos extraídos del búffer de recepción. Exixte
otra diferencia, PeekData solamente funciona en las conexiones TCP.
La sintaxis es similar a la de GetData.

Sintaxis NombredelWinsock.PeekData datos, [tipo,] [longMáx]

Los parámetros de este método son los mismos que para GetData.

Evento SendProgress
Se produce mientras se están enviando datos. Pasa como parámetros los bytes enviados desde la
última vez que se activó el evento (bytesEnv) y los bytes que esperan a ser enviados en el búffer de
transmisión (bytesRest)

(NombredelWinsock_SendProgress (bytesEnv As Long, bytesRest As Long)

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 17


Evento SendComplete
Se produce cuando termina una operación de envío. No pasa argumentos.

NombredelWinsock_SendComplete()

Evento Error
Se produce siempre que ocurre un error en los procesos de segundo plano (por ejemplo, un fallo al
conectar o un fallo al enviar o recibir en segundo plano). Pasa como parámetros el código de error, la
descripción del error, el scode del error, el origen del error, y un booleano para cancelar o aceptar el que
presente un cuadro de dialogo con el aviso de error. (Los parámetros de fichero de ayuda y contexto de
ayuda, personalmente no los he visto en ninguno de los ejemplos preparados.

NombredelWinsock_Error(número As Integer, descripción As String, scode As Long, origen As String,


archivoAyuda as String, contextoAyuda As Long, cancelarVista As Boolean)

El código de error puede tomar estos valores:

Constante Valor Descripción

SckOutOfMemory 7 Sin memoria


SckInvalidPropertyValue 380 El valor de la propiedad no es válido
SckGetNotSupported 394 No se puede leer la propiedad
SckSetNotSupported 383 La propiedad es de sólo lectura.
SckBadState 40006 Protocolo o estado de conexión incorrecto para la
solicitud o la transacción requerida.
SckInvalidArg 40014 El argumento que se pasó a una función no estaba en el
formato correcto o en el intervalo especificado.
SckSuccess 40017 Correcto
SckUnsupported 40018 Tipo Variant no aceptado.
SckInvalidOp 40020 La operación no es válida en el estado actual.
SckOutOfRange 40021 El argumento está fuera del intervalo.
SckWrongProtocol 40026 Protocolo erróneo para la solicitud o la transacción
requerida.
SckOpCanceled 10004 Se canceló la operación.
SckInvalidArgument 10014 La dirección solicitada es una dirección de multidifusión,
pero el indicador no está activado.
SckWouldBlock 10035 El socket es no bloqueante y la operación especificada
se bloqueará.
SckInProgress 10036 Se está efectuando una operación de Winsock
bloqueante.
SckAlreadyComplete 10037 Se completó la operación. No se están efectuando
operaciones bloqueantes.
SckNotSocket 10038 El descriptor no es un socket.
SckMsgTooBig 10040 El datagrama es demasiado grande para el búfer y se
truncará.
SckPortNotSupported 10043 El puerto especificado no es compatible.
SckAddressInUse 10048 Dirección en uso.
SckAddressNotAvailable 10049 La dirección no está disponible en la máquina local.
SckNetworkSubsystemFailed 10050 Error en el subsistema de red.
SckNetworkUnreachable 10051 El host no puede encontrar la red en este momento.
SckNetReset 10052 Expiró el tiempo de espera de la conexión antes de
establecer SO_KEEPALIVE.
SckConnectAborted 10053 La conexión se ha cancelado al sobrepasar el tiempo de
espera o por otro error.
SckConnectionReset 10054 La conexión se ha restablecido desde el lado remoto.
LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 18
SckNoBufferSpace 10055 No hay espacio disponible en el búfer.
SckAlreadyConnected 10056 El socket ya está conectado.
SckNotConnected 10057 El socket no está conectado.
SckSocketShutdown 10058 El socket se ha desactivado.
SckTimedout 10060 Se ha sobrepasado el tiempo de conexión.
SckConnectionRefused 10061 Se ha forzado el rechazo de la conexión.
SckNotInitialized 10093 Es necesario llamar primero a WinsockInit.
SckHostNotFound 11001 Respuesta autorizada: host no encontrado.
SckHostNotFoundTryAgain 11002 Respuesta no autorizada: host no encontrado.
SckNonRecoverableError 11003 Errores no recuperables.
SckNoData 11004 Nombre válido; no hay registro de datos del tipo
solicitado.

Evento Close
Se produce cuando el equipo remoto cierra la conexión. Las aplicaciones deben usar el método Close
para cerrar correctamente una conexión TCP.

El Método Bind
El método Bind sirve para reservar un puerto local cuando estamos trabajando en una comunicación
UDP. Esto puede ser muy útil para evitar que haya otra aplicación escuchando en ese mismo puerto.
Hay que darse cuenta que en UDP puede haber muchas aplicaciones escuchando el mismo puerto ya
que al no establecerse una comunicación, la información que llega pueden tomarla mas de una
aplicación. (Es idéntico al caso en el que una persona hable y muchas escuchan) Si reserva un
determinado puerto a un Winsock, a ese puerto no se le puede conectar otro Winsock a escuchar a partir
de ese momento. Hay que invocar el método Bind antes de invocar el método Listen.

También puede usar el método Bind en una comunicación TCP. Se emplea cuando hay más de un
adaptador de red en el equipo (Un equipo con dos placas de red, y cada una de ellas con un número IP).
Si en ese equipo hay un Winsock, ¿Qué número IP tiene?. Podría tomar uno de los dos indistintamente.
Mediante Bind podemos asignar uno de esos números IP a un Winsock.

Método Bind
Especifica el puerto local y la dirección IP local a usar en las conexiones TCP.

Sintaxis NombreDelWinsock.Bind puertoLocal, IPLocal

Donde:
PuertoLocal: Puerto utilizado para realizar una conexión.
IPLOcal: Dirección IP local sobre la que se va a establecer la conexión.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 19


LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 20
Programa servidor que recibe varias comunicaciones simultaneas.
Vamos a realizar un ejemplo consistente en un programa servidor cuya misión sea recibir ficheros desde
varios clientes, guardarlos en una base de datos donde apuntará también el origen del fichero y la fecha
de recepción, y que envíe al cliente la conformidad de recepción de ese fichero. En sentido contrario,
una vez identificado al cliente, podrá enviarle los ficheros pendientes que ese cliente tenga depositado
en el servidor. Esto es lo más parecido a un servidor de correo, pero no lo es. Le falta cumplir las
especificaciones. Pero bien estará como ejercicio práctico del winsock.

El programa podrá recibir simultáneamente desde varios corresponsales. Para enviar, podrá hacerlo de
uno en uno, es decir, en un determinado momento solamente podrá estar enviando a otro corresponsal,
aunque podrá enviar, en momentos sucesivos, a cuantos corresponsales estén activos. El envío de
información se podrá hacer simultáneamente a la recepción.

Para lograr esto, es necesario disponer de dos winsock en la aplicación. Uno, que estará recibiendo en
un puerto y atendiendo a todas las llamadas entrantes, (Wsk1) y otro, que se usará solamente para
enviar información a través de las llamadas salientes (Wsk2). Cada vez que se reciba una llamada
entrante, se creará una instancia de Wsk1, que será en realidad la que acepte la llamada usando su
método Connect.

Debemos elegir un puerto para la escucha. A la hora de decidir el número del puerto debemos pensar
que no se pueden usar los 2024 primeros puertos, que el puerto elegido no esté siendo usado de forma
internacional por otro servicio (que no esté registrado a ninguna aplicación a nivel mundial) y que no esté
usado en nuestros PCs para otro servicio. En nuestro ejemplo, lo que vamos a hacer es leerlo de un
fichero de configuración, y colocarlo en un TextBox llamado TbPuertoLocal. De esta forma, al winsock lo
programaremos con el puerto indicado en ese TextBox, y a ese TextBox le llevaremos el dato con la
lectura del fichero de configuración, operación que se realiza durante la carga del formulario. De esta
forma podremos poner en el fichero de configuración el puerto deseado, sin necesidad de variar el
programa.

Ya vamos teniendo una idea de la interfase gráfica necesaria para empezar. Dado el fin didáctico de este
ejemplo, se van a mostrar todos los parámetros que entran a formar parte de la comunicación.

Fig. 2 Aspecto de la parte de la Interfase gráfica de comunicaciones

En esta figura se pueden ver dos partes bien diferenciadas, una en azul, (Máquina Local, Instancias
activas, Textos/Ficheros recibidos) con la parte de la aplicación correspondiente a la recepción, La parte
roja (Equipo remoto llamado) corresponde a la parte de transmisión.

En la parte azul tenemos el winsock de recepción (Wsk1) y sus instancias. El contenido de cada cuadro
de texto y el origen del dato presentado es el siguiente:

Maquina local. Pone el nombre de la máquina local. Sistema


Ip Local. Pone el número IP de la máquina local. Sistema
Puerto Local. Pone el puerto de recepción asignado a esta aplicación. Fichero de configuración
Protocolo. UDP o TCP. Puede cambiarse haciendo doble clic en este texto
LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 21
RequestID. Parámetro IdSolicitud Proc. ConnectionRequest
Estado. Valor de la propiedad State del Wsk1 Se analiza cada 100 ms. Con Timer1
Ultima máquina remota conectada. Puerto e IP de la última máquina conectada. Se toman de las
propiedades RemotePort y RemoteHostIP de Wsk1, en el
procedimiento ConnectionRequest.
Instancias activas. Se introduce el número de la instancia, requestID, IP remota y puerto remoto de
la conexión que ha forzado la creación de una nueva instancia de Wsk1. Cada
vez que se cierra una instancia, se elimina de esta lista. El número de la ultima
instancia eliminada se presenta el la caja lateral a esta lista.
Texto recibido Muestra el texto enviado desde el remoto. Se limpia con cada recepción,
y también se puede limpiar con el botón Limpia Texto Rec. Los textos recibidos
se acumulan en un fichero (cuyo nombre y path se determinan en el fichero de
configuración) con indicación de la hora de recepción y equipo remoto que lo
envía.
Fichero recibido Presenta el nombre y Path del ultimo fichero recibido. El nombre del
fichero es una composición del número de instancia del winsock que lo recibe
(tres cifras) y de la fecha y hora del sistema (iiiyyyymmddhhmmss.Dat). El path
se introduce en el fichero de configuración. Paralelamente se crea otro fichero
con nombre idéntico y extensión .Env con los datos relativos al equipo remoto
que lo ha enviado, hora de recepción y localizador del acuse de recibo. Para
limpiar esta caja de texto, se hace clic en el botón Limpia Fichero Rec.

En la parte roja tenemos todo lo relativo a la transmisión, y las cajas de texto pare enviar mensajes de
texto y ficheros.

Dirección IP En esta caja se debe introducir el número IP del equipo al que se llama.
Puerto Se introducirá el puerto en el que escucha el equipo remoto. El puerto por
defecto se introduce mediante el fichero de configuración.
Protocolo Protocolo utilizado. (UDP o TCP) se cambia haciendo doble clic en esa caja.
Debe usarse el mismo protocolo que el equipo remoto.
Conectar Haciendo clic en este botón se inicia el proceso de conexión con el equipo
remoto.
Cerrar Haciendo clic en este botón se cierra lña conexión existente.
Estado Dos etiquetas con el estado del winsock de transmisión. Una, con el valor de la
propiedad State, y otra, con la condición de conectado / no conectado. Se hace
cada 100 ms. Con el Timer1
Texto a enviar. Texto que se quiere enviar al equipo remoto. Para comenzar a enviarlo hay que
hacer clic sobre el botón à
Fichero a enviar Nombre y path del fichero que se quiere enviar. Para buscarlo dentro del disco,
hay que hacer clic sobre el botón ··· Para proceder a su envío, se hace clic sobre
el botón à Si existe Texto a enviar y Fichero a enviar, al hacer clic sobre el
botón à se enviarán ambos

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 22


Fig. 3 La aplicación puede conectarse consigo misma

Es muy sencillo comprobar el funcionamiento correcto de la aplicación conectándose consigo misma. En


la Fig. 3 podemos ver el aspecto que toma la interfase gráfica de comunicaciones una vez conectada.
Observe la coincidencia de las direcciones IP y los puertos utilizados tanto en la parte roja (equipo
remoto) como en la azul (equipo local). De esta forma se pueden probar las funciones del programa sin
necesidad de un interlocutor remoto.

Fig. 4 Este es el aspecto final del la aplicación. Vea en el disco de ejemplos el código completo.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 23


LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 24
Visual Basic e Internet (2)
Control Microsoft Internet Transfer
El control Internet Transfer

Microsoft Internet Transfer (Control)


El control Internet Transfer ofrece una implementación de dos de los protocolos más ampliamente
utilizados en Internet: Protocolo de transferencia de hipertexto (HTTP) y Protocolo de transferencia de
archivos (FTP). Mediante el protocolo HTTP, puede conectarse con servidores de World Wide Web para
obtener documentos HTML. Con el protocolo FTP puede iniciar sesiones en servidores FTP para
descargar y cargar archivos. Las propiedades UserName y Password permiten iniciar sesiones en
servidores privados que requieran autentificación. Por otra parte, puede conectar con servidores FTP
públicos y descargar archivos. Los comandos más comunes de FTP, como CD y GET, son compatibles
por medio del método Execute.

Usar el control Internet Transfer


El control Internet Transfer implementa dos protocolos de Internet de gran difusión: Protocolo de
transferencia de hipertexto (HTTP) y Protocolo de transferencia de archivos (FTP). Con el control
Internet Transfer se puede conectar con cualquier sitio que utilice alguno de estos protocolos y obtener
archivos mediante los métodos OpenURL o Execute.
Funcionamiento básico
La funcionalidad del control Internet Transfer depende del protocolo que desee usar. Como los dos
protocolos contemplados funcionan de forma distinta, las operaciones que puede realizar dependen del
protocolo elegido. Por ejemplo, el método GetHeader sólo funciona con HTTP (documentos HTML).

Para poder empezar a usar el control Internet Transfer (Inet) debe estar conectado a una red que
disponga de algún servidor Http y Ftp. No tienen porqué ser directamente a Internet. Puede estar
conectado a una Intranet donde existan. Pero en este control no podemos hacer lo que hacíamos con el
Winsock, conectarnos con nosotros mismos. Este control está para acceder a sitios con un servidor http
o ftp.

Vamos a ir introduciendo las propiedades del Inet al mismo tiempo que lo conectamos a Internet. Y lo
primero es saber si se va a conectar directamente o a través de Proxi. Supongo que el alumno sabrá que
es un Proxi, por lo que solamente vamos a explicar la propiedad que tiene el Inet para acceder desde
una Red de Area Local (RAL) con o sin Proxi y así zanjamos esa primera dificultad que puede tener para
conectarse a la Red:

Propiedad AccessType
Establece si el Inet se comunica directamente a Internet o a través de Proxi.

Sintaxis NombreDelInet.AccessType = tipo

Tipo acepta los valores:


Constante Valor Descripción
IcUseDefault 0 Predeterminada. Asume lo que su PC tenga programado en el navegador de
Internet que tenga por defecto.
IcDirect 1 Directo a Internet. Se usa este valor cuando el Inet se utiliza para comunicar con
servidores http o ftp que están en la misma RAL. De esta forma no le afecta
cómo tenga programado el acceso de su navegador.
IcNamedProxy 2 Le está indicando al Inet que la salida hacia Internet (O la red donde se
encuentra el servidor http o ftp) debe hacerla a través del equipo indicado en la
propiedad Proxi.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 25


Propiedad Proxy
Devuelve o establece el nombre del servidor proxy utilizado para comunicar con Internet. Esta propiedad
sólo se utiliza cuando el valor de AccessType es icNamedProxy (3).
Sintaxis NombredelInet.Proxy = proxy

Donde Proxi es el nombre del servidor que se desea usar.

Puede usar un proxi distinto para acceder con protocolo Http o Ftp, y determinar porque puerto accede a
cada uno de estos servicios. El proxi suele estar programado para que en la parte interior de la red se
acceda a los servicios externos a través de un puerto distinto al real. Es típico en la programación de los
proxis acceder desde la red interior al sevicio http a través del puerto 8080, en vez del puerto 80.

Puede hacer esto estableciendo la propiedad Proxi de la siguiente forma:

NombredelInet.Proxy = "ftp=CorpFTP:123 HTTP=CorpHTTP:131"

Esta forma de establecer la propiedad hará que para ftp use el servidor Proxi CorpFTP, por el puerto
123, y que para http use el servidor CorpHTTP por el puerto 131.

Supongamos que ya estamos conectados a Internet. ¿Que como lo sabemos? Utilizaremos un método
del Inet: OpenURL para establecer una comunicación con un servidor http conocido. Si se completa la
conexión es que ya estamos conectados.

Método OpenURL
Abre y devuelve el documento ubicado en la dirección URL especificada. El documento se devuelve con
el tipo Variant. Cuando termina la ejecución del método, las propiedades URL (y las partes de la
dirección URL como el protocolo) se actualizan para reflejar la URL actual.

Sintaxis Variable = NombredelInet.OpenUrl url [,tipoDatos]

Donde

Variable Variable tipo string donde se guardarán los datos obtenidos (Texto) o una variable
Variant donde se guardarán los datos obtenidos como matriz de bytes
url Dirección URL que se desea abrir.
TipoDatos Entero que especifica el tipo de datos. Acepta los valores 0 (Predeteminado) para que
obtenga los datos como cadena de caracteres, o 1, para que los obtenga como matriz de
bytes. Si la URL es una página Web debe poner 0 en este valor.

Ejemplo: En un botón de comando ponemos este código

Dim TextoPagina As String


TextoPagina = Inet1.OpenURL(TbURL.Text, 0)
TbTextoPagina = TextoPagina

TbTextoPagina es un TextBox donde vamos a presentar el valor devuelto. Para el valor www.mae.es
devolvió esto:

<html>
<head>
<title>Ministerio de Asuntos Exteriores. España</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<frameset cols="1,*" frameborder="NO" border="0" framespacing="0">
<frame name="nulo" scrolling="NO" noresize >
<frame name="inicial" scrolling="auto" src="/mae/index.jsp" >
</frameset>
LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 26
<noframes>
<body bgcolor="#FFFFFF">
</body>
</noframes>
</html>

El método OpenURL trabaja de forma síncrona, es decir, espera a recibir el contenido del fichero para
ejecutar la línea siguiente del código. Cuando se ejecuta la línea

TextoPagina = Inet1.OpenURL(TbURL.Text, 0)

La conexión tarda un tiempo en ejecutarse, y el servidor tarda cierto tiempo en buscar el fichero
correspondiente a la petición y enviarlo. Y mientras tanto, el código está parado en esa línea, y es
solamente cuando se termina de recibir todo el contenido o cuando el Inet genera un error de
comunicación cuando se ejecuta la siguiente línea.

TbTextoPagina = TextoPagina

De no ser síncrona, y dado que la conexión tarda algo (por muy poco que fuese) al ejecutar esta
segunda línea la variable TestoPagina estaría vacía, por lo que TbTextoPagina siempre aparecería en
blanco.

El control Inet es un poco delicado. Como sabrá, la propiedad por defecto de un TextBox es la propiedad
Text. Sería de suponer que la línea:
TextoPagina = Inet1.OpenURL(TbURL, 0) =
Es igual a esta otra:
TextoPagina = Inet1.OpenURL(TbURL.Text, 0)
Pues el Inet, con la primera línea, da error. Debe tomar TbURL como el objeto tipo control. Sale este
error:
Error 35752 en tiempo de ejecución:
La dirección URL está mal generada

Es posible que desee saber si ha conectado con la URL solicitada. Eso puede saberlo analizando la el
estado de la conexión. Pero no existe ninguna propiedad que se lo indique. Tiene que ir a buscarlo al
único procedimiento que tienen el control Internet Transfer: el evento StateChanged

Evento StateChanged
Se produce siempre que hay un cambio de estado en la conexión. Aporta el parámetro estado que es un
integer.

Inet1_StateChanged(ByVal estado As Integer)

estado puede tener uno de estos valores:

Constante Valor Descripción


icNone 0 No hay estado del que informar.
icHostResolvingHost 1 El control está buscando la dirección IP del host especificado.
icHostResolved 2 El control encontró la dirección IP del host especificado.
icConnecting 3 El control está conectando con el equipo host.
icConnected 4 El control conectó correctamente con el equipo host.
icRequesting 5 El control está enviando una solicitud al equipo host.
icRequestSent 6 El control envió correctamente la solicitud.
icReceivingResponse 7 El control está recibiendo una respuesta del equipo host.
icResponseReceived 8 El control recibió correctamente una respuesta del equipo host.
icDisconnecting 9 El control se está desconectando del equipo host.
icDisconnected 10 El control se desconectó correctamente del equipo host.
LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 27
icError 11 Se produjo un error en la comunicación con el equipo host.
icResponseCompleted 12 La solicitud se completó y se recibieron todos los datos.
Puede analizar el estado del Inet introduciendo este código en este procedimiento:

Private Sub Inet1_StateChanged(ByVal State As Integer)


Select Case State
Case 0
LState = "0 - Sin actividad" ‘Lstate es un Label donde presentamos el estado de la conexión
Case 1
LState = "1 - Buscando Host"
Case 2
LState = "2 - Host encontrado"
Case 3
LState = "3 - Conectando"
Case 4
LState = "4 - Conectado"
Case 5
LState = "5 - Enviando solicitud"
Case 6
LState = "6 - Solicitud enviada"
Case 7
LState = "7 - Recibiendo respuesta del Host"
Case 8
LState = "8 - Respuesta recibida"
Case 9
LState = "9 - Desconectando"
Case 10
LState = "10 - Desconectado"
Case 11
LState = "11 - Error de conexión"
Case 12
LState = "12 - Operación completada"
End Select
End Sub

Este procedimiento no se comporta de igual forma cuando se conecta con una página Http que cuando
lo hace con un servidor Ftp. Nos centraremos primero en conexiones con servidores Http, y veremos
más adelante como se comporta con servidores Ftp.

El procedimiento StateChanged se emplea también para ejecutar el método GetChunk para recuperar
datos. Vea este método más adelante.

Otro método muy importante para ver páginas en la Web el método GetHeader, que permite recuperar el
encabezado o paerte de él de una página. Este método puede ser muy útil cuando tenemos que bajar
una página, pero previamente queremos comprobar que ya ha sido actualizada.

Método GetHeader
Recupera el encabezado de un archivo HTTP. Devuelve un string.

Sintaxis Inet1.GetHeader (nombreEnc)

Donde:
Inet1 Nombre del control Inet
NombreEnc Opcional. Cadena que especifica el encabezado que desea recuperar. Si no indica
ninguno los recuperará todos. Los valores permitidos para nombreEnc son (Pueden
existir otros, dependiendo el servidor)
Date Devuelve la hora y la fecha de la transmisión del documento. El formato de los datos
obtenidos es Fri, 01 Nov 2002 12:10:51 GMT. Este dato puede servir para sincronizar
los relojes de muchos ordenadores, sin necesidad de recurrir a complejos y costosos
sistemas basados en GPS, ya que todos los ordenadores pueden ponerse en hora
tomándola de una página Web de referencia.
MIME-version Devuelve la versión del protocolo MIME. Normalmente los servidores no contestan a este
parámetro.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 28


Server Devuelve el tipo del servidor. (Esta respuesta tienen mucho peligro, ya que los hackers
es lo primero que miran para realzar un ataque)
Content-length Devuelve la longitud en bytes de los datos que enviará cuando ejecutemos el método
OpenURL.
Content-type Devuelve el tipo de contenido MIME de los datos.
Last-modified Devuelve la fecha y la hora de la última modificación del documento. El formato de los
datos devueltos es Wed, 20 Feb 2002 15:26:44 GMT. Observe que la hora siempre se
suministra GMT (Grenwich Meridian Time, una hora menos que en el horario de invierno
de España peninsular)

La página www.mae.es devuelve este texto:

HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Content-Location: http://www.mae.es/index.htm
Date: Fri, 01 Nov 2002 12:10:51 GMT
Content-Type: text/html
Accept-Ranges: bytes
Last-Modified: Wed, 20 Feb 2002 15:26:44 GMT
ETag: "0129d023bac11:991"
Content-Length: 420
Age: 0

Método Cancel
Cancela la solicitud actual y cierra las conexiones establecidas actualmente. No devuelve ningún valor.

Sintaxis Inet1.Cancel

Es posible que este método genere un error, ya que en algunas ocasiones cierra la conexión sin poder
cancelar ya el proceso que está en curso. Tenga cuidado al usarlo.

Vamos a ver ahora el método más útil de este control. Con él podemos hacer todas las funciones de
envío y recogida de ficheros.

Método Execute
Ejecuta una solicitud a un servidor remoto. Sólo puede enviar solicitudes válidas para el protocolo que
esté utilizando. Lógicamente este método funcionará de forma distinta y necesitará parámetros distintos
dependiendo del protocolo que estemos usando. Para el protocolo Http la sintaxis es la siguiente:

Sintaxis (Http) Inet1.Execute url, operación, datos, encabezadosSolicitud

Inet1 Nombre del control Inet


URL (Opcional) Cadena que especifica la dirección URL con la que se debe conectar el
control. Si no se especifica ninguna, se usará la dirección contenida en la propiedad URL
operación Opcional. Cadena que especifica el tipo de operación que desea ejecutar. Mas abajo
encontrará una lista con las operaciones admitidas.
datos Opcional. Cadena que especifica los datos para las operaciones (vea más abajo).
EncabezadosSolicitud
Opcional. Cadena que especifica los encabezados adicionales para enviarlos al servidor
remoto. El formato de los mismos es el siguiente:

nombre encabezado: valor encabezado vbCrLf

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 29


Comandos de HTTP admitidos

Los valores válidos para operación son:

Operación Descripción
GET Recupera datos de la dirección URL especificada en la propiedad URL.
HEAD Envía los encabezados de la solicitud.
Envía datos al servidor. Los datos están en el argumento datos. Éste es
POST un método alternativo a GET para el que se especifican las instrucciones
adicionales en el argumento datos.
Operación de colocación. El nombre de la página que se va a reemplazar
PUT
está ubicado en el argumento datos.

Es difícil probar estos comandos. Normalmente las páginas comerciales no ofrecen los servicios que a
nosotros nos gustaría probar. Vea en los ejemplos entregados una aplicación del comando PUT (Que no
podrá ensayar en su casa excepto que tenga acceso a un servidor con Password)

Vamos a mostrarle un ejemplo del comando GET. Pero previamente tenemos que hablar de un método
que antes habíamos citado de pasada:

Método GetChunk
Obtiene datos cuando se produce el evento StateChanged al llegar al estado de respuesta completa
(icResponseCompleted = 12) Este método se invoca después de ejecutar el método Execute como
una operación GET.

Sintaxis Inet1.GetChunk( tamaño [,tipoDatos] )

Cuando se ejecuta la operación GET los caracteres recibidos desde el servidor se almacenan enun
buffer. El método GetChunk recupera los caracteres del buffer en bloques de un tamaño que se debe
fijar en el parámetro tamaño. Si la información recibida es mayor que tamaño será necesario hacer un
bucle hasta completar la recuperación de todos los caracteres. El parámetro tipoDatos puede ser
icString (0) para recuperar una cadena de caracteres, ó icByteArray (1) para recuperar una matriz de
bytes.

Este es el código que se ha metido en el SelectCase del evento StateChanged, para el caso que State
sea 12
Dim vtData As Variant ' Variable de datos.
Dim strData As String, bDone As Boolean, F As Integer
' Obtiene el primer bloque.
vtData = Inet1.GetChunk(1024, icString)
DoEvents
Do While Not bDone
strData = strData & vtData
DoEvents
' Obtiene el bloque siguiente. Está sacando bloques de 1024 caracteres
'hasta que no queda ninguno. En ese caso, GetChunk devuelve la cadena vacía
vtData = Inet1.GetChunk(1024, icString)
If Len(vtData) = 0 Then
bDone = True
End If
Loop
TbTextoExecute.Text = strData
If TbNombreFichero <> "" Then
F = FreeFile
Open "C:\_aaa\" & TbNombreFichero For Output As #F
Print #F, strData
Close #F
End If

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 30


Método Execute (Continuación)
Veamos ahora que puede hacer el método Execute para el protocolo Ftp. Aunque la sintaxis es igual, en
Ftp no se usan los parámetros datos y encabezadosSoliicitud y queda como sigue:

Sintaxis (Ftp) Inet1.Execute url, Instruccion

url es el nombre del servidor. Este parámetro puede darle algún problema si no conoce exactamente el
nombre del servidor, (Si lleva o no lleva el encabezado FTP:// , si es una DNS o un número IP, ..) Estas
direcciones son un ejemplo de ello:

“FTP://ftp.microsoft.com” “Ftp://10.3.22.119”

Instrucción es una cadena que incluye el comando (GET, PUT, ..) y el nombre o nombres de los archivos
necesarios. Ejemplos:

Inet1.Execute "FTP://ftp.microsoft.com", "GET Disclaimer.txt C:\Temp\Disclaimer.txt"


Inet1.Execute "FTP://ftp.microsoft.com", "PWD"
Inet1.Execute “Ftp://10.3.22.119”, “PUT C:\Prensa\PrensaDia.Tiff /Documentos/PrensaHoy.Tiff”

Nota No se admiten nombres de archivos que incluyan espacios incrustados.

Los comandos válidos para FTP son los siguientes:

Operación Descripción
CD archivo1 Cambiar directorio. Cambia al directorio especificado en archivo1.
CDUP Cambiar al directorio superior. Equivale a "CD.."
CLOSE Cierra la conexión FTP actual.
DELETE archivo1 Elimina el archivo especificado en archivo1.
Directorio. Busca en el directorio especificado en archivo1. Se admiten
comodines, pero el host remoto determina la sintaxis. Si no especifica
DIR archivo1
archivo1, obtendrá una lista completa del directorio de trabajo actual.
Puede usar el método GetChunk para obtener los datos del directorio.
Recupera el archivo remoto especificado en archivo1 y crea el nuevo archivo
GET archivo1 archivo2
local especificado en archivo2.
Lista. Busca en el directorio especificado en archivo1. Se admiten comodines,
LS archivo1 pero el host remoto determina la sintaxis. Puede usar el método GetChunk
para obtener los datos de los archivos del directorio.
Crear directorio. Crea el directorio especificado en archivo1. El éxito de la
MKDIR archivo1
operación depende de los privilegios del usuario en el host remoto.
Copia el archivo local especificado en archivo1 en el archivo del host remoto
PUT archivo1 archivo2
especificado en archivo2.
Mostrar directorio de trabajo. Devuelve el nombre del directorio actual. Puede
PWD
usar el método GetChunk para obtener los datos.
QUIT Termina la sesión del usuario actual.
RECV archivo1 Recupera el archivo remoto especificado en archivo1 y crea un nuevo archivo
archivo2 local especificado en archivo2. Equivale a GET.
Cambia el nombre del archivo indicado en archivo1 por el nombre
RENAME archivo1
especificado en archivo2. El éxito de la operación depende de los privilegios
archivo2
del usuario en el host remoto.
Eliminar directorio. Elimina el directorio remoto especificado en archivo1. El
RMDIR archivo1
éxito de la operación depende de los privilegios del usuario en el host remoto.
SEND archivo1 Copia el archivo local especificado en archivo1 en el archivo del host remoto
archivo2 especificado en archivo2. Equivale a PUT.
SIZE archivo1 Devuelve el tamaño del directorio especificado en archivo1.
LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 31
Siguiendo con el servidor Ftp de Microsoft podemos ensayar algunos de estos comandos:

Inet1.Execute "FTP://ftp.microsoft.com", "DIR"

Nos devuelve el directorio. Como no hemos realizado ninguna operación sobre ese directorio, nos
devolverá el directorio del raíz.

bussys/
deskapps/
developr/
KBHelp/
MISC/
MISC1/
peropsys/
Products/
ResKit/
Services/
Softlib/

No contiene ficheros sino más directorios. Uno de ellos es el directorio MISC. Podemos cambiarnos a él
con la instrucción:

Inet1.Execute "FTP://ftp.microsoft.com", "CD MISC"

Y para comprobarlo vamos a pedir otra vez el directorio. Ahora ya vemos que ya contienen ficheros, y
más directorios.
beckyk/
CBCP.TXT
csformat/
DAILYKB/
DISCLAIM.TXT
FDC/
friKB/
FULLKB/
Homenet/
INDEX.TXT
Jeffreyf/
KB/
KBSPV/
Markesh/
monKB/
NBFCP.TXT
NBFCP2.TXT
NBFCP3.TXT
NBFCP4.TXT
NBFCP5.TXT
Peach/
PRODUCT.TBL
ReadMe1.txt
satKB/
Store/
STORE1/
sunKB/
test/
thuKB/
TREE.COM
tueKB/
wedKB/

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 32


Para realizar este tipo de operaciones debe asegurarse que la operación se ha terminado antes de iniciar
una nueva operación. Esto puede verlo con el valor de State del procedimiento StateChanged. Ha de
esperar a que tenga el valor icResponseCompleted ( = 12). Es en ese momento cuando debe invocar
el método GetChunk para sacar los datos del búffer. Es el mismo código del Select Case que ha visto
antes, que le repito aquí por comodidad:

Case 12
LState = "12 - Operación completada"

Dim vtData As Variant ' Variable de datos.


Dim strData As String, bDone As Boolean, F As Integer
' Obtiene el primer bloque.
vtData = Inet1.GetChunk(1024, icString)
DoEvents
Do While Not bDone
strData = strData & vtData
DoEvents
' Obtiene el bloque siguiente. Está sacando bloques de 1024 caracteres
'hasta que no queda ninguno. En ese caso, GetChunk devuelve la cadena vacía
vtData = Inet1.GetChunk(1024, icString)
If Len(vtData) = 0 Then
bDone = True
End If
Loop
TbTextoExecute.Text = strData ‘El texto devuelto se introduce en el TextBox TbTextoExecute
End Select

Una vez en el directorio adecuado, podemos “bajarnos” un fichero mediante este código:

Inet1.Execute "FTP://ftp.microsoft.com", "GET ReadMe1.txt C:\PruebaVB\Leeme1.Txt"

Al ejecutarlo dejó el fichero ReadMe1.txt en la carpeta C:\PruebaVB con le nombre Leeme1.Txt.


Contenía esto:

The Microsoft Knowledge Base is currently published to this server in three formats. Two of the formats are published for legacy
reasons and are now obsolete. The KB will be posted to this server only in HTM format as of August 1, 2002.
The Microsoft Knowledge base has been posted to this server in text format since 1993. With the growth of the world wide web and
the spread of browser technology, the HTML formats of the KB became the defining standard, and in many cases the text rendering
of the content lost important data only visible in the HTML view. We will be discontinuing text format output to ensure our customers
don't miss critical data in the articles they download from this server. One variant of text files we have been publishing is SPV files.
SPV files group articles by the product that they apply to. An article can only belong in one group, which avoids duplicates if more
than one collection is downloaded. Today, many articles apply equally to multiple products. As such, the binary or arbitrary division
of articles results in information being hidden from customers who needed it. Effective August 1, we will no longer divide articles on
this server by these arbitrary groupings and the published SPV files will be deleted.
The KB will continue to be available for download at ftp://ftp.microsoft.com/misc/kb as HTM files.
The files which were in this location will be available until July 31, 2002 at ftp://ftp.microsoft.com/misc1.
The zipped SPV files that were being stored here are now located at ftp://ftp.microsoft.com/misc1 until 07/31/02 at which time these
files will no longer be available.
In summary:
The following folders and/or files at:
ftp://ftp.microsoft.com/bussys/...../kb
ftp://ftp.microsoft.com/deskapps/...../kb
ftp://ftp.microsoft.com/developr/...../kb
ftp://ftp.microsoft.com/MISC/
ftp://ftp.microsoft.com/peropsys/...../kb
are all located at:
ftp://ftp.microsoft.com/MISC1/
and only at:
ftp://ftp.microsoft.com/misc/kb
will there be HTM files after 7/31/02.
Thank you,
endspv@microsoft.com

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 33


Podría enviar un fichero para el servidor. Pero no se lo iba a aceptar. Muchos de los comandos
enumerados arriba sólo pueden ejecutarse si el usuario tiene privilegios en el host servidor. Por ejemplo,
los sitios FTP anonymous no permiten enviar ficheros, ni eliminar archivos ni directorios.

Transmisión asíncrona del método Execute


Al contrario que el método OpenURL, el método Execute produce una transmisión asíncrona de los
datos. Cuando se invoca el método Execute, la operación de transferencia se produce
independientemente de otros procedimientos. Por tanto, después de invocar el método Execute es
posible ejecutar otro código mientras se reciben datos en segundo plano. Pero cuidado con esto, que no
podrá invocar otro método que afecte a la conexión hasta que la transferencia haya terminado o haya
sido abortada, por ejemplo, por haber ocurrido un error de transmisión.

Este es el motivo por el que tras el método Execute, haya que recurrir al método GetChunk, aplicándolo
cuando el parámetro State del procedimiento StateChanged haya tomado el valor 12 (Respuesta
completa). No se puede saber cuando ha terminado la recepción de los datos, por lo tanto es necesario
disponer de un recurso que nos lo indique.

Guardar en un archivo con el método OpenURL


El método GET sobre FTP guarda directamente un archivo en un fichero, haciendo una copia exacta del
fichero que estaba en el servidor. Recuerde el código con el que nos habíamos bajado el fichero desde
Microsoft.

Inet1.Execute "FTP://ftp.microsoft.com", "GET ReadMe1.txt C:\PruebaVB\Leeme1.Txt"

Es decir:

Inet1.Execute "DireccionFTP", "GET NombreFicheroenServidor NombreFicheroLocal"

Este método no da ningún problema en cuanto a la exactitud de los datos. El fichero guardado en el
disco local es idéntico al que estaba en el servidor.

Recuerde que anteriormente habíamos explicado el método OpenURL pero solamente lo habíamos
aplicado al contenido de una página Web (Texto) y por lo tanto habíamos puesto en el método OpenURL
como tipo de datos strURL

Cuando el fichero a bajar mediante OpenURL es un fichero binario (Contiene todos los caracteres
posibles) el hecho de decirle que el tipo de datos va a ser texto implica que muchos de los caracteres se
perderán (El carácter cero sin ir más lejos) En este caso debe decirle que los datos son una matriz de
Bytes. Para ello, debemos declarar como Byte la variable donde vamos a meter cada uno de los
caracteres.

Si desea guardar en un archivo los datos obtenidos con el método OpenURL, puede usar las
instrucciones Open, Put y Close, como se muestra en el código siguiente. En este ejemplo se transfiere
un archivo binario a una matriz de bytes antes de guardar los datos en disco:

Dim strURL As String


Dim bData() As Byte ' Variable de datos
Dim F As Integer ' Variable para conocer el primer archivo (canal) libre FreeFile
strURL = "ftp://ftp.microsoft.com/Softlib/Softlib.exe"
F = FreeFile() ' Establece F a un integer con el archivo más bajo sin utilizar
' El resultado del método OpenURL va a la matriz de bytes y ésta se guarda entonces en disco.
bData() = Inet1.OpenURL(strURL, icByteArray)
Open "C:\Temp\Softlib.exe" For Binary Access Write As #F
Put #F, , bData()
Close #F

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 34


Se puede emplear un procedimiento similar para escribir un archivo de texto en disco, pero ahora no es
necesaria una matriz de bytes, pues los datos se guardan directamente en el archivo:
Dim strURL As String ' Cadena URL
Dim intFile As Integer ' Variable FreeFile
IntFile = FreeFile()
strURL = "http://www.microsoft.com/spanish"
Open "c:\temp\MSsource.txt" For Output _
As #IntFile
Write #IntFile, Inet1.OpenURL(strURL)
Close #IntFile

Sugerencia Cuando utilice el método OpenURL o el método Execute, no necesita establecer la


propiedad Protocol. El control Internet Transfer establecerá automáticamente el protocolo correcto,
según determine la parte de protocolo de la dirección URL.

Iniciar sesión en los servidores FTP


Hay servidores FTP de dos tipos: públicos y privados. Los servidores públicos, como su nombre indica,
están abiertos a todos. Los servidores privados, por otra parte, no le permitirán el acceso si no es un
usuario de confianza del servidor. En cualquier caso, el protocolo FTP solicita un nombre de usuario y
una contraseña. Estos dos elementos se utilizan para autentificar al usuario y permitir (o impedir) sus
acciones posteriores.
Para iniciar una sesión en los servidores públicos, la práctica habitual es especificar como nombre de
usuario "anonymous", (UserName = "anonymous") y enviar su propia dirección de correo electrónico
como contraseña. Sin embargo, este proceso se simplifica aún más con el control Internet Transfer. De
forma predeterminada, no hay que indicar los valores de las propiedades UserName y Password, pues
el control envía "anonymous" en la primera y su dirección de correo electrónico en la segunda.
Si va a iniciar una sesión en un servidor privado, sólo tiene que establecer las propiedades UserName,
Password y URL a los valores apropiados e invocar el método Execute, como se muestra en el ejemplo
siguiente:

With Inet1
.URL = "ftp://ftp.iies.es"
.UserName = "NombreRegistrado"
.Password = "ClavedeAcceso"
.Execute , "DIR" ' Devuelve el directorio.
Do While Inet1.StillExecuting = True
DoEvents
Loop
.Execute , "CLOSE" ' Cierra la conexión.
End With

Una vez invocado el método Execute, la conexión FTP permanecerá abierta. Puede entonces continuar
utilizando el método Execute para realizar otras operaciones de FTP, como CD y GET. Cuando haya
completado la sesión, cierre la conexión con el método Execute y con la operación CLOSE. También
puede cerrar la conexión automáticamente si modifica la propiedad URL e invoca el método OpenURL o
Execute; esta acción cerrará la conexión FTP actual para abrir la nueva dirección URL.

Ya hemos visto un poco como funciona. No se preocupe si le empiezan fallando las primeras
aplicaciones que vaya haciendo. Con lo leído hasta aquí no se conoce todavía este control de forma
suficiente. Le llevará un buen tiempo (y muchos errores en sus aplicaciones) aumentar sus
conocimientos, pero con lo visto tiene para empezar a andar. No olvide que muchas veces la instrucción
que está empeñado en hacer no se puede porque le faltan permisos de acceso a su servidor. Paciencia
y sobre todo, apunte sus experiencias.

Vamos a ver una a una las propiedades del Inet.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 35


Propiedades de Control Internet Transfer

Propiedad AccessType
La hemos visto más atrás. Determina si se accede a Internet directamente (1), con Proxy (2) o las
preestablecidas en su PC
Propiedad Document
Devuelve o establece el archivo o documento que se usará con el método Execute. Si no especifica esta
propiedad, se empleará el documento predeterminado del servidor. Si no especifica ningún documento,
se producirá un error en las operaciones de escritura.

Sintaxis Inet1.Document = cadena

hInternet (Propiedad)
Devuelve el controlador de Internet de la API de Wininet.dll subyacente. Por tanto, puede usar este
controlador en llamadas directas a la API. Esta propiedad no se utiliza cuando efectúa el acceso al
control desde Visual Basic.

Sintaxis VariableLong = Inet1.hInternet

Propiedad UserName
Devuelve o establece el nombre de usuario que se enviará con las solicitudes a los equipos remotos. Si
deja en blanco esta propiedad, el control enviará "anonymous" como nombre de usuario al realizar
solicitudes.

Sintaxis Inet1.UserName = nombre

Propiedad Password
Devuelve o establece la contraseña que se enviará junto con la solicitud de inicio de sesión a los equipos
remotos. Si deja esta propiedad en blanco, el control enviará la contraseña predeterminada (Dirección de
Correo electrónico).

Sintaxis Inet1.Password = cadena

Propiedad Protocol
Establece el protocolo que desea usar con el método Execute.

Sintaxis Inet1.Protocol = entero

Los valores válidos para entero son:


Constante Valor Descripción
icUnknown 0 Desconocido.
icDefault 1 Protocolo predeterminado.
icFTP 2 FTP. Protocolo de transferencia de archivos.
icReserved 3 Reservado para uso futuro.
icHTTP 4 HTTP. Protocolo de transferencia de hipertexto.
icHTTPS 5 HTTP seguro.

Comentarios
Cuando especifica esta propiedad, la propiedad URL se actualiza para mostrar el nuevo valor. Además,
si la parte de protocolo de la dirección URL se actualiza, también se modifica la propiedad Protocol para

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 36


reflejar el cambio. Los métodos OpenURL y Execute también pueden modificar el valor de esta
propiedad. El cambio de valor de esta propiedad no tiene ningún efecto hasta que se invoque el
siguiente método Execute u OpenURL.
Propiedad Proxy
Vista más atrás. Devuelve o establece el nombre del servidor proxy utilizado para comunicar con
Internet.

Propiedad RequestTimeout
Devuelve o establece la duración, en segundos, de un intervalo de espera. Si no se responde a una
solicitud dentro del intervalo especificado y si la solicitud se efectuó con el método OpenURL (solicitud
síncrona), se produce un error. Si la solicitud se efectuó con el método Execute, se producirá el método
StateChanged junto con un código de error. El valor 0 de esta propiedad significa espera indefinida.

Sintaxis Inet1.RequestTimeout = tiempoensegundos

Propiedad ResponseCode
Devuelve el código de error de la conexión cuando aparece el estado icError (11) en el evento
StateChanged. Si desea obtener una descripción del error, vea la propiedad ResponseInfo.

Sintaxis Inet1.ResponseCode= código

Propiedad ResponseInfo
Devuelve la descripción del último error que se ha producido.

Sintaxis Inet1.ResponseInfo

Puede usar el evento StateChanged para recibir la notificación de un error. En el case = 11 podemosm
poner este código y vemos las dos propiedades anteriores.

MsgBox “Ha ocurrido el error “ & Inet1.ResponseCode & “ : “ & Inet1.ResponseInfo

Propiedad StillExecuting
Devuelve un valor True / False que especifica si el control Internet Transfer está ocupado. El control
devolverá True cuando esté realizando una operación como obtener un archivo de Internet y no
responderá a ninguna otra solicitud mientras esté ocupado.

Sintaxis VariableBooleana = Inet1.StillExecuting

Si VariableBooleana = True es que está ocupado

Propiedad URL
Devuelve o establece la dirección URL empleada por los métodos Execute y OpenURL.

Sintaxis Inet1.URL = Nombredela URL

Al invocar los métodos OpenURL y Execute, cambia el valor de esta propiedad por el que se introduzca
al ejecutar esos métodos. La modificación de esta propiedad no tiene ningún efecto hasta que se llama
al siguiente método OpenURL o Execute.

La propiedad URL debe contener al menos un protocolo y un nombre de host remoto.


La propiedad URL puede especificar un directorio o un archivo. Por ejemplo, son válidas las dos
direcciones URL siguientes:
Inet1.URL = HTTP://www.microsoft.com ' Con esta URL sólo obtendrá el directorio del archivo

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 37


Inet1.URL = "HTTP://www.microsoft.com/disclaimer.txt" ‘' Con esta obtendrá el texto del archivo:

La propiedad URL casi no es necesario usarla, ya que se puede introducir directamente en los métodos
OpenURL y Execute. Esta propiedad cambia cada vez que se invocan esos método con otro valor para
la URL, quedando el último valor usado como valor actual de la propiedad.

Nota Cuando utilice el método OpenURL, establezca la propiedad URL antes que las propiedades
Password y UserName. Si establece la propiedad URL en último lugar, las propiedades UserName y
Password estarán establecidas a "".

Errores interceptables del control Internet Transfer


En las tablas siguientes se indican los errores interceptables correspondientes al control Internet
Transfer y las constantes asociadas.
Constante Valor Descripción
IcOutOfMemory 7 "Memoria insuficiente"
IcDisconnected 10 El equipo ha sido desconectado de la red.
IcTypeMismatch 13 "El tipo no coincide"
IcInvalidPropertyValue 380 El valor de la propiedad no es válido
IcInetOpenFailed 35750 No se puede abrir el controlador de Internet
IcOpenFailed 35751 "No se puede abrir la dirección URL"
IcBadUrlL 35752 "La dirección URL está mal generada"
IcProtMismatch 35753 "Este método no es compatible con el protocolo"
IcConnectFailed 35754 "No se puede conectar con el host remoto"
IcNoRemoteHost 35755 "No se ha especificado ningún equipo remoto"
IcRequestFailed 35756 "No se puede completar la petición"
IcNoExecute 35757 "Debe ejecutar una operación antes de recuperar datos"
IcBlewChunk 35758 "No se puede recuperar datos"
IcFtpCommandFailed 35759 "Falló el comando FTP"
IcUnsupportedType 35760 "No se puede forzar el tipo"
IcTimeOut 35761 "Se excedió el tiempo de espera"
IcUnsupportedCommand 35762 "El comando no es válido o no es compatible"
IcInvalidOperation 35763 "Argumento de operación no válido"
IcExecuting 35764 "Todavía se está ejecutando la última petición"
IcInvalidForFtp 35765 "Esta llamada no es válida para una conexión FTP"
IcOutOfHandles 35767 "Sin controladores"
IcinetTimeout 35768 "Se ha excedido el tiempo de espera"
IcInetTimeout 35768 Se ha excedido el tiempo de espera
IcExtendedError 35769 Error extendido.
IcIntervalError 35770 Error interno.
IcInvalidURL 35771 Dirección URL no válida.
IcUnrecognizedScheme 35772 Patrón no reconocido
IcNameNotResolved 35773 Nombre sin resolver.
IcProtocolNotFound 35774 Protocolo no encontrado.
IcInvalidOption 35775 Opción no válida.
IcBadOptionLength 35776 Longitud de opción incorrecta.
IcOptionNotSettable 35777 La opción no se puede establecer
IcShutDown 35778 Apagar

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 38


IcIncorrectUserName 35779 Nombre de usuario incorrecto.
IcLoginFailure 35781 Error al iniciar la sesión.
IcInetIvalidOperation 35782 Operación no válida.
IcOperationCancelled 35783 Operación cancelada.
IcIncorrectHandleType 35784 Tipo incorrecto de controlador.
IcIncorrectHandleState 35785 Estado incorrecto del controlador.
IcNotProxyRequest 35786 No es un proxy.
IcRegistryValueNotFound 35787 Valor del Registro no válido.
IcbadRegistryParameter 35788 Parámetro del registro incorrecto.
IcNoDirectAccess 35789 Sin acceso directo.
IcIncorrectPassword 35780 Contraseña incorrecta.
IcNoContext 35790 Sin contexto.
IcNoCallback 35791 Sin devolución de llamada.
IcRequestPending 35792 Petición pendiente.
IcIncorrectFormat 35793 Formato incorrecto.
IcItemNotFound 35794 No se encuentra el elemento.
icCannotConnect 35795 No se puede conectar.
icConnectionAborted 35796 Conexión anulada.
icConnectionReset 35797 Conexión restablecida.
icForceEntry 35798 Forzar reintento.
icInvalidProxyRequest 35799 Petición del proxy no válida
icWouldBlock 35800 Con bloqueo.
icHandleExists 35802 El controlador ya existe.
icSecCertDateInvalid 35803 Fecha de certificación de seguridad no válida.
icSecCertCnInvalid 35804 Número de certificación de seguridad no válido.
icHttpsToHttpOnRedir 35806 HTTPS a HTTP al redirigir.
icMixedSecurity 35807 Seguridad mixta.
icChgPostIsNotSecure 35808 Cambiar la exposición no es seguro.
icHttpToHttpsOnRedir 35808 HTTPS a HTTP al redirigir.
icPostIsNonSecure 35809 La exposición no es segura.
icClientAuthCertNeeded 35810 Es necesaria la certificación de autorización del cliente.
icInvalidCa 35811 Autorización del cliente no válida.
icClientAuthNotSetup 35812 Autorización de cliente no establecida.
icAsyncThreadFailed 35813 Error en el subproceso Async.
icRedirectSchemeChange 35814 Cambio en el patrón de redirección.
La operación está suspendida hasta que cierre un cuadro de
icDialogPending 35815
diálogo abierto.
icRetryDialog 35816 Intente la operación de nuevo.
Debe volver a intentar la operación porque falló la
icHttpsHttpSubmitRedir 35818
comprobación de seguridad de zona
La caché de CD instalable requiere un CD-ROM presente en
icInsertCdrom 35819
la unidad.
icFtpTransferInProgress 35876 FTP: transferencia en curso.
icFtpDropped 35877 FTP: conexión interrumpida.
Se intentó una conexión en modo pasivo (es decir, la solicitud
de conexión original se especificó como
icFtpNoPassiveMode 35878
INTERNET_FLAG_PASSIVE), pero el servidor no permite
ese modo.
icGopherProtocolError 35896 Gopher: Error de protocolo.
icGopherNotFile 35897 Gopher: No es un archivo.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 39


icGopherDataError 35898 Gopher: Error de datos.
icGopherEndOfData 35899 Gopher: Fin de los datos.
icGopherInvalidLocator 35900 Gopher: Localizador no válido.
icGopherIncorrectLocatorT
35901 Gopher: Tipo de localizador incorrecto.
ype
icGopherNotGopherPlus 35902 Gopher: Sin Gopher Plus.
icGopherAttributeNotFound 35903 Gopher: No se encontró el atributo.
icGopherUnknownLocator 35904 Gopher: Localizador desconocido.
icHeaderNotFound 35916 HTTP: No se encontró el encabezado.
icHttpDownlevelServer 35917 HTTP: Servidor de bajo nivel.
icHttpInvalidServerRespons
35918 HTTP: Respuesta del servidor no válida.
e
icHttpInvalidHeader 35919 HTTP: Encabezado no válido.
icHttpInvalidQueryRequest 35920 HTTP: Petición de consulta no válida.
icHttpHeaderAlreadyExists 35921 HTTP: El encabezado ya existe.
icHttpRedirectFailed 35922 HTTP: Falló la redirección.
icSecurityChannelError 35923 Error de seguridad de canal.
icUnableToCacheFile 35924 No se puede almacenar en caché el archivo.
icHttpCookieNeedsConfirm Debe confirmar un cookie suministrado por el servidor antes
35927
ation de que comience la transferencia.
icHttpCookieDeclined 35928 No fue aceptado un cookie suministrado por el servidor.
No fue posible la conexión con el servidor solicitado. Esto se
icServerUnreachable 35930 produjo por el error WSAEHOSTUNREACH recibido desde
WinSock.
icProxyServerUnreachable 35931 No se pudo alcanzar el servidor proxy solicitado.
Existe un error en el archivo de comandos de configuración
icBadAutoProxyScript 35932 automática del proxy, de modo que el archivo de comandos
no pudo ejecutarse.
No se pudo recibir el archivo de configuración automática del
icUnableToDownloadScript 35933
proxy solicitado.
icHttpRedirectNeedsConfir Debe confirmar una redirección del nivel de protocolo antes
35934
mation de que pueda comenzar la transferencia.
icSecInvalidCert 35935 El certificado no es válido
icSecCertRevoked 35936 El certificado ha sido revocado.
icFailedDueToSecurityChec Falló la operación que intentó porque no pudo pasar la
35937
k comprobación de seguridad.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 40


Visual Basic e Internet (3)
Control WebBrowser

El Control WebBrowser
El control WebBrowser es un control DLL-ActiveX (Concretamente el Shdocvw.dll) que se encuentra en
la lista de componentes (Proyecto |Componentes) como Microsoft Internet Controls. En la caja de
herramientas está representado como un icono que representa un globo del mundo.
Forma parte del Internet Explorer de Microsoft. Es decir, es una pieza de las usadas por
Microsoft para su navegador de Internet.

El WebBrowser puede buscar páginas en la red o en el disco local y presentarlas. Presenta un


documento Html y guarda el historial, de forma que siempre puede volver atrás en su navegación. Puede
incluso presentar un documento Word ó Excel.

Parece en principio que no es práctico realizar un nuevo navegador, usando precisamente la misma
“pieza” que usa el Internet Explorer. Para eso ya tenemos el Internet Explorer. Y ciertamente es así. Pero
no voy a negar que tienen algo de sugestivo realizar un navegador propio para nuestras aplicaciones,
aún a sabiendas que estamos usando una parte del IE. Analizaremos las propiedades, métodos y
evento más relevantes, presentaremos el Guia del Estudiante Internet Explorer, y luego será el alumno
quien decida si merece la pena hacer algo con este control o no.

Propiedades del control WebBrowser

La información y ayuda del WebBrowser vienen en el disco 2 del MSDN. Dependiendo de cómo haya
instalado el MSDN le aparecerá o no en la ayuda normal de VB que sale pulsando F1. Le recomiendo
que los dos discos del MSDN debe tenerlos continuamente en su puesto de trabajo.

Propiedad Busy

Devuelve un valor True / False indicando que el WebBrowser está ocupado en una operación de
navegación o bajando un archivo. Puede usar el método Stop para detener la operación en curso.

Propiedad Container

Devuelve una referencia al formulario u otro contenedor que contiene al WebBrowser. Como devuelve
una referencia al objeto, podremos ver cualquier propiedad de ese objeto, por ejemplo, su nombre:

Label1 = brwWebBrowser.Container.Name

Esta línea devuelve el nombre del formulario que contioenen al WebBrwser

Propiedad Document

Devuelve una referencia al documento que está presentando el WebBrowser. Al devolver una referencia,
podemos ver cualquier propiedad de ese documento, por ejemplo, su título.

Propiedad FullScreen

Devuelve un valor True / False indicando si el navegador está maximizado.

Propiedades Height / Width

Devuelven el alto y ancho de la ventana del WebBrowser medidos en la unidad de medida del formulario
o contenedor.
LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 41
Propiedades Left / Top

Devuelven la distancia desde la parte izquierda o desde la parte superior del formulario o contenedor, al
vértice superior izquierdo del WebBrowser, medidos en la unidad de medida del formulario.

Propiedad LocationName

Devuelve una cadena con el nombre del documento que está presentando el WebBrowser. Si lo que está
presentando es una página Web del www, devuelve el título de la página. Si lo que está presentando es
un fichero del disco, preseta el nombre (Sin el path) de ese fichero

Propiedad LocationURL

Devuelve una cadena con el nombre del documento que está presentando el WebBrowser. Si lo que está
presentando es una página Web del www, devuelve el título de la página. Si lo que está presentando es
un fichero del disco, preseta el nombre con el Path completo de ese fichero

Propiedad Offline

Devuelve o establece un valor True / False que indica si el WebBrowser está actalmente operando en
modo OffLine. En este modo, el WebBrowser está obligado a leer las páginas de la caché del ordenador,
pero si no las tiene, accede al servidor a buscarlas.

Propiedad Parent

Devuelve una referencia al formulario o contenedor del WebBrowser. Funciona igual que la propiedad
Container.

Propiedad ReadyState

Devuelve un valor que indica el estado de la operación actual del WebBrowser. Toma uno de los
siguientes valores:

Valor Constante Descripción

0 READYSTATE_UNINITIALIZED Sin operación. Estado por defecto


1 READYSTATE_LOADING = 1 Cargando sus propiedades
2 READYSTATE_LOADED El WebBrowser ya está inicializado
3 READYSTATE_INTERACTIVE Está descargando una página
4 READYSTATE_COMPLETE Ya ha terminado de descargar la página

Propiedad Type

Devuelve un string con el tipo de documento que está presentando

Label1 = brwWebBrowser.Type

Propiedad Visible

Establece si el WebBrowser se ve o está oculto

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 42


Métodos de WebBrowser

Método ExecWB
Ejecuta un comando usando la interface IOLECommandTarget. La sintaxis es la siguiente:

NombreDelWebBrowser.ExecWB nCmdID, nCmdExecOpt, [pvaIn], [pvaOut]

NCmdID (Requerido) Es un Long o una constante que identifica el comando a ejecutar.

NCmdExecOpt (Requerido) Es un Long o constante que indica las opciones de ese comando.

PvaIn (Opcional) Un Variant que se emplea para introducir argumentos al comando.

PvaOut (Opcional) Un Variant que se emplea para recoger los resultados

La primera cuestión que surge ahora es ¿Dónde está la lista de los comandos que se pueden
ejecutar? Desconozco donde se puede encontrar la información de todos los comandos, pero
pueden verse uno a uno en el Examinador de Objetos en las clases OLECMDID para los los
identificadores de comandos, y OLECMDEXECOPT para las opciones. Asi, si quiere imprimir el
contenido del WebBrowser basta con poner la siguiente instrucción:

brwWebBrowser.ExecWB OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER


Esto es lo mismo que decir:

brwWebBrowser.ExecWB 6, 2

Y lo que hace es, imprimir (6) y presentar el cuadro de diálogo para seleccionar la impresora. (2)

Esto de no conocer la lista de comandos aunque parece dificil (y lo es) es superable. Cuando estamos
introduciendo el método ExecWB aparece la lista con todos los comandos posibles. Y habrá que echar
imaginación y ver, dentro de la lista presentada, el comando que nos interesa. Así sugió la línea
siguiente para guardar la página:

brwWebBrowser.ExecWB OLECMDID_SAVEAS, OLECMDEXECOPT_PROMPTUSER

Puede ver la lista completa de los


comandos en el Explorador de
Objetos (Al que se accede pulsando
F2) y que presentamos en esta
página como recordatorio. En la
imagen está presentando la Clase
OLECMDID. Puede presentar la
clase OLECMDEXECOPT haciendo
clic sobre su línea en el cuadro de
la izquierda. Dejo al alumno
interesado el trabajo de realizar una
lista con todos estos comandos, sus
constantes y valores.

Nota. Para que aparezca en el


Explorador de Objetos la lista con
todos los comandos OLECMDID
debe estar introducido el control
WebBrowser en el proyecto.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 43


Método GoBack

Navega hacia atrás dentro de la lista de las páginas visitadas.

Método GoForward

Navega hacia delante dentro de la lista de páginas visitadas

Método GoHome
Abre la página especificada como página inicial en las opciones del Internet Explorer.

Método GoSearch

Abre la página especificada en el Internet Explorer como página de b´squeda (¿)

Método Navigate

Abre la página especificada.

Sintaxis :

NombreWebBrowser.Navigate URL [Flags,] [TargetFrameName,] [PostData,] [Headers]


URL Requerido. Una cadena con la dirección del documento a mostrar. Puede ser una URL de una
página en la Web, dirección completa de un fichero en el disco, una dirección IP.

Flags Opcional. Un valor o constante que determina varias cosas, según se explica en la lista siguiente.
Pueden sumarse dos o más valores de estos.

Constante Valor Descripción

NavOpenInNewWindow 1 Abre la página en una nueva ventana.


NavNoHistory 2 No añade la página a la lista del histórico de páginas.
NavNoReadFromCache 4 No lee de la cahé del disco para buscar la página.
NavNoWriteToCache 8 No guarda la página abierta en la caché

TargetFrameName Opcional. Indica la ventana sobre la que mostrará la nueva página. Los valores
posibles son:

_blank Presenta el documento sobre una nueva ventana sin nombre


_parent Presenta el documento en el contenedor inmediatamente superior al que tienen el link.
_self Presenta el documento dentro de la misma ventana que tienen el link
<window_name> Presenta el documento en el frame especificado por el nombre. Si no existe un frame
con ese nombre, abre una nueva ventana.

PostData Opcional. Este parámetro es el dato a enviar al servidor durante la transacción HTTP
POST (POST es una forma de enviar datos desde un cliente al servidor HTTP)
Headers Opcional. En este parámetro se especifican los Header que se envian al servidor para
especificar acciones que el cliente desea que haga el servidor.

Método Navigate2

Extiende el método Navigate para poder navegar por carpetas especiales tales como el escritorio o
Mi PC. La sintaxis es idéntica a la del método Navigate.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 44


Método Refresh

Vuelve a cargar el documento que está presentando.

Sintaxis NombredelWebBrowser.Refresh

Método Refresh2

Vuelve a cargar el documento que está presentando. La diferencia con el Método Refresh es que
este método contienen un parámetro que especifica el nivel de actualización.

Sintaxis NombredelWebBrowser.Refresh2 Nivel

Nivel puede tomar uno de los siguientes valores:

Constante Valor Descripción

REFRESH_NORMAL 0 Realiza un refresco simple, en el que no incluye el envio del


header “pragma:nocache” al servidor

REFRESH_IFEXPIRED 1 Realiza un refresco simple si la página ha caducado

REFRESH_COMPLETELY 3 Realiza un refresco completo, enviando al servidor el header


“pragma:nocache”

El header "pragma:nocache" obliga al servidor a no enviar una copia que tenga en su propia cache.
De esta forma sabemos que nos va a enviar la información más reciente. Los navehadores suelen
enviar este header cuando el usuario selecciona Actualizar. Esto puede causar problemas en
algunos servidores.

Método Stop

Cancela cualquier navegación pendiente y la recepción de cualquier elemento dinámico de la página,


como puede ser sonidos o animaciones..

Sintaxis NombredelWebBrowser.Stop

Eventos del control WebBrowser

Evento BeforeNavigate2

Este evento ocurre cuando el control WebBrowser cambia la navegación a otra URL diferente. Esto
puede ocurrir porque el usuario ha hecho click en un link o por cualquier otra razón. En este evento
se tiene la oportunidad de cancelar la nueva navegación.

Private Sub object_BeforeNavigate2(ByVal pDisp As Object, ByVal URL As String,


ByVal Flags As Long, ByVal TargetFrameName As String, PostData As Variant,
ByVal Headers As String, Cancel As Boolean)

Para impedir la navegación a una nueva URL basta con poner esta línea de código:

Cancel = True

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 45


DocumentComplete Event

Ocurre cuando el documento que está siendo bajado pasa al estado READYSTATE_COMPLETE. Este
evento tienen importancia cuando un documento tiene frames, pues se produce cada vez que se termina
de enviar el documento correspondiente a cada una de las frames.

Evento DownloadBegin

Ocurre cuando comienza una operación de navegación. Este evento ocurre inmediatamente después del
BeforeNavigate2, excepto que la navegación haya sido cancelada en aquel. A cada evento
DownloadBeguin le tiene que suceder un DownloadComplete, por lo que puede aprovechar ambos
eventos para señalar mediante un icono que se está bajando un nuevo documento. (El Internet Explorer
lo hace mediante un globo mundial girando)

Evento DownloadComplete

Ocurre cuando la navegación termina, se detienen voluntariamente o ha fallado.

Evento NavigateComplete2

Ocurre cuando el WebBrowser ha alcanzado con éxito la nueva URL. A partir de este momento es
cuando comienza a bajarse el documento. Este evento es el apropiado para poner el aviso: Sitio Web
encontrado.

Evento NewWindow2

Ocurre cuando se ha creado una nueva ventana para presentar un nuevo documento.

Evento OnFullScreen

Ocurre cuando ha cambiado la propiedad FullScreen

Evnto OnVisible

Ocurre cuando cambia la propiedad Visible

ProgressChange Event

Ocurre cuando se actualiza el avance de la operación de bajar un documento.

Private Sub object_ProgressChange(ByVal Progress As Long, ByVal ProgressMax As Long)

Progress Long conteniendo el número total de Bytes transferidos

ProgressMax Long con el número total de bytes a tranferir.

Este evento se puede usar para colocar un aviso tranquilizante de la evolución de la descarga del
documento.

LSB Visual Basic Guía del Estudiante Cap. 18 Pág. 46


Visual Basic - Guía del Estudiante Cap. 19

REALIZACION DE CONTROLES OCX

A modo de comentario. Hemos llegado a un capítulo que todos los alumnos desean conocer:
el capítulo donde vamos a ver como se crea un control personalizado. A lo largo de mis años
de docencia he observado que los alumnos mas aventajados tienden a realizar aplicaciones
usando controles realizados por ellos mismos, en la creencia que eso protege sus programas
frente a posibles imitaciones, ya que parece que poseen la llave que da acceso a sus secretos.
Incluso hay quien piensa que el uso de este tipo de controles da cierto prestigio como
programador. Y hay también empresas especializadas en software que comparten esas mismas
ideas. En el ámbito empresarial hay quien realizó uno de estos controles con fecha de
caducidad, de forma que pasada una fecha, el control deja de funcionar y con él la aplicación.
Buena forma de asegurarse el contrato de mantenimiento, ya que el control había que
reemplazarlo antes de llegar a esa fecha, pero una hermosa forma a la vez de perder al cliente
y la credibilidad como empresario y como programador. Es una cuestión de criterios personales
o comerciales, pero la creación de controles personalizados es una práctica que solamente
debe llevarse a cabo cuando es estrictamente necesario por no existir ningún recurso en VB
que realice lo deseado. Y es decisión muy prudente no aceptar ninguna aplicación que llevando
un control personalizado, no se entregue con la aplicación, toda la información relativa al
mismo, incluyendo su código fuente.

Para crear un control, lo primero que hay que hacer es pensar, con papel y lápiz, las funciones
que debe realizar ese control, así como sus propiedades y métodos. Hay que pensar durante
este proceso, si el control se va a encapsular dentro de un OCX solo o con otros
controles, ya que un mismo OCX puede contener más de un control. Una vez
realizado este estudio previo, se procede a abrir un nuevo proyecto, eligiendo en
este caso la creación de un Control ActiveX, sobre el icono mostrado en la figura.
Aparecerá algo distinto a lo que nos encontramos cuando creamos un proyecto EXE
Standard.

Lo primero que observamos es que no aparece un formulario, sino algo, que si bien se le
parece, sabemos que no lo es. Esa especie de formulario es el objeto UserControl.

El UserControl es el objeto base del control que estamos creando. Un control ActiveX se
compone siempre de un UserControl y sobre él podremos colocar otros controles. A los
controles que colocamos sobre el UserControl se les denomina Controles Constituyentes.

Un proyecto con un UserControl es similar a un proyecto con un formulario. El proyecto se


guarda en un fichero ASCII con extensión .vbp igual que cualquier proyecto Visual Basic. El
nombre de ese fichero será el nombre con el que se ha guardado el proyecto.
El UserControl se guarda también en un fichero ASCII. De la misma forma que un formulario se
guarda con extensión .frm, un UserContol se guarda con extensión .ctl Y de la misma forma
que un formulario, cuando tenía gráficos éstos se guardaban en un fichero aparte, con
extensión .frx, cuando un UserControl tiene gráficos se guardan en un fichero con extensión
.ctx El nombre de ambos ficheros es el mismo con el que se haya guardado el UserControl.

Al compilar el proyecto, en vez de generar un fichero .EXE, generará un fichero .OCX Y este
OCX es idéntico a los que vemos en Proyecto | Componentes cada vez que queremos
introducir un componente que no está en la barra de herramientas. (Falta registrarlo, pero
veremos más adelante como se registra)

Se pueden introducir varios UserControl en un mismo proyecto. Esto generará igual número de
controles dentro del mismo paquete .OCX. esta práctica es bastante normal. Por ejemplo, el
MSCOMCTL.OCX (Microsoft Windows Common Controls 6.0) contiene 9 controles. Pero tenga
cuidado cuando meta controles dentro del mismo paquete. Piense que cada control va a ocupar
cierto sitio. Suponga que hace un OCX con 9 controles. Ocupará más espacio en disco que si
hubiese metido 1. Cuando meta en un proyecto uno solo de estos controles, deberá meter en el

LSB Visual Basic Guía del Estudiante Cap.19 Pág. 1


proyecto la totalidad del espacio que ocupaban los 9 controles. El caso del control de Microsoft
citado tienen su razón de ser. El OCX contiene 9 controles, que se pueden usar todos dentro
del mismo proyecto (Barra de herramientas, barra de estado, TreeView, ListView, Barra de
Progreso, Slider, TabStrip, Image Combo e ImageList)

Registrar un control. El registro de un control es una operación que Windows debe hacer para
meter los datos de ese control (nombre y ubicación dentro del disco) dentro del registro de
Windows. Esto le facilita la búsqueda del fichero.
Lo normal es colocar los controles OCX dentro de la carpeta C:\Windows\System. Puede
ponerlo en cualquier otra carpeta, pero esa es la usual. Eso sí, una vez puesto en la carpeta
deseada y registrado no lo puede mover, ya que Windows no lo encontraría.

Hay un método muy sencillo para registrar un control cuando tiene el Visual Basic instalado en
su PC. Guarde el fichero OCX en C:\Windows\System. Vaya a Proyecto | Componentes y le
aparecerá el cuadro para elegir un nuevo control. No aparecerá ese nuevo OCX dentro de la
lista de este cuadro, ya que todavía no está registrado.

Fig. 19.1 Cuadro para elegir un nuevo control

Haga clic sobre el botón Examinar… Le aparecerá el cuadro para seleccionar un fichero.
Seleccione el fichero OCX que acaba de introducir y ese OCX ya está registrado.
Cuidado. Esta forma, sencilla y sin complicaciones, puede llevarle en más de una ocasión a
registrar controles que no desea.

Cuando no tenga VB instalado tendrá que recurrir a un programa que trae Windows: el
Regsvr32.Exe Para ello vaya a Inicio | Ejecutar y en el cuadro que le aparece introduzca el
nombre del programa seguido del nombre completo del OCX a registrar. (Fig. 19.2)

Cuando realizamos la instalación de un programa realizado en Visual Basic, ocurre con mayor
frecuencia de la deseada que uno de los controles no se registra. El registro lo hace
automáticamente la instalación, pero a veces, falla. En algunos casos el programa funciona
perfectamente, pero en otros no funciona. Y en estos casos es normal que el OCX no haya
llegado a guardarse en el disco. Solución: copiar ese OCX directamente sobre
C:\Windows\System y realizar el registro de la forma descrita.

LSB Visual Basic Guía del Estudiante Cap.19 Pág. 2


Fig. 19.2 Forma de registrar un control OCX

Sigamos con el UserControl.

Propiedades, métodos y eventos del nuevo control.


El nuevo control que va a crear va a tener propiedades. Unas las va a tener porque son
inherentes a cualquier control (Left, Top, Tag, y aquellas que sean necesarias para la ubicación
del control y sus dimensiones) Otras, porque se han introducido durante la creación del control.
Los métodos y eventos deben introducirse todos durante la creación.

El UserControl tiene sus Propiedades, Métodos y Eventos. También las tienen los controles
constituyentes. Pero las propiedades, métodos y eventos de ninguno de ellos pasa a formar
parte de las propiedades, métodos o eventos del control que estamos creando.

Vamos a ver como se introducen las propiedades del nuevo control. Para ello vamos a estudiar
dos instrucciones de Visual Basic: Property Get y Property Let

Estas instrucciones se introducen igual que cuando se introduce una función o procedimiento
en un formulario. Haciendo clic en Herramientas | Agregar Procedimiento. Nos aparece un
cuadro donde debemos elegir Propiedad Recuerde que el elemento del menú de VB Agregar
Procedimiento solamente está activado cuando está abierta una ventana de código. La ventana
de código abierta debe ser del proyecto del control ActiveX (Del UserControl o de cualquiera de
los controles constituyentes) Se le pone el nombre que desea que tenga la propiedad. Por
ejemplo, si queremos que esa propiedad sea el color de fondo del nuevo control, pondremos
ColorDeFondo (¿Porque habríamos de poner Backcolor si el control se ha desarrollado en
España?)

Fig. 19.3 Cuadro para introducir una propiedad en el nuevo control

Basta con hacer clic en Aceptar y ya nos ha introducido dos nuevas cosas en la ventana de
código, en el desplegable de la derecha (Fig. 19.4)

LSB Visual Basic Guía del Estudiante Cap.19 Pág. 3


Fig. 19.4 Ventana de código mostrando PropertyGet y PropertyLet

Al introducir una nueva propiedad se generan estos dos


procedimientos (los denominaremos Procedimientos
Property) que tienen por nombre el de la propiedad que
acabamos de introducir, y llevan la coletilla de Property
Get y Property Let. Sin perder el tiempo guardamos el
proyecto y vamos a ver las propiedades del nuevo
control. (Veremos un poco más adelante como se pone
el control sobre un formulario dentro del mismo grupo de
proyectos) Vemos que figura una propiedad llamada
ColorDeFondo, tal como habíamos puesto en la Fig.
19.3
Puede ver que hay más propiedades, que no han sido
introducidas. Todas esas propiedades son la que se
introducen automáticamente como inherentes a
cualquier control.
La propiedad ya está en el cuadro de propiedades, pero
todavía no hace nada. Lo que queramos que haga
debemos programarlo justamente en esos dos
procedimientos property que acaban de aparecer.

Aparecen dos procedimientos porque en principio es


una propiedad de lectura y escritura. Mediante el
Property Let escribiremos el valor y con el Property Get
leeremos el valor de la propiedad. (Let pone el valor,
Get lee el valor)

Fig. 19.5 Cuadro de propiedades del nuevo control

Veamos como son esos dos procedimientos antes de introducir código:

Public Property Let ColorDeFondo(ByVal vNewValue As Variant)

End Property

Public Property Get ColorDeFondo() As Variant

End Property

Vea que empieza como todos los procedimientos, con Public (Podría ser Private) seguido de
Property Let (o Property Get) y termina con End Property
Como puede verse, el procedimiento Property Let necesita un valor, vNewValue que ha
declarado como Variant. A ese el procedimiento para poner el valor a la propiedad necesita que
le pasemos el valor de esa propiedad. Lo que no puede saber, es el tipo de dato que debe usar
para ColorDeFondo. Por eso pone As Variant y de esta forma podemos meter cualquier valor.
Sin embargo, sabemos desde el Capítulo 1 que las variables declaradas como Variant ocupan

LSB Visual Basic Guía del Estudiante Cap.19 Pág. 4


mucho espacio en memoria, y debemos optimizar el programa ajustando las variables. Como
sabemos que el color es un número Long, podemos sustituir el tipo Variant por un tipo Long:

Public Property Let ColorDeFondo(ByVal vNewValue As Long)

Public Property Get ColorDeFondo() As Long

Observe que lo hemos cambiado en los dos procedimientos. Si no se cambia en ambos dará
error.

También podemos cambiar el nombre de la variable interna del procedimiento (vNewValue) y


poner algo que resulte más comprensible:

Public Property Let ColorDeFondo(ByVal NuevoColor As Long)

En el caso del color también puede poner otro tipo de variable: OLE_COLOR, que es lo que
hace VB con el asistente.

Veamos ahora el código a introducir en ese Procedimiento Property

Como lo que queremos hacer con la propiedad ColorDeFondo es poner de un determinado


color el fondo del control, y el fondo del control es precisamente el UserControl, bastará con
poner que la propiedad BackColor del UserControl es precisamente el nuevo control a poner.
Observe que en el UserControl la propiedad se sigue llamando Backcolor.

Public Property Let ColorDeFondo(ByVal NuevoColor As Long)


UserControl.BackColor = NuevoColor
End Property

Es muy útil, no necesario, comunicar al control que ha cambiado una de sus propiedades. Esto
sirve para que pueda guardar el nuevo valor en su página de propiedades. Ya lo veremos. Para
comunicarle que ha cambiado una propiedad se le añade una línea al código anterior

Public Property Let ColorDeFondo(ByVal NuevoColor As Long)


UserControl.BackColor = NuevoColor
PropertyChanged "ColorDeFondo"
End Property

Ya veremos lo que ocurre con PropertyChanged

Este procedimiento es el que se ejecuta cuando ponemos un valor al color de fondo del nuevo
control cuando ponemos, por ejemplo

TBPV1.ColorDeFondo = 255 (TBPV1 es el nombre del control en el formulario de prueba)

Vamos a ver el código del procedimiento que se ejecuta cuando queremos saber el valor que
tienen esa propiedad.

Public Property Get ColorDeFondo() As Long


ColorDeFondo = UserControl.BackColor
End Property

Observe que el valor devuelto es el número de color de la propiedad BackColor del UserControl.

LSB Visual Basic Guía del Estudiante Cap.19 Pág. 5


Vamos a ver con más detalle los procedimientos Property Let y Property Get

Instrucción Property Let


Declara el nombre, los argumentos, y el código que forman el cuerpo de un procedimiento
Property Let, y asigna un valor a una propiedad.

Sintaxis

[Public Private Friend Static] Property Let NombreDelProcedimiento (argumentos)


instrucciones
Exit Property
instrucciones
End Property

El ámbito del procedimiento queda determinado por la primera expresión:

Public: El procedimiento Property es accesible desde cualquier parte del proyecto


Private: Es accesible solamente para los procedimientos del mismo módulo
Friend (Solo para Clases)El procedimiento no es visible por el controlador de una instancia
Static Los valores de las variables locales declaradas en el procedimiento mantienen su valor
entre distintas llamadas.

NombreDelProcedimiento es el nombre por el que se va a llamar y es precisamente el nombre


de la propiedad que va a controlar. Aunque en VB no pueden existir dos procedimientos con el
mismo nombre, en este caso sí, y el nombre del procedimiento Property Let puede ser igual
(de hecho siempre es igual) a otro procedimiento Property Get

Argumentos Argumentos que deben pasarse al llamar a ese procedimiento. El tipo de datos
de cada argumento será el mismo que en el procedimiento Property Get

Instrucciones Es el código que hay que escribir en el procedimiento para que realice lo que
desea el programador. Estas instrucciones pueden generar una condición en la que se debe
abandonar el procedimiento. En ese caso, puede salirse del procedimiento con Exit Prperty

Los argumentos pueden pasarse:

Por Valor (ByVal) El valor de la variable fuera del procedimiento mantienen el valor, aunque
ese valor cambie dentro del procedimiento.

Por Referencia (ByRef) El valor de la variable fuera del procedimiento cambia si suse modifica
en el procedimiento.

Opcional (Optional) El parámetro es opcional. Si un parámetro es opcional, todos los que


vengan detrás también deben serlo, y hay que indicarlo así con la expresión Optional para cada
uno de ellos. El parámetro que da valor a la propiedad no puede ser opcional.

Array de parámetros (ParamArray) Indica que es una matriz de parámetros.

No se puede llamar a un procedimiento Property Let dentro de otro procedimiento Property,


Sub o Function.

Property Get (Instrucción)


Declara el nombre, los argumentos y el código que componen el cuerpo de un procedimiento
Property, y obtiene el valor de una propiedad.

LSB Visual Basic Guía del Estudiante Cap.19 Pág. 6


Sintaxis

[Public | Private | Friend] [Static] Property Get NombreDelProcedimiento (argumentos) As


tipo
instrucciones
nombreDelProcedimiento = expresión
Exit Property
instrucciones
nombreDelProcedimiento = expresión
End Property

El ámbito y la forma de pasar los parámetros son idénticas a las de Property Let

Comenzando el ejercicio práctico


En el ejercicio que ilustra este capítulo vamos a hacer un control para una caja registradora (No
olviden que es un ejemplo) Ese control va a recibir el código de barras de un producto (se podrá
teclear directamente o leerlo mediante un escáner) y analizará el número de control para
comprobar que es correcto. El control se encargará de buscar en una base de datos la
descripción del producto, el precio y las unidades de oferta. Para ciertos productos aplicará un
incremento de precio en horas nocturnas y para otros un descuento en horas de mañana. Por lo
tanto, debe tomar la hora del sistema y fijar el Incremento / Descuento en razón de la hora. La
interfaz gráfica pensada es la siguiente:

Fig. 19.6 Interfaz gráfica del control a desarrollar

Veamos que propiedades debe tener este control. Aparte de la ya citada, ColorDelFondo,
vamos a ponerle:

In_Cod_Barras. De tipo texto, para poder pasarle por programa el código de barras de un
producto.

In_Unidades. Numérica double para que permita decimales, y permitir así vender productos “al
peso”

In_DeshabilitaIncr_Desc, booleana, que si es true, deshabilitará la operación de incrementar o


rebajar el precio en función de la hora.

Out_Descripcion, que será una cadena de caracteres con el texto de la Descripción.

Out_Precio_Total, numérico double con el precio total de las unidades vendidas de ese
producto

(Hemos tenido el detalle de que las variables que contienen datos que entran en el control
comienzan por In_ y las que salen del control comienzan por Out_ Esto no significa que sean
solo de escritura o de lectura)

Se introducen estas propiedades tal como se explicó más atrás. En la Fig 19.7 puede verse el
cuadro de propiedades del control, con todas estas propiedades ya metidas. Ese cuadro, como
sabemos, aparece pulsando F4 estando seleccionado el control. Ese control está sobre un
formulario de prueba que aun no sabemos como ponerlo, pero se explicará en breve. Este

LSB Visual Basic Guía del Estudiante Cap.19 Pág. 7


cuadro es el típico de todos los controles, pero estamos acostumbrados a que, haciendo clic
con el botón derecho del ratón, aparezca un cuadro de
diálogo donde podemos introducir las propiedades. Y eso,
no sabemos todavía como hacerlo.

Eso se hace mediante una página de propiedades.


Reconozco que es complicado, y pese a mi costumbre de
no usar asistentes para ahorrar trabajo, en este caso no
me queda más remedio que recurrir a ellos.

Vayamos al UserControl y seleccionándolo, pulsamos F4


para sacar sus propiedades. Vayamos a su propiedad
PropertyPages (recuerde que estamos en las propiedades
del UserControl) Sitúese en esa propiedad y haga clic
sobre el botón que aparece a la derecha. Le aparecerá
un cuadro como el de la Fig. 19.8. En ese cuadro se nos
pide que señalemos las páginas que deseamos que tenga
el cuadro de propiedades. En el caso del ejemplo se han
seleccionado una página de propiedades vacía
(PaginaPropiedades1, se le ha cambiado el nombre que
aparecía por defecto), la página donde se elige la fuente
(StandardFont) y la página donde se elige el color
(StandarColor) Al pulsar Aceptar la propiedad
PropertyPages del serControl tiene 3 Pages

Vayamos ahora al menú de Visual Basic, en Proyecto,


elegimos Agregar Página de Propiedades. Y es ahí donde
nos invita a poner una página en blanco o a utilizar un
asistente. Posiblemente un programador con mucha
experiencia elegiría hacerla a mano, pero los controles
ActiveX no se hacen todos los días y vamos a recurrir al
asistente para que nos evite tener que trabajar más, y
sobre todo, tener que estudiar mucho más.
Fig. 19.7 Propiedades del control

Fig. 19.8 Cuadro para


conectar páginas de
propiedades

Al elegir el asistente,
aparece un cuadro donde
nos muestra las
propiedades que hemos
metido en nuestro control.
En el caso del ejemplo,
esas propiedades son:

ColorDeFondo
In_Cod_Barras
In_Unidades
In_DeshabilitarIncr_Desc
Out_Descripcion
Out_Precio_Total

El asistente nos pide que elijamos las propiedades que queremos que aparezcan en el cuadro
de dialogo de propiedades. Se las ponemos todas. Vamos aceptando todos los pasos, hasta
que hacemos clic en el botón Finalizar. El cuadro de dialogo de propiedades ya está creado.

LSB Visual Basic Guía del Estudiante Cap.19 Pág. 8


Vamos al formulario de prueba y hacemos clic con el botón derecho sobre el control. Aparece
por fin el cuadro de dialogo de propiedades.

Fig. 19.9 Cuadro de dialogo de propiedades.

Puede ahora incluir en ese cuadro cualquier control, como si se tratase de un formulario. Queda
a merced de su capacidad artística rematarlo de forma adecuada

Fig. 19.10 Cuadro de propiedades rematado

Puede observar ahora que en la ventana de proyecto aparece ahora otro componente: la página
de propiedades.

La página de propiedades (Property Page) tiene las casi todas las propiedades, métodos y
eventos de un formulario. No vamos a extendernos en su estudio exhaustivo, ya que sería
salirse del objetivo del curso.

LSB Visual Basic Guía del Estudiante Cap.19 Pág. 9


Solamente falta introducir el código adecuado en los procedimientos del UserControl. Por
ejemplo, para comprobar que el código de barras es correcto, creamos un procedimiento
llamado CompruebaCodigo. Llamaremos a este procedimiento cuando se introduzca el código
de barras completo. (Emplearemos solamente EAN-13 para no complicar el ejemplo). El
código del procedimiento que comprueba el código de barras puede verlo en el ejemplo, y es
solamente aplicar la definición del dígito de control de EAN-13. A ese procedimiento le hemos
llamado CompruebaCodigo y es un procedimiento creado por nosotros dentro del UserControl.

Prueba del nuevo control


Para comprobar el nuevo control es necesario ponerlo en un proyecto. Mejor dicho, en un
formulario. Basta con introducir un formulario de la forma habitual: Proyecto | Agregar
Formulario. Verá que aparece una nueva carpeta en el proyecto con un formulario. Para
introducir el nuevo control en el formulario basta con que lo coja de la caja de herramientas y lo
lleve al formulario como lo haría con cualquier otro control. Eso sí, debe cerrar
previamente el UserControl porque si no ese icono que presenta el nuevo está
deshabilitado.

Puede probar todas las características del nuevo control. De cualquier forma no se fíe, y realice
la comprobación final en un proyecto completamente independiente, una vez que ya haya
compilado el control.

Icono para presentar al nuevo control


Es posible que no quiera que su control se vea en la caja de herramientas con el icono de la
figura anterior. Este es el icono por defecto. Si desea cambiarlo debe introducir una imagen
BitMap en la propiedad del UserControl ToolBoxBitMap. La imagen deberá estar en un
formato bastante grande (sin pasarse) para que se vea claro, ya que si se pone pequeña, el
icono que aparece en la caja de herramientas queda bastante feo.

Enlazar el nuevo control a una base de datos mediante el control data.


Ya vamos avanzando en lo que podemos hacer sobre un nuevo control. Ahora vamos a
enlazarlo a una base de datos a través del control Data.

Para ver como se hace esto vamos a hacer un ejemplo, siguiéndolo paso a paso.

LSB Visual Basic Guía del Estudiante Cap.19 Pág. 10


Propiedades del UserControl (Se enumeran solamente aquellas que sean específicas del
UserControl o que aconsejen una explicación especial)

Propiedad AccessKeys
Devuelve o establece una cadena que contiene las teclas que funcionarán como teclas de
acceso (o teclas aceleradoras) del control. La propiedad AccessKeys es una cadena que
contiene todas las teclas de acceso del control. Por ejemplo, para establecer las letras S e Y
como teclas de acceso, la propiedad AccessKeys se establecería a "sy". Cuando un usuario
presiona una de las teclas de acceso junto con la tecla ALT, el control recibirá el enfoque
(según el valor de la propiedad ForwardFocus). Las teclas de acceso de los controles
componentes se incluyen implícitamente como teclas de acceso, aunque no aparezcan en la
propiedad AccessKeys.

ActiveControl (Propiedad)
Devuelve el control que tiene el enfoque.

Propiedad AutoRedraw
El UserControl acepta métodos gráficos. La propiedad AutoRedraw (True/False) hace lo mismo
que en el Formulario.

Propiedad BackStyle
Establece el tipo de fondo del UserControl (Opaco / Invisible)

Los valores aceptados son:


Opaque 1 El fondo será opaco
Invisible 2 El fondo es transparente, pero solamente si la propiedad
Windowless esta a True

Propiedad ClipBehavior
Sirve para determinar la zona donde se verán los métodos gráficos, cuando está transparente.
Véase en la ayuda.

Propiedad ContainedControls
Devuelve la colección de controles constituyentes y los que se hayan podido añadir en tiempo
de ejecución. Funciona de forma similar a la propiedad Controls de un formulario.

Propiedad ContainerHWnd
Devuelve el controlador de la ventana (hWnd) del contenedor de un UserControl. Se usa para
programar con APIS.

Propiedad DataMembers
Devuelve una referencia a la colección DataMembers.
Un proveedor de datos puede proporcionar múltiples conjuntos de datos a los que un receptor
puede enlazar. Cada conjunto de datos se llama "miembro de datos" y está identificado
mediante una cadena única.
La colección DataMembers contiene los nombres de todos los miembros de datos disponibles
para el receptor de datos.

LSB Visual Basic Guía del Estudiante Cap.19 Pág. 11


Propiedad EditAtDesignTime
Establece si un control puede activarse en el tiempo de diseño del programador. Si es True el
control puede activarse en tiempo de diseño y se comportará como lo haría en tiempo de
ejecución.

EventsFrozen (Propiedad)
Devuelve un valor que indica si el contenedor está pasando por alto los eventos
desencadenados por el control. La propiedad EventsFrozen no está disponible en tiempo de
diseño del control y es de sólo lectura en tiempo de ejecución.
Cuando la propiedad EventsFrozen es True, el contenedor pasa por alto todos los eventos
desencadenados por el control. Si el control necesita producir un evento que no se puede
perder, tiene que dejarlo en la cola hasta que EventsFrozen sea False.

Extender (Propiedad)
Devuelve, para este control, el objeto Extender que almacena las propiedades del control
mantenidas por el contenedor. La propiedad Extender no está disponible en tiempo de diseño
del control y es de sólo lectura en tiempo de ejecución.

Propiedad MaskColor
Devuelve o establece el color que determina la región transparente del mapa de bits asignado a
la propiedad MaskPicture de un objeto UserControl cuya propiedad BackStyle está
establecida a 0 (Transparente).

Sintaxis MiUserControl.MaskColor = color

Cuando se asigna a un mapa de bits la propiedad MaskPicture de un UserControl cuya


propiedad BackStyle está establecida a 0 (Transparente), el control se vuelve transparente en
cualquier lugar en que esté cubierto por áreas del mapa de bits que cumplan la propiedad
MaskColor.
Los eventos del mouse que ocurren sobre áreas transparentes las reciben el contenedor o los
controles que, de otro modo, estarían cubiertos por el UserControl.

MaskPicture (Propiedad, Objeto UserControl)


Devuelve o establece el mapa de bits que, combinado con la propiedad MaskColor, determina
las regiones transparentes y visibles de un objeto UserControl cuya propiedad BackStyle está
establecida a 0 (Transparente).

Sintaxis MiUserControl.MaskPicture = imagen

Importante Esta característica sólo es soportada con mapas de bits de tipo imagen, como GIF,
JPEG y DIB. No es soportada con iconos, cursores o metaarchivos de Windows.

Propiedad ToolBoxBitMap

Establece la imagen con la que se va a representar el nuevo control en la caja de herramientas.


Debe ser una imagen BitMap que habremos guardado previamente en el disco.

LSB Visual Basic Guía del Estudiante Cap.19 Pág. 12


Visual Basic - Guía del Estudiante Cap. 20
APLICACIONES CLIENTE SERVIDOR
COMUNICACIÓN PUERTO SERIE: EL CONTROL MSCOMM

(Capítulo inacabado. ¿Algún estudiante quiere colaborar a su terminación?)

Hasta ahora hemos visto aplicaciones que pueden utilizarse por sí solas. Pueden acceder a
bases de datos que estén en el mismo ordenador que la aplicación o en otro, unido mediante
una red de área local. La conexión a las bases de datos a las que accede se realiza, bien
indicándole la dirección y carpeta (\\MiServidor\BasesdeDatos\MiBase.Mdb) o bien “mapeando”
esa dirección (crear una unidad de disco que contienen esa dirección). De esta forma
podemos acceder a una base de datos instalada en un equipo remoto y la aplicación debe
funcionar perfectamente, aunque al abrir o leer la base de datos origine un tráfico elevado por
la red de área local.

Con esta configuración podemos tener problemas de lentitud, sobre todo si la red es lenta y si
hay muchos usuarios trabajando con esa aplicación en distintos ordenadores, accediendo
todos ellos a través de la red a un servidor que contienen la base de datos. Esta lentitud se
incrementaría en una gran escala si la red a utilizar fuese Internet mediante una conexión lenta.

Pero lo que más se notaría sería la ocupación de los recursos de la red durante las consultas a
esa base de datos. Dependiendo de cómo se crease el recordset, podría darse el caso de
transmitir por la red todos los datos de la base de datos para que nuestra aplicación utilice
únicamente los datos correspondientes a un registro. Pensando en una aplicación bancaria,
por ejemplo la petición de saldo de una cuenta desde un cajero automático, los únicos datos
relevantes de esa operación serán el número de cuenta corriente, un código para indicar que lo
que se desea es el saldo, y como datos de retorno, el número de esa cuenta, el saldo actual
disponible y quizás un número de comprobación (Checksum) para comprobar que no ha
existido error en la comunicación. De nada nos serviría en el cajero conocer el estado de
cantidades retenidas, operaciones pendientes, etc.

Si en ese ejemplo del cajero creásemos un objeto Database, un recordset, leyésemos todos los
datos del recordset y luego diésemos la orden de cerrarlo, estaríamos enviando información
innecesaria a través de la red, con el coste de tiempo y ocupación que ello representa.

Casi llegamos a demostrar con esta introducción que sería más conveniente hacer una
aplicación que tuviese dos partes: una, residente en el puesto de operación, (que llamaremos
aplicación cliente) que fuese capaz de enviar datos solicitando información a otra aplicación,
instalada en el servidor donde está la base de datos. Esta segunda aplicación, que llamaremos
aplicación servidor, abrirá la base, creará los recordsets necesarios, filtrará la información,
realizará con ella operaciones matemáticas, y una vez concluido todo el proceso, enviará a la
aplicación cliente los datos estrictamente necesarios. Obviamente se necesita que ambas
aplicaciones sean capaces de entenderse entre sí, es decir, que tengan un protocolo de
comunicación entre ellas previamente definido. Esto es lo que se denomina una aplicación
cliente – servidor.

La aplicación cliente – servidor más popular es el navegador de Internet. Esta aplicación está
formada por una aplicación cliente (Navegador IEXplore, NetScape, etc) y una aplicación
servidor (Internet Information Server IIS, Apache, etc). El protocolo para que se comuniquen
entre ellas es el protocolo Http o el Ftp. Estos protocolos al ser públicos, permiten a cualquier
empresa hacer su propia aplicación cliente o servidor.

No es nuestro deseo llegar a tanto. El navegador de Internet es una aplicación cliente–servidor


que sobrepasa cualquier proyecto que podamos imaginar para realizarlo por medio de
programación en VB. Cualquier navegador de Internet comercial lleva asociadas una serie de
funciones, muchas de ellas transparentes para el usuario, que sería imposible crear una
aplicación de este calibre, sobre todo como ejemplo de un curso de VB. Pensemos en una

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 1


aplicación más sencilla, que nos permita conocer como funcionan las aplicaciones cliente –
servidor, y sirva además para algo útil.

Esa aplicación no puede ser otra que una guía telefónica, (versión novísima del Listatel) cuya
base de datos está en un servidor conectado a Internet, al que se podrá acceder desde un
número ilimitado de puestos cliente. En la base de datos del servidor, en un conjunto de tablas,
figurarán los nombres, números de teléfono, despacho, etc. de una serie de personas, y el
organigrama de esas personas dentro de la organización. Estas tablas serán estáticas, es
decir, tendrán datos que solamente se actualizarán cuando exista un cambio en esas personas,
pero no variarán durante la ejecución del programa. En otra tabla, esta dinámica, tendremos el
registro de los usuarios que están conectados en ese momento al servicio. Así podremos saber
si un usuario está presente y de esta forma conocer un dato importante para otro servicio que
va a tener este programa: su dirección IP actual. Sabiendo que está conectado y con su
dirección IP podremos enviarle mensajes directamente. Creo que ya vemos que se trata de una
agenda telefónica que lleva incorporado un servicio de mensajería. El servicio de mensajería
enviará mensajes con texto plano o RTF y puede llevar ficheros anexados. A esta agenda, y a
su protocolo de comunicación le vamos a denominar SML. No se preocupe de no conocer las
siglas. Al protocolo SMTP tampoco lo conocían en el momento de su creación.

Una aplicación cliente puede comportarse como aplicación servidor de otra aplicación, incluso
de sí misma. Este es el caso de la aplicación cliente del SML. Cuando vamos a pedir la
información de un abonado telefónico al servidor, el cliente se comporta como tal. Sin embargo
cuando otro usuario de SML nos envía un mensaje, es nuestra aplicación la que realiza las
funciones de servidor. Verá esto con mucha más claridad cuando comencemos el ejemplo.

Toda aplicación cliente - servidor debe tener un sistema de comunicación entre la aplicación
cliente y la aplicación servidor. Parece que la comunicación que ha de tener es a través de una
red IP (Red de Area Local, Red Privada Virtual, Internet) pero puede ser cualquier otro sistema
de comunicación entre ordenadores. Sin ir más lejos, a través del puerto de comunicación serie
COM-1 ó COM-2. A efectos de los programas de la aplicación cliente o servidor solamente
variará en la forma en la que reciban y transmitan los datos. En nuestro ejemplo vamos a
utilizar la comunicación a través de una red IP, usando el control Winsock ya estudiado. Tanto
la aplicación cliente como la aplicación servidor deberán tener un Winsock. Como en nuestro
caso, según explicamos más atrás, la aplicación cliente se convierte en aplicación servidor para
recibir mensajes, ésta deberá tener dos Winsocks, uno para la función cliente, y otro para la
función servidor.

Cuando se diseña una aplicación cliente – servidor hay que comenzar pensando en las
funciones que va a realizar y sobre esas funciones comenzar a escribir el protocolo de
comunicación. No es fácil tener terminado el protocolo de comunicación antes de escribir la
primera línea de código del programa. Según se van concretando cada una de las acciones
que debe realizar vemos que es necesario introducir nuevos códigos de operación en nuestro
protocolo. No se preocupe que eso no es improvisar. Pero sí es muy importante tener las
cosas claras desde el principio y saber que es lo que va a hacer nuestra aplicación para de
esta forma poder saber dar respuesta correcta a cada uno de los dos programas. Y para tener
las cosas claras, el autor recomienda que el protocolo de comunicación se establezca antes de
comenzar a escribir el código en tanto se pueda. Y que se escriba en un documento en el
propio ordenador o mejor aún, en una base de datos u hoja de cálculo, que nos permita
ordenar las órdenes y avisos de nuestra aplicación para evitar de esta forma cualquier
repetición involuntaria.

Es muy importante a la hora de pensar el protocolo de comunicación que este no pueda inducir
a error al programa. Si el programa tiene como función la transmisión de mensajes (Tal como
es nuestro caso) los mensajes no pueden estar limitados ni en su longitud ni en su contenido
por el formato del protocolo de comunicaciones. Se entiende mejor esto analizando el protocolo
del SML (fruto únicamente de la imaginación del autor y no sujeto a normas ni
recomendaciones internacionales de ningún tipo)

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 2


Protocolo de comunicación de la aplicación SML.

(Vea el ANEXO 1 Protocolo de comunicación SML)

La comunicación entre ambas aplicaciones se establece mediante palabras en ASCI que


indican una operación. A estas palabras las denominamos Acrónimos. Las operaciones
pueden ser órdenes o avisos. Son órdenes aquellas comunicaciones del cliente que
desencadenan una operación en el servidor. Son avisos aquellas respuestas del servidor para
enviarle datos o comunicar algo al cliente. Cada orden o aviso, puede llevar uno o varios
parámetros. Los parámetros contienen la información necesaria para que la operación que se
va a realizar por esa orden o aviso pueda llevarse a cabo. En esta aplicación SML los
acrónimos todos son de 3 caracteres, utilizando los signos < > como delimitadores del
acrónimo. Si el acrónimo lleva parámetros, la separación entre los tres caracteres y el
parámetro o parámetros es la barra /

Volvamos a lo comentado anteriormente respecto a la limitación del contenido de un mensaje.


Si el mensaje contiene un carácter <, > ó / puede que el programa se confunda y piense que
ese carácter forma parte de un acrónimo. Para evitar cualquier confusión, si uno de estos
caracteres forma parte de un texto, se le antepondrá el signo &. De esta forma la recepción de
la pareja de caracteres &<, &> ó &/ significa que no son parte de un acrónimo sino texto.
Observe ahora que ese mismo problema lo vamos a tener con el carácter &. Si queremos
enviar ese carácter, sin que haya posibilidad de error pensando que se trata del carácter &
antepuesto a cualquiera de los signos anteriores, deberemos poner delante de él también el
signo &. Así, && significa que se está transmitiendo el signo &.

Es obvio pensar que esas tres combinaciones no pueden formar parte de ningún acrónimo.
Pero como los acrónimos los definimos nosotros, basta con hacer que ninguno contenga esas
secuencias de caracteres.

Preocúpese de estos detalles que son los realmente importantes. Verá cuando se ponga a
escribir código que siempre ha de faltar algo en el protocolo de comunicación. No se preocupe
por tener que ir rectificándolo. Eso sí, mantenga siempre actualizado el documento o base de
datos con el protocolo, explicando debidamente cada una de sus partes, los parámetros que
lleva y la función que realiza. Es documento indispensable a la hora de distribuir la aplicación.

A modo de recordatorio, los protocolos de comunicación de las aplicaciones cliente – servidor


para Internet se encuentran en las RFCs, (Request For Coments) son públicas, y han tardado
en desarrollarse varios años a base de continuas aportaciones y correcciones por parte de sus
creadores de todo el mundo mundial. Basta con que teclee RFC en un buen buscador y le
llevará a muchas páginas donde puede ver todas las recomendaciones para todos los servicios
de Internet.

El protocolo de comunicación debe hacerse preferentemente en ASCII puro y caracteres que


tengan representación física. Esto nos permite depurar el programa analizando la
comunicación mediante un programa externo y debidamente probado. Utilizar caracteres sin
representación ASCII lo único que puede hacerle es complicarle la vida a Ud. y a quien analice
su aplicación. Cuando se envíe una cifra, hágalo en decimal o en hexadecimal. Evite en lo
posible enviar cifras sustituyendo su valor por su carácter equivalente. La mayoría de los
caracteres no los va a poder representar y tendrá serios problemas para depurar su programa.
Esto es especialmente importante con el cheksum de un mensaje, por ejemplo. Le recomiendo
que use preferentemente numeración Hexadecimal.

Un buen programador nunca oculta el protocolo de comunicación. Esto permite que otros
mejoren su aplicación. Sólo los programadores mediocres temen que se les plagie. Y por
supuesto, nadie debería aceptar una aplicación cliente – servidor si el programador no
suministra ese protocolo.

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 3


Aspectos que debe tener siempre en cuenta cuando diseñe una
aplicación cliente – servidor.
Si como es normal, utiliza una red IP para la transmisión de información entre ambas
aplicaciones, deberá poner un Winsock en la aplicación cliente, que deberá conocer la
dirección IP o el DNS de la aplicación servidor, y el puerto en el que está escuchando. En el
servidor deberá poner un Winsock que estará siempre a la escucha en el puerto determinado
para la aplicación, y atenderá a todas las llamadas que reciba creando una instancia de ese
Winsock. Creará una instancia para cada comunicación entrante desde los clientes. La
comunicación en el servidor se mantendrá abierta hasta que el cliente la cierre. Solamente en
circunstancias excepcionales, cerrará la comunicación el servidor. Por ejemplo, en aquellos
casos en los que pase un tiempo predeterminado sin recibir ni enviar ningún dato al cliente.
Para eso se utilizará una tecnología muy sencilla, denominada Watch Dog consistente en un
contador que se pone a cero cada vez que se recibe o se envían datos al cliente. Ese contador
incrementa su cuenta en una unidad cada cierto tiempo. Si llega a un número predeterminado,
prueba evidente de que ha pasado un tiempo sin que reciba ni envíe información, cierra la
conexión del Winsock asociado. De cualquier forma hay que tener cuidado y pensar muy bien
lo que se hace antes de cerrar la comunicación desde el servidor.

El programa cliente debe conocer el número IP o dirección DNS del servidor. Pero el servidor
no tiene porque conocer la dirección ni DNS del cliente, ya que debe ser el cliente el que inicie
siempre la comunicación.

Al cliente nunca se le debe forzar el puerto en el que emite (Propiedad LocalPort del Winsock).
El servidor contestará siempre al cliente usando la conexión abierta por éste, es decir, usando
la instancia de su Winsock correspondiente a la conexión realizada para ese cliente)

Normalmente el servidor no podrá comunicar directamente con el cliente, ya que el cliente no


está a la escucha. Solamente en algunas aplicaciones se le dota al cliente de otro Winsock
para que sea este segundo Winsock quien esté a la escucha de una posible llamada del
servidor. Esto se emplea para dar una batida por todos los clientes (Hacer Pooling) y ver los
clientes que están conectados en este momento. Solamente lo he visto en algunas
aplicaciones de seguridad. Generalmente este pooling se sustituye por llamadas periódicas
desde cada cliente para indicarle al servidor que están activos.

La comunicación entre cliente y servidor debe ser siempre TCP. El uso de UDP simplifica
mucho las comunicaciones, pero no sirve para salir a Internet, donde las tramas UDP son
generalmente eliminadas por los servidores. Vale más trabajar un poco más el código y trabajar
con comunicaciones seguras aunque sea en una red de área local que garantice la llegada de
UDP.

Los paquetes broadcast deben evitarse también. Solamente deben usarse en configuraciones
donde no se conocen las direcciones de los servidores. Esto ocurre cuando la red tiene
asignación dinámica de direcciones. (Puede ocurrirle si usa una red VSAT) En cualquier caso,
los paquetes broadcast deben evitarse en lo posible. Los servidores de Internet los eliminan
automáticamente.

Posiblemente haya más recomendaciones relativas a la comunicación. Veamos ahora otras


recomendaciones acerca del código y de la funcionalidad.

Dado que la aplicación cliente y la aplicación servidor son completamente independientes, es


muy fácil realizar modificaciones en una de ellas, sobre todo en el servidor, sin que el cliente se
entere. Basta para ello mantener invariable el protocolo de comunicación.

Pero puede llegar el caso en el que al servidor se le hayan introducido mejoras que puede
aportar al cliente si este es capaz de reconocer un nuevo protocolo. Estamos en el caso de un
servidor que debe atender a dos versiones distintas de cliente. Si el cliente tiene la versión
mejorada, usará con él un protocolo de comunicación que permita las nuevas prestaciones. Si
el cliente tiene la versión más antigua, deberá seguir usando con él el protocolo anterior.

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 4


Esto nos lleva a que el cliente siempre debe indicar al servidor su versión. Esto no ocupa unos
recursos excesivos y puede ser muy útil cuando prevemos introducir una modificación. Esta
práctica puede incluso servir para conocer aquellos clientes a los que hay que realizar el
cambio de versión y enviarles una nueva. En el ejemplo de este curso, el cliente comunica al
servidor su versión en el acto de conectarse mediante el acrónimo <VER>.

El servidor también debería enviar su versión al cliente. No está previsto en la aplicación SML
pero confieso que no sobraría que al identificarse el cliente y devolverle el servidor la
conformidad del registro, le devolviese también la versión del servidor. ¿Se da cuenta que
según se avanza en la definición del protocolo aparecen nuevas necesidades?

La aplicación cliente debe mostrar de forma clara al usuario el estado de conexión o


desconexión con el servidor. Y a ser posible, que indique la causa de la no conexión (Fallo en
la RAL, fallo en el servidor) Esta información se obtienen de forma muy sencilla analizando los
errores generados en el Winsock a la hora de realizar la conexión.

Cuando utilice el puerto COM para la comunicación, bien sea directamente o a través de
módem, debe indicar claramente al usuario el estado de esa conexión, analizando la señal
DSR (esta señal está activa cuando el módem está conectado, y en caso de comunicación
directa, cuando se use, el Host debe poner a 1 esta señal para poder trabajar). Recuerde que
la comunicación por el puerto COM es asíncrona respecto a la ejecución del programa.

En el ejemplo de aplicación cliente – servidor se han ensayado también los controles


avanzados de Visual Basic (Capitulo 16). La aplicación tal como se dijo es una guía telefónica,
que presenta en un TreeView el organigrama del Organismo o empresa a la que pertenece la
guía. Esto facilita la búsqueda de una persona, haciéndolo por departamento. La guía permite
también buscar por nombre, primer apellido, segundo apellido o combinación de ambos. Una
vez encontrada la persona, se cubren todos los datos de la misma, para presentarlos en la
solapa de la guía propiamente dicha, y el dato de su alias (dato que define de forma única a
cada usuario) aparece en la dirección de correo para poder enviarle un mensaje. Para hacer
una práctica con el puerto de comunicaciones COM-1 ó COM-2 utilizaremos un módem,
conectado al PC a través de uno de estos puertos, para marcar el número telefónico.

Todas las operaciones de búsqueda de datos las haremos mediante consultas a la base de
datos que está en el servidor. Las consultas se realizarán siguiendo el protocolo de
comunicaciones. El organigrama se guardará en el cliente, en una base de datos, para evitar
en lo posible el envío desde el servidor. La razón para esto es que el organigrama puede ser
muy extenso, y no va a variar muy a menudo. Como esta información habría que enviarla nada
más conectarse el cliente, y como puede ser bastante amplia, esto podría originar un tráfico
intenso por la red, que es justamente lo que queríamos evitar. Solamente se va a enviar
cuando haya cambiado. ¿Cómo sabe el cliente que ha cambiado?. ¿Cómo sabe el servidor que
el cliente tiene ya la información actualizada? La idea más sencilla para conocerlo es que el
cliente envíe cada vez que se registra (al comienzo de la conexión) el nombre de la revisión del
organigrama que tienen. El nombre puede ser cualquiera. Lo que hace el servidor por defecto
para poner el nombre a la revisión es combinar una cadena de texto con el nombre de la
organización seguido de la fecha (día/mes/año) en la que se realiza la revisión. De esta forma
es imposible que haya dos fichero con el mismo nombre. Al recibir ese nombre el servidor, si
es igual al de la última revisión, le devuelve un OK. Si no es igual, le devuelve una instrucción
para que el cliente solicite al servidor que le envíe la nueva revisión. El cliente la solicita y el
servidor se la envía. Y al recibirla, el cliente reemplaza el contenido de la base de datos por los
nuevos valores recibidos.

Y razonando los procedimientos de esta misma forma, vamos completando el mecanismo de


comunicación entre cliente y servidor, y paralelamente creando el protocolo de comunicación.
Por eso es muy probable que el protocolo de comunicación no esté acabado hasta que esté
acabada la aplicación.

Al día de hoy (30 de Octubre de 2002) no está terminada la aplicación. Posiblemente no lo esté
nunca porque sea una aplicación en continua ampliación. Esto es lo bonito de los programas
ejemplo de los cursos de visual basic.

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 5


LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 6
ANEXO 1
SERVIDOR DE BASES DE DATOS Y MENSAJERIA LISTATEL (SML)

PROTOCOLO DE COMUNICACIÓN CLIENTE – SERVIDOR

La comunicación entre cliente y servidor se realizará mediante el protocolo descrito más


adelante, a través de cualquier medio de comunicación. Generalmente será comunicación a
través de red IP, pero esto no debe impedir que los clientes se puedan conectar al servidor a
través de otros medios de comunicación, como puede ser un módem telefónico o un enlace vía
satélite.

En cualquier caso, el contenido de las órdenes y comandos de este protocolo será siempre en
ASCII, con caracteres alfanuméricos que permitan ver perfectamente el tráfico entre ambos
interlocutores. El hecho de utilizar solamente caracteres legibles asegura igualmente la
comunicación a través de cualquier medio de telecomunicación, incluyendo dispositivos de
cifrado on-line colocados entre cliente y servidor.

La comunicación puede iniciarse tanto en el servidor como en cualquiera de los clientes. Una
comunicación puede estar compuesta de:

Ordenes
Respuestas
Confirmaciones
Avisos

Ordenes: Son aquellas partes de la comunicación que inician una operación en el equipo
colateral.

Respuestas. Son siempre respuesta a una orden, y contendrán el resultado de la operación


generada por la orden, o en su defecto, la notificación de que esa orden no ha sido ejecutada o
que dio resultado nulo.

Confirmaciones: Son el reconocimiento de recepción de una comunicación. Pueden


emplearse tanto para responder a un aviso como para confirmar que una orden se ha recibido,
y que está siendo tratada. También pueden existir confirmaciones para avisar que una orden o
una respuesta no ha llegado en un tiempo determinado.

Avisos: Son aquellas comunicaciones que no ejecutan ninguna acción en el colateral, pero
informan de algo. Por ejemplo, servidor fuera de servicio temporalmente, servidor restablecido.
Pueden ser individuales, en cuyo caso generarán normalmente una confirmación, o broadcast,
en cuyo caso no generarán confirmación.

Formato de las tramas de comunicaciones.

La trama de una comunicación estará compuesta de unos acrónimos que indicarán la orden,
respuesta, confirmación o aviso que envían, dirección IP, nombre de la máquina o nombre del
servidor que envía, dirección IP, nombre de la máquina o nombre del servidor destino, datos,
cheksum de la trama y acrónimo de fin de trama. Cada uno de estos componentes irá metido
entra los símbolos < > y su longitud puede ser variable. Cuando se envíe información, esta se
colocará detrás del acrónimo que la define, separada por la barra /.

Ejemplos:

<SAT> Servidor Atención. Inicia una sesión de un cliente con el servidor.


<IPO/10.3.22.119> Dirección IP del equipo origen
<IPD/217.126.179.96> Dirección IP del equipo destino
<QRY/Select * From Agenda_Personal Where Apellido1 Like ‘FERN%’>

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 7


Si hubiese que emplear los símbolos /, &, < o > como símbolos de la información, deberá
anteponerse a cada uno de ellos el símbolo &.
Por ejemplo:

<QRY/Select * From Agenda_Personal Where Edad &> 25>

El cheksum será el resultado de realizar la función XOR sobre todos los caracteres de los
componentes de la trama, exceptuando los correspondientes precisamente a este cheksum y al
fin de trama. El cheksum se indicará en decimal, con el acrónimo CHK. Por ejemplo,
<CHK/235>

El acrónimo de fin de trama será <EOT>

El orden de los componentes de una trama no debe ser estricto, si bien debe ir en primer lugar
el acrónimo que inicie la sesión de comunicaciones, en penúltimo lugar el cheksum, y en
último lugar el <EOT>

Una trama puede contener varias ordenes siempre y cuando estas sean congruentes.

Cuadro con los acrónimos usados en las tramas de comunicación.

<RHC> Remote Host Conectado. Lo devuelve el servidor o un cliente cuando otro


equipo se conecta a él.
<SAT> Servidor ATención. Inicia una sesión de comunicación desde el cliente al
servidor.
<CAT> Cliente Atención. Inicia una sesión de comunicación desde una máquina
(Servidor o cliente) a una máquina cliente.
<LIC> Login Cliente. Indica que el cliente desea hacer Login en ese servidor. Pasa
como parámetros el alias y el password (en claro o cifrado) del cliente.
<LOC> LogOut de cliente. Ese cliente quiere hacer LogOut de ese servidor. Pasa como
parámetros el alias y el password (en claro o cifrado) del cliente.
<ALC> Alias de cliente. Llevará como dato el alias de ese cliente.
<ALS> Alias de servidor. Llevará como dato el alias de ese servidor.
<PWC> Password del cliente. Lleva como parámetro el password (en claro o
encriptado) del cliente
<IPO> IP de la máquina origen. Llevará como dato el número IP de la máquina origen
de la trama.
<IPD> IP de la máquina destino. Llevará como dato el número IP de la máquina
destino.
<NMO> Nombre máquina origen. Llevará como dato el nombre de la máquina dentro de
la red.
<NMD> Nombre máquina destino. Llevará como dato el nombre de la máquina dentro
de la red.
<NSO> Nombre Servidor origen. Llevará como dato el nombre del servidor origen. Este
nombre de servidor será el nombre de un programa servidor, no el nombre de
la máquina donde se alberga el programa servidor.
<NSD> Nombre servidor destino. Igual que el anterior.
<QRY> Consulta a una base de datos. Llevará como datos la consulta completa en
SQL
<QPR> Consulta ya preprogramada en el servidor. Lleva como parámetro el nombre de
esa consulta, y los datos que necesite esa consulta para su ejecución.
<RQY> Resultado de la consulta a la base de datos. Llevará como datos el resultado
de esa consulta. Si el resultado genera varios registros, cada uno de ellos irá
entre brackets ( [ ] )
<QIP> Consulta de los datos del correo de un usuario. Envía como parámetro el Alias
del usuario del que se quieren conocer los datos. Devuelve los datos con el
acrónimo <QIP>

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 8


<QIR> Consulta los datos del correo de un usuario pasándole en este caso como
parámetro la dirección de correo SML. Devuelve los datos con el acrónimo
<QIP>
<QIS> Consulta los datos del correo de un usuario pasándole la dirección de correo
SMTP. Devuelve los datos con el acrónimo <QIP>
<ECO> Orden de envío del mismo dato en la respuesta a esa orden. Se envía, por
ejemplo, en una consulta a la base de datos, para que el cliente ubique la
respuesta a esa consulta en un sitio determinado.
<OCE> Se emplea para devolver el mismo dato recibido con <ECO>
<CRY> Inicia o finaliza una operación de cifrado de datos. Lleva como parámetro INI
para iniciar y FIN para terminar. En el caso de iniciar, lleva uno o dos
parámetros más, el número de clave o el nombre de un usuario con clave
asociada. Puede llevar dos nombres de usuario en caso que se cifre
doblemente con la clave privada del remitente y la clave publica del destino, en
cuyo caso se envían como dos parámetros
<CRY/INI/PUB_LUIS.RODRIGUEZ/PRI_JOSE.LOPEZ>
Si el inicio no llevase parámetros de clave, el servidor entenderá que se cifra
con la clave asignada en el servidor al usuario que envía
<CRY/FIN>

<DI0> Datos iniciales. Son datos que se envían entre aplicaciones


<DI1> para su inicialización. Van del 0 al 9 . Pueden usarse en ambos
... sentidos. Preferentemente, DI5 como contestación a DI0,
<DI9> DI6 como contestación a DI1, etc.

<BRC> Mensaje dirigido a todos los clientes


<BRS> Mensaje dirigido a todos los servidores
<BRA> Mensaje dirigido a todos los equipos (Clientes y servidores)
<VER> Versión del programa cliente. Se envía al registrarse.
<VES> Solicita la versión de software del servidor. Devuelve la versión del software del
servidor.
<BIP> Busca IP. Se usa para comprobar que un cliente está disponible actualmente
en la red. No lleva parámetros.
<DIP> Es la respuesta del cliente a la llamada <BIP> Lleva como parámetro la
dirección SML o el nombre del usuario de ese cliente.
<UCC> Usuario Cliente Conectado. Se devuelve cuando un cliente recibe una solicitud
de conexión. Es equivalente al RHC del servidor.
<MN_> Información del mensaje. Número de mensaje. Es una cadena de caracteres
generada por el origen, para definir el mensaje enviado. Consiste en una
cadena de 4 caracteres programable por el usuario, seguida de un número que
indica el año, mes, día, hora, minuto y segundo del envío, todos ellos de dos
dígitos. (abcdyymmddhhnnss)
<FR_> Origen del mensaje (From) Lleva como parámetro la dirección SML del origen.
<IP_> Dirección IP desde la que se envía el mensaje. Es similar a <IPO> pero
solamente se utiliza al enviar un correo.
<TO_> Información del mensaje. Indica dirección de correo a la que se está enviando
el mensaje. Lleva como parámetro la dirección SML o SMTP del destino.
<SJ_> Información del mensaje. Indica el Asunto (Subjet) del mensaje. Lleva como
parámetro el contenido del asunto.
<NX_> Información del mensaje. Indica el nombre del fichero Anexado enviado en el
mensaje. Puede haber varios anexos dentro de un mismo mensaje, en este
caso se enviarán varios grupos <NX_>. Lleva como parámetro el nombre del
fichero en el origen y el tamaño (en bytes) del fichero.
<CX_> Cheksum del fichero anexado. Lleva como parámetro 8 bytes con el cheksum
en Hexadecimal. (El cheksum son 32 bits –4 bytes- expresados en
hexadecimal. Si no envía cheksum, estos 8 bytes se sustituyen por la cadena
YYYYZZZZ.
<BX_> Comienza la transmisión del anexo. No lleva parámetros. El primer carácter del
anexo debe transmitirse inmediatamente después de este acrónimo.

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 9


<EX_> Termina la transmisión del anexo. Este acrónimo debe enviarse
inmediatamente después del ultimo carácter del anexo.
<MSG> Cuerpo del mensaje enviado como texto. Lleva como parámetro el texto del
mensaje.
<CHM> cheksum del mensaje. Se envía cuando se solicita acuse de recepción o de
lectura, para comprobar la exactitud de la transmisión. Se usa también para
devolver el cheksum del mensaje al origen en la confirmación de recibo o
lectura. Lleva como parámetro los dos bytes del checsum codificados en
hexadecimal (4 caracteres).
<RTF> Información del mensaje. Indica que el contenido del mensaje está en formato
RTF. Puede no llevar ningún parámetro, en cuyo caso indica que todo el
cuerpo del mensaje está en formato RTF, o llevar le parámetro INI para indicar
que comienza el formato RTF y FIN para indicar que termina. Afecta solamente
al cuerpo del mensaje enviado con <MSG>
<SAR> Solicitado acuse de recibo. Puede llevar como parámetro una dirección de
correo SML o SMTP que será en este caso a quien enviará acuse de recibo del
mensaje. Si no lleva ningún parámetro enviará el acuse de recibo al origen del
mensaje. El acuse de recibo implica solamente que se ha recibido el mensaje
correctamente en el destino, pero no indica que se haya leído.
<SAL> Solicitado Aviso de Lectura. Puede llevar como parámetro una dirección SML o
SMTP que será en este caso a quien se envíe el aviso de lectura del mensaje.
Si no lleva parámetro se le enviará al origen del mensaje. Este aviso de lectura
indica solamente que se ha abierto el mensaje, pero no puede asegurar que el
usuario destino lo haya leído.
<FM_> Fin del mensaje. Indica que se ha transmitido todo el mensaje con todos los
anexos. En caso de una transmisión de mensajes múltiples, lleva como
parámetro el número del mensaje que termina. En caso de mensaje único no
lleva ningún parámetro o puede llevar el número del mensaje.

Una máquina puede identificarse bien por su dirección IP o por su nombre dentro de una red.
Puede también identificarse por ambos, en aquellas situaciones en las que la máquina
receptora del mensaje deba retransmitirlo a otra máquina. Este es el caso, por ejemplo, de una
red conectada a través de una conexión ADSL. El módem ADSL tiene asignado un número IP
verdadero, y en esa red existen varias máquinas que cada una de ellas tendrá un nombre
distinto, y un número IP distinto, (número IP que para estas máquinas será ya de la numeración
interna) Al poder identificar una máquina por su IP y nombre, basta con poner como IP de
destino el numero IP real del módem ADSL, y como nombre, el nombre de la máquina dentro
de la red privada.

Por ejemplo:

<CAT> <IPO/100.100.100.100><IPD/217.126.179.96><NMD/Administracion_1>
<OCE/123>
<RQY/[Antonio Fernandez_91 1234567][Antonio Fernangomez_91 7654321]>

Este mensaje devuelve el resultado de una consulta a la máquina Administracion_1 que está
en la red de área local cuyo acceso desde Internet se realiza por un módem ADSL cuyo
número IP es el 217.126.179.96. Lógicamente, la máquina real que recibe esta comunicación
no es la máquina Administracion_1, sino otra máquina colocada en la misma red de área local,
sobre la cual se ha hecho NAT desde Internet para el puerto que use este sistema, y esta
máquina, una vez recibido el mensaje, lo reenvía a la máquina Administracion_1 que será
quien lo trate. Si la comunicación no llevase más que el número IP, se entiende que el destino
es la máquina que tiene ese número IP.

ORDENES PREPROGRAMADAS

Las órdenes preprogramadas son aquellas que el servidor ya tienen programadas en su


código. Deben ir necesariamente tras el acrónimo <QPR> ya que en caso contrario no serán
tratadas.

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 10


<ORG> Pide / devuelve el organigrama. No lleva más parámetros
<ABN> Pide devuelve el nombre t Teléfono 1 de los abonados de un departamento. Se
le pasa como parámetro el ID de ese departamento (Campo
Ag_Departamento_ID)
<ABD> Pide / devuelve todos los datos de un abonado. Lleva como parámetro el ID de
ese abonado.
<ABL> Pide / devuelve todos los datos de los abonados de un departamento. Se le
pasa como parámetro el ID del departamento.
<ABC> Pide todos los datos de los abonados de un despacho. Se le pasa como
parámetro el número de despacho. Los datos se devuelven con el acrónimo
<ABL>
<ABB> Pide todos los datos de los abonados que tienen un determinado nombre
(Búsqueda aproximada por ambos lados) Se pasa como parámetro el nombre
por el que se quiere buscar, o las letras del nombre por el que se va a realizar
búsqueda aproximada. Devuelve los datos con el acrónimo <ABL>
<ABA> Pide todos datos de los abonados con un determinado primer apellido
(Búsqueda aproximada por la derecha) Se pasa como parámetro el apellido a
buscar, o la cadena de caracteres por la que hará la búsqueda. Devuelve los
datos con el acrónimo <ABL>
<ABE> Pide todos los datos de los abonados con un determinado segundo apellido.
(Búsqueda aproximada por la derecha) Se pasa como parámetro el apellido a
buscar, o la cadena de caracteres por la que hará la búsqueda. Devuelve los
datos con el acrónimo <ABL>
<ABF> Pide todos los datos de los abonados con el mismo primer apellido (Búsqueda
aproximada por la derecha) y segundo apellido (Búsqueda aproximada por la
derecha). Se pasan como parámetros los apellidos a buscar, o las cadenas de
caracteres por las que hará la búsqueda. Devuelve los datos con el acrónimo
<ABL>
<ABG> Pide todos los datos de los abonados con el mismo nombre (Búsqueda
aproximada por los dos lados) y el mismo primer apellido (Búsqueda
aproximada por la derecha) Se pasa como parámetro el nombre y apellido a
buscar, o las cadenas de caracteres por la que hará la búsqueda. Devuelve los
datos con el acrónimo <ABL>
<ABH> Igual que el anterior, con nombre y segundo apellido.

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 11


LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 12
EL CONTROL PERSONALIZADO MICROSOFT COMM

Este control permite la comunicación de una aplicación VB con el puerto serie. Parece en
principio que los puertos serie del PC se usan para muy pocas cosas. Prácticamente para
conectarnos a Internet a través de un módem telefónico. Existen muchísimas aplicaciones
industriales para las cuales son fundamentales los puertos COM. Las redes de área local
parece que han dejado obsoletos a los puertos COM1 y COM2. No es así. Deje volar su
imaginación. Vuelva a la página 4 del capítulo 2, y observe el panel de control de una radio
realizado en Visual Basic. La unión entre el PC y la radio, separados muchos kilómetros, se
realizó mediante el puerto COM, conectado a una línea telefónica mediante un módem. El
puerto COM es el gran olvido de los informáticos…

El control MSComm no está normalmente en la caja de herramientas, por lo que será


necesario introducirlo mediante Proyecto | Componentes.

En el formulario solamente se le ve en tiempo de diseño. El icono que lo representa en la caja


de herramientas coincide con el que presenta en el formulario:

Al tratarse de un control personalizado, presenta dos formas de ver las propiedades. Si


hacemos click con el botón derecho del ratón sobre el control y vamos a propiedades, nos
presenta tres cuadros de configuración de los típicos de los controles personalizados. Si
seleccionamos el control MSComm y pulsamos F4 , aparecerá la caja de propiedades típica de
los controles VB.

PRPIEDADES

Existen propiedades que pueden establecerse en tiempo de diseño o en tiempo de ejecución, y


otras que solamente se pueden ejecutar o consultar en solamente en tiempo de ejecución. Se
detallan a continuación las primeras. Las segundas se enumerarán tras estas, aunque se
nombran algunas de estas últimas al explicar cada una de las propiedades del primer tipo.

CommPort
Indica el número del puerto serie usado. Admite los valores de 1 a 255. Cambiando esa
propiedad podemos cambiar el puerto de comunicación que vamos a usar (Un PC tiene
normalmente 2 puertos serie : El Com1 y el Com2. Puede tener sin grandes problemas
Hardware hasta 4 (Com3 y Com4) Si le damos a ese valor un número de puerto inexistente,
dará error.

Settings

Sintaxis Velocidad, Paridad, Bits de información, Bits parada

Indica la velocidad, paridad, número de bits y bits de stop (parada) que se van a usar en la
comunicación.

Los valores posibles para velocidad son : Indica la velocidad en baudios.

50 100 110 300 600 1200 2400 4800 9600 14400 19200 y 28800

Los valores posibles para paridad son :

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 13


N - No envía bit de paridad ni hace comprobación de paridad en la recepción.
O - Envía y comprueba paridad, con el criterio de paridad IMPAR
E - Envía y comprueba paridad, con criterio de paridad PAR

Los valores para el parámetro Bits de Información pueden ser :

7 - Se envían / reciben 7 bits por trama de información.


8 - Se envían / reciben 8 bits por trama de información
5 - Se envían / reciben 5 bits por trama de información. Este valor de 5 bits es el típico
del sistema Baudot para transmisión telegráfica (Teletipos) que se ha conservado en
las comunicaciones informáticas por pura tradición. Si se eligen 5 bits, los bits de parada
se ponen automáticamente a 1,5 (Típico también del sistema Baudot.)

Los valores para el parámetro Bits de parada pueden ser :

1 - Se envía un bit de parada


2 - Se envían 2 bits de parada

(No es posible programar 1,5 bits de parada. Sólo lo hace cuando se programan 5
bits de información y lo hace automáticamente).

Handshaking

Especifica el método de control sobre el flujo de información. En una comunicación serie se


necesita conocer si el puerto puede enviar información (necesita saber si el módem está
preparado para recibirla) y necesita indicarle al módem que él está preparado para recibir
información. A este proceso se le denomina Handshaking. (Handshaking = Control de Flujo)
(Como sabrá por sus conocimientos de inglés, Handshaking significa apretón de manos,
ponerse de acuerdo. Y ponerse de acuerdo entre dos terminales que van a comunicarse es
establecer las condiciones de control que uno va a tener sobre otro.)

El Control de Flujo puede hacerse de dos formas : Una mediante las señales auxiliares del
puerto (RTS, CTS, DSR, DTR), que son cables adicionales que tendrán una tensión positiva
respecto a los 0V del equipo si esa señal está activada, o una tensión negativa si no lo está.
Este tipo de control del flujo de información es el típico para comunicarse el ordenador con un
módem.

Existe otra forma de controlar el flujo de información : mediante señales especiales que se
envían por los dos cables que transportan la información. Mediante estas dos señales podemos
controlar que el ordenador envíe información o deje de enviarla. De igual forma, podemos
indicarle al módem que envíe o no envíe. Estas señales especiales se denominan X-ON y X-
OFF.

La propiedad Handshaking controla la forma de realizar este proceso. Puede tomar los
siguientes valores :

0 - No existe Control de Flujo


1 - Control de Flujo mediante XON - XOFF
2 - Control de Flujo mediante Request To Send (RTS) y Clear To Send (CTS)
3 - Control de Flujo mediante XON - XOFF y RTS - CTS

Los tres tipos de Control de Flujo tiene cada uno su aplicación.

InBufferSize

Mediante esta propiedad establecemos el tamaño del Buffer (almacén de datos) de entrada.
Este Buffer sirve para poder recibir datos sin que tenga que intervenir la aplicación
continuamente para controlar el puerto de entrada.

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 14


Puede conocerse el número de caracteres presentes en el Buffer de entrada consultando el
valor de la propiedad InBufferCount.

OutBufferSize

Mediante esta propiedad controlamos el tamaño del Buffer de salida.

El tamaño de los Buffers dependerá de la aplicación y de la velocidad de comunicación. Si la


aplicación tiene muchas cosas que hacer, aparte de controlar el puerto de comunicaciones, se
deberá poner un Buffer grande. Tanto mas grande cuanta mayor sea la velocidad de
transferencia de datos.

Puede conocerse el número de caracteres presentes en el Buffer de salida (los que aún están
por transmitir), consultando el valor de la propiedad OutBufferCount.

RThreshold, SThreshold

Estas dos propiedades especifican el número de caracteres que deben estar presentes en los
Buffers de Recepción y Transmisión respectivamente, para que se produzca el evento
OnComm relativo a recepción y transmisión de caracteres. (Eventos EvReceive y EvSend) Si
el valor de una de estas propiedades está a 0, no se produce el evento OnComm
correspondiente.

El valor que se debe dar a estas dos propiedades depende de la aplicación y del tiempo que
queramos que la aplicación está atendiendo al puerto de comunicaciones. Concretamente para
la propiedad RThreshold debemos pensar muy bien el valor que se le pone. Si ponemos un
valor corto (1 es el mínimo), cada vez que reciba un carácter se producirá el evento OnComm.
(Vea la descripción de eventos mas adelante). Al producirse este evento, ejecutará el
procedimiento asociado a él, lo que hará perder tiempo a la aplicación, impidiéndole realizar
otras funciones. Si se pone un valor muy alto, el puerto no avisará que tiene caracteres
recibidos hasta que reciba un número igual al programado en esta propiedad, por lo que no
podremos procesar los datos recibidos hasta que el buffer tenga ese número de caracteres en
su interior. En número adecuado dependerá del tipo de aplicación que vayamos a realizar. En
cualquier caso, este número será inferior al número programado para la longitud del buffer,
(InBufferSize)

InputLen

Por defecto, cuando se lee el Buffer de recepción, se leen todos los caracteres, quedando el
Buffer vacío. Si se le asigna a esta propiedad un valor distinto de 0, cada vez que leamos el
Buffer de recepción leerá un número de caracteres igual a esa cantidad, permaneciendo los
caracteres restantes en el Buffer a la espera de una nueva lectura. Asignándole el valor 0
(Valor por defecto), el buffer se lee completo.

ParityReplace

Si la comunicación se realiza con bit de paridad (Par o Impar), en recepción se comprueba byte
a byte la recepción de la paridad correcta. Si se recibe un Byte que no tiene paridad correcta, lo
mas probable es que ese Byte (carácter) se haya recibido defectuoso. Esta propiedad nos
permite sustituir un carácter que ha llegado con bit de paridad incorrecto por otro carácter. ( ?
predeterminado). Se puede sustituir por una cadena de caracteres (Error, por ejemplo).

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 15


NullDiscard

Cuando se recibe el carácter nulo (00000000) puede ser que no sirva para nada a efectos de
nuestra aplicación, o que este carácter sea un dato mas. Esta propiedad acepta los valores
True / False. Si es True se desprecia el carácter Nulo. Si es False, se toma como un carácter
mas.

CTSTimeout

Es el tiempo (en milisegundos) que permanece esperando la señal CTS (Señal CTS -
Dispuesto para enviar), señal de entrada al ordenador que debe estar presente antes de que el
puerto comience a enviar información. El tiempo se mide desde que se pone activa la señal de
salida RTS (Petición de envío). Si se supera este tiempo entre el instante de activación de la
señal RTS y la recepción de la señal CTS, se produce el evento CTSTO. Poniendo 0 en esta
propiedad, se deshabilita, y en estas condiciones no se producirá nunca el evento CTSTO.

CDTimeout

Es el tiempo máximo de espera (en milisegundos) desde que se activa la señal DTR hasta que
se recibe la señal CD (Carrier Detect - Detección de portadora). Este tiempo solamente tendrá
importancia en ciertas aplicaciones donde se espere recibir CD continuamente. No tendrá
sentido cuando la aplicación se queda en espera a recibir una comunicación, pero sin saber
cuando la tiene que recibir. Si transcurre el tiempo programado en esta propiedad, ocurrirá el
evento CDTO. Poniendo el valor 0 se deshabilita esta propiedad y no se producirá nunca el
evento CDTO.

DSRTimeout

Similar a la anterior, pero en vez de esperar la señal CD se espera la señal DSR. Esta
propiedad sí tiene sentido, ya que si, por ejemplo, estamos conectados con un módem, y
nuestra aplicación se pone a la espera de recibir alguna llamada, activa la salida DTR, y espera
recibir inmediatamente la respuesta de que el módem está dispuesto, mediante la línea DSR.
Si transcurre el tiempo programado sin recibir la señal DSR se producirá el evento DSRTO .
Poniéndola a 0, se deshabilita esta propiedad y nunca ocurrirá el evento DSRTO.

RTSEnable

Activa (Pone a 1) la señal RTS (Request To Send - Petición de envío) Esta señal debe
ponerse a 1 para indicar al módem (o al equipo que va a recibir nuestra comunicación) que
deseamos enviar datos. Debe estar activada durante toda la transmisión de datos.

Cuando se pone la propiedad Handshaking a 2 (control con RTS / CTS) ó 3 (Control con RTS /
CTS y con X-ON / X-OFF) no debemos preocuparnos de poner a 1 la señal RTS, pues lo hace
automáticamente el puerto de comunicaciones. Esta propiedad está ahí para aplicaciones
donde no se emplee ese tipo de Handshaking y necesitemos activar algo antes de transmitir.
(Caso por ejemplo de transmisión de datos por radio, donde podemos usar esta señal de salida
para activar el PTT (Push To Talk - Pulse para hablar) y poner el transmisor en marcha)

DTREnable

Activa (Pone a 1) la salida DTR (Data Terminal Ready - Terminal de Datos Listo). Esta señal
se emplea para decirle al módem que el terminal (Ordenador) está preparado para recibir
datos.

Se hace la misma observación que para la propiedad anterior respecto a los valores de la
propiedad Handshaking

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 16


Interval

Indica el tiempo (en milisegundos) del intervalo entre una y otra comprobación del estado de
recepción del puerto. El valor mínimo es de 55 ms.

El análisis del puerto de comunicación no tiene nada que ver con la generación del evento
OnComm. Este evento se producirá cuando se cumplan las condiciones para ello,
independientemente del tiempo programado en esta propiedad. La comprobación del puerto
cada intervalo de tiempo marcado por esta propiedad solamente afecta a averiguar el estado
de las líneas auxiliares CD, DSR y CTS, y para saber el número de caracteres existentes en los
Buffers de transmisión y recepción.

Las siguientes propiedades no difieren en nada respecto a otros controles :

Left, Name, Index, Top, Tag

Propiedades propias del tiempo de ejecución

PortOpen

Abre el puerto de comunicación. Puede tener los valores True (Para abrirlo) y False (Para
cerrarlo) Si tenemos un MSComm con Nombre (Name) MSComm1, para abrirlo ejecutaremos
la siguiente sentencia :

MSComm1.PortOpen = True

Para cerrarlo, ejecutaremos :

MSComm1.PortOpen = False

InBufferCount.

Nos permite averiguar cuantos caracteres tenemos en el Buffer de entrada. Con el mismo
MSComm anterior, comprobaremos el número de caracteres sin leer con la sentencia :

caracteressinleer = MSComm1.InBufferCount

OutBufferCount

Nos permite conocer cuantos caracteres quedan por transmitir en el Buffer de salida.
Emplearemos la sentencia :

caracteressinenviar = MSComm1.OutBufferCount

Output

Envía caracteres al Buffer de salida. Debe existir un signo igual ( = ) entre Output y lo que se
envía al Buffer. Para enviar la frase Curso de Visual Basic ejecutaremos la sentencia :

MSComm1.Output = “Curso de Visual Basic”

Si deseamos enviar el contenido de una variable

MSComm1.Output = variable

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 17


Input

Lee el Buffer de recepción. El número de caracteres leídos dependerá del valor de la propiedad
InputLen. Cuando la propiedad InputLen tiene el valor 0, el Buffer se lee completo. Si
InputLen tiene un valor distinto de 0, se leerá un número de caracteres igual al valor de esta
propiedad.

CommEvent

Devuelve el evento mas reciente que ha ocurrido para generar el evento general OnComm
(Vea mas adelante). Esta propiedad no está disponible en tiempo de diseño y es de sólo
lectura en tiempo de ejecución.

Sintaxis NombredelMSComm.CommEvent

Break

Devuelve un valor (True / False) que indica que se ha recibido la señal Break.

variable = MSComm1.Break

CDHolding

Devuelve el estado de la línea de control CD (Detección de Portadora) Si es True, esa entrada


está activada, si es False, la entrada está desactivada.
variable = MSComm1.CDHolding

CTSHolding

Devuelve el estado de la línea de control CTS (Dispuesto para enviar) Si es True, esa entrada
está activada, si es False, la entrada está desactivada.
variable = MSComm1.CTSHolding

DSRHolding

Devuelve el estado de la línea de control DSR (Data Set Ready ) Si es True, esa entrada está
activada, si es False, la entrada está desactivada.
variable = MSComm1.DSRHolding

EVENTOS DEL MSComm

El MSComm tiene varios eventos, pero un solo Procedimiento : el Procedimiento OnComm.


Este procedimiento se ejecuta cada vez que se produce alguno de los eventos del MSComm.
Esto quiere decir que para escribir el código apropiado en el procedimiento del MSComm será
necesario analizar qué evento se ha producido y colocar, mediante una sentencia If .. Then el
código apropiado para cada uno de los eventos que se produzcan.

Para averiguar qué evento se ha producido puede hacerse consultando el valor de la propiedad
CommEvent. (Se toma como nombre del MsComm el de MsComm1)

If MsComm1.CommEvent = ComEvRing Then

'Se ha consultado si el evento particular que ha producido el evento general OnComm


'ha sido el ComEvRing (Se está recibiendo la llamada del teléfono). En esta sentencia

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 18


‘If Then deberemos colocar el código necesario para que la aplicación se prepare para
‘recibir una comunicación a través del módem.

End If

Los eventos del Comm pueden identificarse por una constante o un número. La constante,
como todas las de Visual Basic, tiene una expresión bastante difícil. Se pone entre paréntesis
el número que identifica a ese evento. Este número debe declararse como Integer.

Se ejecutará el Procedimiento OnComm cuando ocurra alguno de los siguientes eventos :

ComEvCD (5) Cambio en la línea CD. Para conocer el estado actual de esa línea
(Activado/Desactivado) deberemos invocar la propiedad CDHolding

ComEvCTS (3) Cambio en la línea CTS. Igual que la anterior, este evento solamente
nos indica que ha existido un cambio. Para averiguar el estado en que
se encuentra esta línea, debemos invocar la propiedad CTSHolding

ComEvDSR (4) Cambio en la línea DSR. Igual que las anteriores. Debemos invocar la
propiedad DSRHolding para averiguar su estado actual.

ComEvRing (6) Cambio en la línea de detección de llamada (Ring). Este evento se


produce cuando hay un cambio en la línea Ring (Detección de
llamada en el módem)
No existe una propiedad para averiguar el estado de la línea Ring
pues no es necesario. Lo importante de esta línea es que está
cambiando, es decir, el teléfono está sonando y poco importa que
analicemos si la línea Ring está a 1 o a 0, pues toda llamada
telefónica es intermitente. Dependiendo de la UART de su PC, puede
que este evento no lo soporte.

ComEvReceive( 2 ) Cuando se recibe un número igual o mayor de caracteres que el


indicado en la Propiedad RThreshold

ComEvSend (1) Cuando quedan en el búfer de transmisión menos caracteres que los
indicados en la Propiedad SThreshold

ComEvEOF (7) Recibido un carácter de fin de archivo (carácter ASCII 26) .

comEventBreak (1001) Se ha recibido una señal de interrupción. (Break)

ComEventCDTO (1007) Tiempo de espera de Detección de portadora. La línea


Detección de portadora (CD) estuvo baja durante el periodo de tiempo
especificado en la Propiedad CDTimeout, mientras se intentaba
transmitir un carácter.

ComEventCTSTO 1002 Tiempo de espera de Preparado para enviar. La línea


Preparado para enviar (CTS) estuvo baja durante el periodo de tiempo
especificado en la propiedad CTSTimeout mientras se intentaba
transmitir un carácter.

ComEventDSRTO 1003 Tiempo de espera de Equipo de datos preparado. La línea


Equipo de datos preparado (DSR) estuvo baja durante el periodo de
tiempo especificado en la Propiedad DSRTimeout mientras se
intentaba transmitir un carácter.

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 19


ComEventOverrun 1006 Se sobrepasó la capacidad del Buffer de entrada sin haber
leído todos los caracteres. Los caracteres no leídos se han perdido.
Debemos aprovechar este evento para solicitar al colateral una
repetición de los datos perdidos.

ComEventRxOver 1008 Desbordamiento del búfer de recepción. No hay espacio para


más datos en el búfer de recepción.

ComEventRxParity 1009 Error de paridad. El hardware ha detectado un error de


paridad.

ComEventTxFull 1010 Búfer de transmisión lleno. El búfer de transmisión estaba


lleno cuando se ha intentado agregar un carácter a la cola de
transmisión. Este error es fácil de evitar, analizando el valor
de la propiedad OutBufferCount antes de enviar mas datos al buffer
de salida.

ComEventDCB 1011 Error inesperado al recuperar el Bloque de control de


dispositivos (DCB) para el puerto.

ComEventFrame 1004 Error de trama. El hardware ha detectado un error de trama.

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 20


NOTA ADICIONAL El puerto de comunicaciones.

El puerto de comunicaciones de un PC está formado por varias entradas / salidas. El soporte


físico es un conector tipo Sub-D de 9 ó 25 contactos, macho en ambas versiones. Se necesita
por tanto un cable con conector Sub-D hembra de 9 o 25 pines para acceder a él.

La distribución de las señales en cada uno de sus pines es la siguiente :

GND (Potencial de 0 V.).

TxD Transmisión de datos. Es una salida del ordenador. Por ella salen los datos en serie.

RxD Recepción de datos. Es una entrada del ordenador. Por ella entran los datos en serie.

RTS Request To Send. Petición de envío. Es una salida del ordenador. El ordenador pone a
1 esta señal cuando quiere enviar datos.

CTS Clear To Send. Dispuesto para enviar. Es una entrada del ordenador. Si está a 1
significa que el ordenador puede enviar datos pues el módem (o el dispositivo que
vaya a recibirlos) está preparado para hacerlo.

DSR Data Set Ready. Dispositivo de datos preparado. Es una entrada del ordenador. Le
indica que el módem está encendido y listo para funcionar.

DCD o CD Carrier Detect. Detección de portadora. Es una entrada del ordenador. Le


indica al ordenador que el módem está detectado señal de audio (tonos) válida.

DTR Data Terminal Ready. Terminal de datos listo. Es una salida del ordenador. Indica que
está listo para trabajar. Suele emplearse para indicar al módem que el ordenador está
dispuesto para recibir información.

Otra señal (disponible sólo en los ordenadores que tengan conector de 25 pines, y no en todos)
es la señal RING (timbre del teléfono) Es una entrada del ordenador. Le indica que está
sonando el timbre de la línea telefónica del módem.

Disposición de los pines en el ordenador

Dependiendo de si tiene conector de 9 pines o de 25, la distribución de estas señales


físicamente en el conector es :

Conector de 9 pines Conector de 25 pines

Pin Señal Pin

3 TxD 2
2 RxD 3
7 RTS 4
8 CTS 5
6 DSR 6
5 GND 7
1 CD 8
4 DTR 20
RING 22
Tierra de protección 1

(La señal RING no está disponible en el conector de 9 pines. La detección del Ring del
teléfono se realiza directamente por la línea RxD. El módem envía la palabra RING cuando
suena el timbre del teléfono. La tierra de protección tampoco se usa en este conector.

LSB Visual Basic Guía del Estudiante Cap. 20 Pág. 21

You might also like