Vous êtes sur la page 1sur 188

Curso Bsico de Programacin

en Visual Basic
Primera. (Iniciado el 18/Abr/97)
por Guillermo "guille" Som

A estas alturas no es fcil hacer un curso de introduccin a la programacin con Visual Basic. Si fuese a
raiz de la primera o segunda versin, incluso con la tercera, sera ms fcil. Pero ahora est ms crudo,
por aquello de que soporta 16 y 32 bits y te enfocas en una u otra direccin o...
Pero como el ttulo indica, esto ser una cosa para introducir al que quiere empezar a programar, incluso
para el que viene de otro lenguaje, aunque seguramente, sobre todo al principio, se encontrar con
conceptos demasiados bsicos.
Como este curso no se publica sobre algo que ya est terminado, ir hacindolo sobre la marcha, espero
tus indicaciones sobre si voy demasiado rpido o si realmente me estoy pasando en cuanto a 'simpleza'.
De cualquier forma, me gustara oir tu comentario y tus impresiones, eso me animar a seguir y sobre
todo a terminar.
Bueno, manos a la obra.
A ver como me sale el tema, (al final no he encontrado los apuntes que ya tena hechos, de cuando daba
clases a nios y a no tan nios, de esto hace ya 10 aillos de nada)
Lo advierto, a los que saben algo y a los que lo saben todo (o casi todo), lo que viene a continuacin
es super bsico. Y pensando tambin en los que por una razn u otra no tienen unos conocimientos
que a otros les parecer absurdo, s que an hay gente que no tienen ni 'repajolera' idea de lo que es
una expresin, una variable y ni que decir tiene sobre las matrices, los nmeros binarios o la notacin
hexadecimal...
Que es una variable?
En cualquier programa siempre necesitaremos hacer clculos, usar informacin, procesarla y mostrarla.
En la mayora de los casos, necesitaremos un lugar temporal en el cual guardar parte de esa
informacin, incluso toda.
Todos los lenguajes, y el Basic no iba a ser menos, nos permiten guardar datos en la memoria, para que
cuando los necesitemos, podamos tomarlos, modificarlos y volverlos a guardar para usarlos ms tarde.
Si no seguimos unas normas o usamos unas reglas, de poco nos iba a servir el guardar esa informacin,
si despus no podemos almacenarla en ningn sitio, pero ese ser tema de otro captulo... ahora
centremosno en la memoria.
La memoria? Espero que este concepto lo tengas claro, pero si no es as, ah va un poco de 'rollo':
La memoria es el lugar donde el ordenador almacena de forma temporal los programas y parte de la
informacin que necesita o utiliza. As pues, los lenguajes de programacin usan tambin esa memoria
para guardar informacin propia del lenguaje y del programa que queramos realizar.
El programa una vez que se est ejecutando puede necesitar tambin guardar informacin, aunque esta
informacin slo estar disponible mientras se est ejecutando. Esas posiciones o lugares de la memoria
donde los programas pueden almacenar informacin son las variables. El que se llamen de esta forma
es porque podemos hacer que el contenido de ese lugar de almacenamiento varie, es como si
tuviesemos una serie de cajas y en ellas pudiesemos guardar cosas, con la salvedad de que en cada
caja slo puede haber una cosa a la vez; aunque tambin veremos cmo hacer que el contenido pueda
variar y que varie dependiendo de lo que contena antes...
Veamos un ejemplo:
Imaginate que quieres guardar tu nombre en una variable, para ello tendriamos que 'guardar' el nombre
en la memoria, es decir asignar a una variable un valor. En este caso nuestro nombre. Para ello el
lenguaje de programacin pone a nuestra disposicin unos lugares deonde almacenar nuestro nombre,
pero nos impone una serie de reglas de conducta.
Si queremos guardar en una de nuestras cajas una hoja, por lo menos tendremos una caja con el
tamao adecuado y que tenga una 'forma', para que el papel no vuele al menor soplo de viento.
Esta es la regla bsica para poder usar esos lugares de almacenamientos (variables):
Llamar a esas posiciones de memoria con un nombre. Simple, verdad?
En principio, es todo el requisito necesario: que le demos un nombre al sitio en el que queremos guardar
la informacin.

Por tanto, si queremos guardar un nombre, (el nuestro, por ejemplo), en la memoria, podramos
llamarlo nombre.
Y ahora tendremos que seguir otra norma de conducta (o funcionamiento), que en este caso el lenguaje
Basic nos dicta:
Para guardar en una variable (posicin de memoria) algo, debes hacerlo de la siguiente manera:
---Pon el nombre con el que quieres llamar a esa parte de la memoria,
---a continuacin pones el signo igual (=) y
---despus lo que quieras guardar.
Por tanto para guardar Guillermo en la variables nombre, tendriamos que hacer (o casi):
Nombre = Guillermo
Pero esto poda llevar a confusin, ya que el Basic no nos dice nada sobre cmo debemos llamar (o si lo
prefieres, cmo hay que escribir) el nombre de una variable, por tanto Guillermo tambin podra ser una
variable, (es que el Basic, a pesar de que llevo tantos aos bregando con l, no sabe que ese es mi
nombre!!!).
As pues, cuando queramos guardar en una variable una palabra, una frase, nombre o cualquier tipo de
informacin alfabtica, tendremos que indicarlo poniendo dicha informacin dentro de comillas dobles, el
ejemplo quedara as:
Nombre = "Guillermo"
Ahora no hay confusin posible, hemos seguido lo que el Basic nos ha dicho: variable, signo igual, valor
a almacenar.
Si queremos guardar un nmero en una variable, la cosa es ms simple:
Numero = 7
Te ests enterando?
Pero, que ocurre si quisieramos repetir 7 veces a Guillermo?
Podras hacer esto, multiplicar a Guillermo por 7 (como no hay bastante con uno...)
Paliza = "Guillermo" * 7
Pero el Basic te dira que eso no est bien, no porque Guillermo (yo) no sea un paliza, sino porque te
dira que no coinciden los tipos (Type Mismatch)
Que son los tipos? Los distintos tipos de datos. (que esfuerzo mental...)
Los datos pueden ser, bsicamente, de dos tipos:
Numricos: slo nmeros y
Alfanumricos: cualquier cosa, letras y/o nmeros, pero es tratada como si fuesen palabras, frases, etc.
Para el Basic 7 y "7" son dos tipos de datos diferentes.
El primero es el nmero 7 y en el segundo caso, es el literal (o palabra) "7"
As que cuando veas algo entrecomillado, piensa que no es un nmero, sino una palabra (ms
vulgarmente llamada cadena de caracteres o string en ingls)
Hemos visto que no podemos multiplicar una palabra (cadena) por un nmero, pero si podemos
multiplicar una variable por un nmero (siempre que la variable sea numrica, por supuesto)
Segn esto, el Basic debera permitir hacer esto:
Guillermo = 5
Paliza = Guillermo * 7
El Basic tomara el 5 y lo almacenara en ena variable numrica llamada Guillermo.
Despus se encuentra con: Paliza = Guillermo * 7 y aqu lo que hace es evaluar la expresin que est
despus del signo igual, lo calcula y el resultado lo guarda en la variable que est a la izquierda del signo
de asignacin (=)
Expresin? Expresin es cualquier cosa que el Basic tenga que 'desglosar' para poder entenderla,
incluso a veces ni eso...
Por ejemplo cuando el Basic se encuentra con 5 * 2 tiene que 'evaluar' lo que significa, para poder hacer
el clculo, de esta forma sabr que tenemos una operacin en la cual queremos multiplicar dos nmeros,
una vez que ha evaluado nuestra intencin de multiplicar esos dos nmeros, efectuar el clculo y
almacenar el resultado en... si no le decimos dnde, lo har en una memoria que tiene para esas cosas,
pero si no le indicamos que debe hacer con ese resultado, nos dar un error...
Si le decimos simplemente: 5 * 2
El Basic no sabr que hacer con el resultado de esta 'expresin' (que por cierto es 10) y nos dir:
o te espabilas o lo tienes crudo conmigo.
As que lo ms juicioso sera decirle: vale, vale, guardalo en una variable, as que:
Resultado = 5 * 2 guardara un 10 en la variable Resultado.
Tambin podramos decirle que nos mostrara el resultado, en lugar de guardarlo en una variable, y aqu
llega nuestra primera instruccin: Print. Con ella le decimos al Basic que lo imprima (o sea que los
muestre, ms adelante vermos dnde), segn lo dicho, haciendo esto:
Print 5 * 2, el Basic dira que muy bien y mostrara un 10
Pero, volvamos al Paliza del Guillermo, es decir al ejemplo de Paliza = Guillermo * 7
Si quisieramos mostrar el valor de Paliza, tendramos que hacer algo como esto: Print Paliza, y nos

mostrara 35, ya que el valor de Paliza sera 35, porque el contenido de Guillermo es 5 y 5 * 7 es 35 (y
sin calculadora!!!)
Veamos si es cierto que Guillermo vale 5. Haciendo Print Guillermo, mostrar un 5.
Antes de seguir 'imaginando' las cosas, vamos a verla en funcionamiento. Es decir vamos a probar que
todo esto es cierto.
Carga el Visual Basic (si es que an no lo has hecho.
Te crear un Form nuevo, que estar vaco.
Cierralo y muestra la ventana de cdigo.
Mostrar la parte de las declaraciones Generales del Formulario.
Si tiene escrito Option Explicit, (estar en la parte superior), borralo, ms adelante te explicar para que
sirve.
Ahora situate en Form (seleccionalo de la lista desplegable que est a la izquierda), te mostrar:

Private Sub Form_Load()


End Sub
Situate en medio, es decir, en una lnea en blanco despus del Private... y escribe el ejemplo, quedara
as:

Private Sub Form_Load()


Show
Guillermo = 5
Paliza = Guillermo * 7
Print Paliza
End Sub
Pulsa F5, para ejecutar el programa, y vers que se escribe el 35.
Bien, ya tienes una forma de mostrar datos. Ahora veamos otros ejemplos, antes debes parar el
programa, para ello cierra el Form, pulsando en el botn que tiene una X, o bien pulsa en el botn
detener de la barra de herramientas del VB.
Situate de nuevo en el cdigo del Form_Load, escribe despus de la lnea del Print, lo siguiente:

Print Guillermo
Pulsa de nuevo F5 y vers que ahora adems del 35, hay un 5 debajo. El valor de la variable Guillermo.
Pero, que ocurrira si cambiasemos el valor de Guillermo?
Aade estas lneas a continuacin de la anteriores, para que quede de esta forma:

Private Sub Form_Load()


Show
Guillermo = 5
Paliza = Guillermo * 7
Print Paliza
Print Guillermo
Guillermo = 10
Print Guillermo
Print Paliza
End Sub
Despus de pulsar F5, te mostrar los siguientes valores (cada nmero en una lnea), 35, 5, 10, 35
Esperabas que el ltimo fuese 70?
Fijate que cuando asignamos a Paliza el contenido de Guillermo, ste era 5, por tanto el Basic evalu la
expresin 5 * 7 y almacen el resultado (el 35). Una vez almacenado el resultado, el Basic se olvid de
dnde haba sacado ese 5.
Si queremos que se 'actualice' el valor de Paliza, tendremos que indicarselo de nuevo al Basic, para que
vuelva a evaluar la expresin y hacer la correspondiente asignacin. Para ello, pon en medio de los dos
ltimos prints la siguiente asignacin:

Paliza = Guillermo * 7
Esta vez, al ejecutar el programa, mostrar un 70, que ser el nuevo contenido de Paliza.
Ya para terminar, borra todo lo anterior y escribe: (por supuesto debes detener el programa...)

Private Sub Form_Load()


Show
Nombre = "Guillermo"
Print Nombre
End Sub
Pulsa F5 y vers que se muestra el contenido de la variable Nombre, es decir Guillermo.
Prueba ahora con esto otro (es un clsico):
Print "Hola Mundo"
Y para rematar, y de camino ver otra posiblidad del Print, escribe en lugar del Print Nombre:
Print "Hola " ; Nombre
El punto y coma, se usa para indicarle al Basic que se deben mostrar las cosas una a continuacin de la
otra.
Ahora te habr mostrado: Hola Guillermo, fijate que despus de hola y antes de cerrar las comillas hay
un espacio.
Bien, creo que con esto es suficiente por hoy... o por ahora.
Si tienes algn comentario, hazlo pulsando en este link. As sabr que opinin te merece este primer
captulo del cursillo/tutorial o como prefieras llamarlo.
Nos vemos, (espero que pronto).

Nota: En todos los FORM_LOAD debers poner SHOW al principio para que se
muestre lo que se imprime.

Curso Bsico de Programacin


en Visual Basic
Segunda Entrega: 09/May/97.
por Guillermo "guille" Som

Seguimos con este cursillo bsico. Antes de nada una pequea aclaracin, para que los ejemplos que se
dieron en la entrega anterior, debers poner un Show en el form Load antes de los Prints, para que se
muestre algo... sino no se ver nada.
Una vez hecha esta pequea puntualizacin, vamos a la tarea.
El tema de hoy ser sobre el manejo de entrada de datos y una forma un poco ms prctica de mostrar
los datos, empezaremos a vernos ya con lo que es programar con Windows, es decir el manejo de
eventos, o al menos el movernos dentro de los eventos y saber "controlarlos" para las cosas que
queramos hacer.
Con el "basic clsico", no haba problemas. Las cosas se producan de forma lineal, es decir empezaban
por el principio del programa y se iban ejecutando a medida que se avanzaba por l. Salvo en las
ocasiones en las que en un momento dado "saltabamos" a otro sitio, pero era porque nosotros as lo
habamos programado. De una forma u otra tenamos control total sobre lo que poda ocurrir. Pero en

Windows (o los entornos dominados por los eventos), la cosa no es tan sencilla.
Debemos controlar todas (o casi) las posibilidades que se pueden producir...
Antes vamos a dejar un par de cosillas claras. Segn como tengas configurado el entorno de desarrollo,
habrs tenido problemas con los ejemplos de la entrega anterior. La razn es que el Visual Basic nos
permite controlar un poco mejor el tema de las variables que queremos usar. Ese control lo da la
instruccin: Option Explicit. Si ponemos esto en la parte destinada a las declaraciones de cualquier
mdulo, nos obligar a declarar las variables que vamos a usar en dicho mdulo.
En el ltimo ejemplo de la entrega anterior, tenamos una variable llamada Nombre, en la cual
almacenamos un nombre, por tanto podramos haberle avisado a Visual Basic que reservara espacio
para una variable, y para hacerlo usamos la instruccin DIM, con sta le indicamos que nos guarde un
"cachillo" de la memoria para nuestro uso:
Dim Nombre
Tambin nos ofrece una variante con respecto al "basic clsico" y es, precisamente, el tipo de
datos variant. Con este tipo podemos asignar a una variable cualquier tipo de dato. Desde un nmero
hasta una cadena de caracteres, psando por cualquier tipo de objeto que Visual Basic pueda manejar
(ms o menos).
Los que hayan tenido experiencias anteriores, con Basic u otro lenguaje, sabrn que cada variable debe
ser del tipo de datos que queramos asignarle. En VB por supuesto esto tambin es posible y
recomendable.
Ya vimos que los tipos de datos podan ser numricos o de caracteres. Pero dentro de los numricos,
tenemos cuatro tipos bsicos: enteros, enteros largos, simples y dobles. Cada uno de ellos tienen unas
capacidades determinadas, adems de ocupar ms memoria o menos, (ahora lo veremos), lo ms
importante es que los nmeros enteros y entero largo slo admiten nmeros enteros (de ah sus
nombres), es decir que no admiten decimales. Sin embargo los otros dos si admiten decimales.
Estas capacidades puedes encontrarlas en el manual del basic o en la ayuda, lo que a mi me interesa
que sepas es cmo poder indicarle al Visual Basic que reserve ese espacio de memoria para un tipo
determinado. Ya te he dicho que el espacio que ocupa en memoria es diferente para cada uno de estos
tipos, veamos en la siguiente tabla cmo declararlos y cuanto ocupa:
Tipo

Espacio ocupado

Tipo de declaracin

Ejemplo

Entero

2 bytes

Integer

Dim Numero As Integer

Entero Largo

4 bytes

Long

Dim Numero As Long

Simple

4 bytes

Single

Dim Numero As Single

Doble

8 bytes

Double

Dim Numero As Double

En el caso de las variables que van a guardar nombres (cadenas de caracteres), se deben declarar como
String y el espacio que ocupa ser 4 bytes ms un byte por cada caracter que tenga, en el caso de VB
de 32 bits realmente ocupar 2 bytes por cada caracter que tenga.
La longitud mxima de una variable del tipo String ser de aproximadamente 32.000 caracteres y la
forma de declararla ser:
Dim Cadena As String
Una vez declarada podemos asignarle la cantidad de caracteres que queramos (sin pasarnos) y cuantas
veces queramos.
Hay que tener en cuenta que en cualquier variable slo se queda el ltimo valor asignado. Ya lo vimos en
la entrega anterior, pero vamos a refrescarlo un poco:
Dim Nmero As Integer
Nmero = 5
Print Nmero
Nmero = 12
Print Nmero
En este ejemplo, el ltimo valor almacenado en Nmero es el 12. El 5 que tena en un principio se perdi.
Pero, que tengo que hacer para sumarle una cantidad al valor almacenado en una variable?
Es decir, cmo incrementar el valor de una variable numrica?
La respuesta la tienes en cmo se manejan las expresiones y las asignaciones a las variables. Como ya
vimos anteriormente, al asignar a una variable una expresin, primero se calcula la expresin y una vez
obtenido el resultado, se asigna a la variable.
Recuerdas lo que ocurra con la variable Paliza? Vamos a verlo de nuevo, pero usando otros nombres
menos "cachondos"

Dim N As Integer
Dim M As Integer
N = 10
M=N*3
Print M
El resultado de este programa sera 30, que es lo que resulta de multiplicar 10 por 3. Cuando se asigna a
la variable M el valor de N (que es 10) multiplicado por 3, el VB toma el contenido de N y lo multiplica por
3. Una vez que sabe la solucin, asigna ese valor, en este caso 30) a la variable que hay a la izquierda
del signo igual.
Sabiendo esto, podriamos simplificar la cosa y hacer los siguiente:
N=N*3
Print N
Tambin obtendriamos 30. Ya que cuando el Basic calcula la expresin de la derecha del signo igual, N
vale 10, una vez obtenido el resultado del clculo lo asigna a la variable de la izquierda del signo de
asignacin, sin importarle lo ms mnimo de que variables es y como en este caso hemos usado la
misma, pues se queda el ltimo valor, perdindose el que originalmente estaba "guardado". Esto es til
cuando necesitamos "contar" de forma secuencial, para as incrementar el valor de una variable.
Ya veremos alguna "utilidad" para estos casos. Ahora vamos a ver cmo podemos manejar las cadenas
de caracteres, es decir las variables de tipo String.
Con estas variables ocurre lo mismo que con las numricas, pero la nica operacin que podemos
realiazar es la suma.
Realmente una suma en una cadena de caracteres es "pegar" dos cadenas en una sola.
Por ejemplo si hacemos esto: N = 3 + 2. El valor obtenido es 5 y eso es lo que se guarda en N.
Sin embargo con los strings hacer esto: Cadena = "A" + "B", se guardar "AB", es decir se unirn las dos
cadenas en una sola. Para este tipo de operacin se recomienda usar mejor el signo &. Que entre otras
cosas le indica al Visual Basic que lo que pretendemos hacer es unir dos cadenas, no sumarlas.
Aunque "tericamente" no se pueden sumar cadenas, slo con-catenarlas, veremos cmo podemos
llegar a producir "problemillas" de entendimiento entre el VB y nuestras "mentes poderosas".
Como te he comentado al principio el tipo de datos Variant acepta de todo, nmeros, nombres, etc.
Si no le indicamos de forma correcta al VB cual es nuestra intencin, podemos confundirle y hacer que el
resultado de algo que nosotros dabamos "por hecho", al final se convierte en un pequeo caos para
nuestras pobres mentes.
Vamos a verlo con un par de ejemplos, en estos casos: (al no indicarle de que tipo son las variables, el
Basic entiende que nuestra intencin es usar el tipo Variant)
Dim Num1
Dim Num2
Num1 = 5
Num2 = 3
Num1 = Num1 + Num2
Print Num1
Que imprimir? Pruebalo y saldrs de duda. Bueno, imprimir un 8.
Ahora veamos este otro ejemplo:
Dim Num1
Dim Num2
Num1 = "5"
Num2 = "3"
Num1 = Num1 + Num2
Print Num1
Fijate que lo que vara es slo las comillas. El resultado en este caso es 53, es decir ha unido las dos
cadenas.
Ahora quita las comillas del 5, para dejarlo as:
Dim Num1
Dim Num2
Num1 = 5

Num2 = "3"
Num1 = Num1 + Num2
Print Num1
Alehop! Que ha pasado? Pues que ha impreso un 8, es decir ha "pasado" de que el tres sea una
cadena de caracteres y lo ha tomado por un nmero...
En esta ocasin, slo vamos a cambiar la lnea de la asignacin para dejarla de esta forma:
Num1 = Num1 & Num2
El resultado ser 53. Porque le hemos indicado que una las dos cadenas, por tanto al encontrase con
esta "operacin" ha considerado al nmero 5 como una cadena, en lugar de un nmero.
Cambia ahora la asignacin del Num2, para que sea: Num2 = 3
Vuelve a mostrar 53, el signo & tiene unos poderes enormes... y a pesar de ser dos nmeros la nica
operacin que puede realizar es la concatenacin de cadenas, por tanto el tipo Variant se convierte por
arte de mgia en cadena.
Pero fijate si es "fuerte" el poder de conviccin que tiene este operador, que aunque cambiemos el tipo
de las variables, sigue "convenciendo" al basic que tipo de operacin debe hacer. Esto no debera ocurrir
as, pero ocurre.
Dim Num1 As Integer
Dim Num2 As Integer
Num1 = 5
Num2 = 3
Num1 = Num1 & Num2
Print Num1
Sigue mostrando 53, aunque en este caso debera producir un error, ya que un Integer no es una
cadena.
As que "cuidadn" con las operaciones que realizamos. Ya que si aades esta lnea:
Print Num1 * 2
vers que realmente Num1 tiene guardado un nmero y el resultado ser: 106
A dnde nos lleva todo esto? A que debemos usar los signos (operadores) de forma adecuada. Y si
nuestra intencin es sumar nmeros, empleemos el signo +, en caso de que queramos unir cadenas de
caracteres, usaremos el &
Para rematar esta segunda entrega, vamos a usar un textbox para que se puedan introducir datos y
empecemos a manejar los eventos, mejor dicho empecemos a "habituarnos" a los eventos.
Aade al form dos Label, un TextBox y un botn de comandos. El aspecto ser algo parecido al de la
siguiente figura:

Aade el siguiente cdigo y despus ejecuta el programa, ya sabes F5. Escribe algo en el cuadro de
texto y pulsa en el botn.

Private Sub Form_Load()


Label2 = ""
Text1 = ""

End Sub
Private Sub Command1_Click()
Label2 = "Hola " & Text1
End Sub
Cuando pulsas F5, se produce el evento Form_Load, por tanto se asigna al Label2 y al Text1 una cadena
vaca, con lo cual borramos el contenido anterior, que es el que se muestra en la Figura.
Hasta que no pulsemos el botn mostrar, no ocurrir nada y el programa estar esperando a que ocurra
algo.
Una vez pulsado el botn, se produce el evento Click del Command1 y se hace lo que se indica en su
interior, que es tomar lo que hay en la caja de texto y unirla a la palabra Hola, para asignarla al Label2.
Ahora, imaginate que quieres mostrar el nombre en maysculas. Lo nico que tendras que hacer es lo
siguiente:

Private Sub Command1_Click()


Label2 = "Hola " & UCase(Text1)
End Sub
Lo que se ha hecho es decirle al VB que convierta en maysculas lo que ya est en Text1. Esa es la
"utilidad" del UCase.
Pero y si quisieramos que conforme se va escribiendo se vayan convirtiendo los caracteres a
maysculas?
Aqu entraran ms instrucciones/funciones del Visual Basic, as cmo otro de los eventos que pone a
nuestra disposicin, en este caso el evento que se produce cada vez que se modifica el contenido del
textbox: Change, escribe lo siguiente:

Private Sub Text1_Change()


Text1 = UCase(Text1)
End Sub
Pruebalo y vers lo que ocurre. Queda "guay" verdad? Pero no es lo que nosotros pretendiamos.
Vamos a intentar remediarlo y de camino vemos nuevas instrucciones/propiedades, en este caso del
TextBox.

Private Sub Text1_Change()


Text1 = UCase(Text1)
Text1.SelStart = Len(Text1)
End Sub
La lnea que se ha aadido (realmente la habrs tecleado t), lo que le indica al Visual Basic es que haga
lo siguiente:
Calcula la longitud del contenido del Text1, (Len cuenta los caracteres de una cadena y lo devuelve como
nmero), SelStart es una propiedad del TextBox que entre otras cosas, le indica la posicin en la que se
insertar el siguiente caracter que se escriba o bien nos puede indicar la posicin actual del cursor. Por
tanto obliga a poner el cursor, (el palico ese que parpadea y que nos indica que podemos escribir), al
final de la ltima letra que contiene el Text1.
Ahora ya sabes que cada vez que "cambie" el Text1, se produce un evento Change.
Pero hay otra forma de hacer esto mismo y es controlando cada tecla que se pulsa. Esto lo podemos
"controlar" en el evento KeyPress, el cual se produce cada vez que se pulsa una tecla. Borra el
procedimiento anterior y escribe este otro:

Private Sub Text1_KeyPress(KeyAscii As Integer)


Dim s As String
s = UCase(Chr(KeyAscii))
KeyAscii = Asc(s)

End Sub
Ahora han entrado dos nuevas funciones en accin: Chr, la cual convierte un nmero en una cadena...
realmente convierte un cdigo ASCII en la letra que representa (busca en la ayuda ASCII y leete lo que
dice en las opciones que te muestra). Por otra parte Asc hace lo contrario, es decir convierte una letra en
el cdigo ASCII. Y lo que nosotros hacemos es: convertir el cdigo de la tecla pulsada, representado por
la variable KeyAscii, en una cadena, la pasamos a maysculas y despus la volvemos a asignar a la
variable, para "engaar" al Visual Basic y as hacerle pensar que realmente hemos tecleado una letra en
maysculas.

Curso Bsico de Programacin


en Visual Basic
Tercera Entrega: 14/Jun/97.
por Guillermo "guille" Som

Bien, despus de un mes y pico, seguimos con la tercera entrega del curso "super-bsico" de
programacin con Visual Basic. Si quieres ver las entregas anteriores, pulsa en los siguientes links: este
para la Primera y este otro para la Segunda.
Esta entrega la voy empezar con recomendaciones e instrucciones del buen hacer en Visual Basic,
espero que sigas algunas, preferiblemente todas, estas normas.
Ya has visto cmo maneja el Visual Basic las variables, si a esta "libertad" (aunque ms bien es
libertinaje), le aadimos que no nos obliga a nada, es decir el VB nos est diciendo: "puedes usar las
variables para lo que quieras, cmo quieras (o casi) y cuando quieras"
Y esto en principio podra parecer una buena cosa, pero realmente es un mal hbito, que muchos de los
que vens del BASIC, ya teneis formado y creo que ahora sera un buen momento para empezar a
cambiar.
Lo primero que debes hacer es ir al men Herramientas (Tools) y en Opciones (Options) marca la casilla
que indica "Requerir declaracin de variables" (Require Variable Declaration), esto aadir a cada nuevo
mdulo (FRM, BAS o CLS) la siguiente instruccin: Option Explicit, de esta forma tendrs la obligacin
de declarar cada una de las variables que uses en el programa. Y tu preguntars: Para que obligar a
que se declaren las variables? La respuesta es bien sencilla: para que las declares... (algunas veces
me asombro de la lgica tan aplastante de mis comentarios)
Bromas aparte, es recomendable que declares las variables que vayas a usar y te dira ms: no slo es
bueno declarar las variables, sino que mejor an es declararlas del tipo adecuado.
Ya vimos que hay diferentes tipos de variables, no slo de tipos genricos como podran ser para
almacenar caracteres y nmeros, sino que dentro de las numricas hay varios tipos, y cada uno de ellos
tiene una razn de ser.
En mis tiempos del BASIC normalito, es decir del MS-DOS, no exista esta obligacin de declarar
"forzosamente" las variables y cuando estabas escribiendo un programa (proyecto que lo llaman ahora),
grande, acababas "invitablemente" usando ms variables de la cuenta porque ya no recordabas si la
variable "i" o "j" estaba siendo usada a nivel global o no... (yo es que con el despiste que gasto, me vea
creando las variables "ii", "j2", etc, para no "meter la pata") y esto no era lo peor, al fin y al cabo lo nico
que ocurra era que estaba "desperdiciando" memoria, por no tener un control de las variables que
estaba usando; lo malo era que se podan escribir errneamente los nombres de las variables de forma
que al final, el programa no funcionaba bien porque al escribir un nombre de variable, habamos
cambiado el nombre... era frustrante y algunas veces te volvas loco buscando el fallo...
La ventaja de usar el Option Explicit, es que si escribes mal una variable, el VB te avisa... bueno,
algunas veces te avisa, sobre todo cuando se encuentra con la variable "mal escrita".

Aqu viene la segunda recomendacin del da: cuando ejecutes un programa, hazlo con Control+F5,
de esta forma se hace una compilacin completa y "ms o menos" exhaustiva del cdigo, avisndote
cuando hay algo que no "cuadra", con el VB3 no haba problemas, ya que siempre se haca la
compilacin completa, pero desde el VB4 se puede pulsar F5 y hasta que no llega al procedimiento
actual, no comprueba si todo lo que hay en l est correcto.
As que para "curarte en salud" procura hacer la compilacin completa
La tercera recomendacin no es obligatoria, siempre que sigas la que voy a dar despus, esta es uan
norma que tambin he usado desde mis tiempos de MS-DOS (aunque reconozco que ltimamente no la
pongo en prctica, ya que hago lo que despus comentar en la cuarta recomendacin).
En todos los mdulos, antes slo eran BAS, pona al principio la siguiente lnea:
DEFINT A-Z
de esta forma le indicaba al BASIC que mi intencin era usar todas las variables del tipo Integer (entero),
(realmente despus usaba del tipo que me daba la gana, pero mi primera intencin era no complicarme
la vida con la mayora de las variables), cuando quera usar una variable diferente de Integer, le indicaba
"explicitamente" de que tipo era y as me obliga a usar la mayora de ellas de este tipo que a la larga es o
era el ms usado, ya que para hacer bucles (ya te explicar en un ratillo que es eso de los bucles y cmo
hacerlos en VB) y otros clculos "normales", era ms que suficiente y en la mayora de los casos: ms
rpido.
En Basic, y por supuesto todava en Visual Basic, aunque cada vez va a menos, se puede indicar el tipo
de una variable de varias formas, al declararlas con Dim, vimos que se haca de la siguiente forma:
Dim unNumero As Integer
Dim unNumeroLargo As Long
Dim otroNumero As Single
Dim masNumeros As Double
Dim unNombre As String
Dim multiUso As Variant
Cada una de estas varibales es de un tipo distinto, las cuatro primeras numricas, la quinta para
almacenar cadenas de caracteres y la ltima del tipo por defecto del VB: Variant que como su nombre
indica (aunque en ingls), es Variante y puede almacenar prcticamente cualquier cosa, objetos
incluidos, (ya veremos los objetos en otra ocasin). Lo del tipo por defecto, es siempre que no se haya
especificado un tipo determinado para todas las variables, por ejemplo usando el DEFINT A-Z, el tipo por
defecto ya no es Variant, sino Integer.
Al grano, "quesnoche", a lo que iba era que adems de declarar las variables de esta forma, tambin se
puede hacer de de esta otra:
Dim unNumero%
Dim unNumeroLargo&
Dim otroNumero!
Dim masNumeros#
Dim unNombre$
En el caso de Variant no existe un caracter especial para indicar que es de ese tipo, as que cuando
quieras usar una varible Variant, tendrs que declararla como en el primer ejemplo.
An queda otro carcter para otro tipo de datos numrico, el tipo Currency que se puede declarar con @.
Estre tipo ocupa 8 bytes y permite guardar nmeros de tipo moneda, es decir nmeros no enteros, pero
con un nmero determinado y fijo de decimales, ahora no recuerdo, pero en la ayuda o en los manuales
podrs ver la "retaila" de nmeros que cada tipo admite.
Para terminar con las recomendaciones de hoy, voy a indicarte algo que debes tener en cuenta cuando
declaras variables y que an los ms expertos caen en la trampa.
Adems de declarar las variables con Dim, poniendo cada declaracin en una lnea, cosa que por otro
lado queda bastante claro y es como suelo hacerlo, aunque ltimamente estoy volviendo a cojer malos
hbitos... ser la edad?
Tambin se pueden declarar ms de una variable con un mismo DIM, vamos a verlo con un ejemplo:
Dim Numero As Integer, NumeroLargo As Long, otroNum As Single, Nombre As String, Numerazo
As Double
por supuesto tambin valdra de esta otra forma:
Dim Numero%, NumeroLargo&, otroNum!, Nombre$, Numerazo#

Y si me apuras, tambin de esta otra:


Dim Numero%, NumeroLargo As Long, otroNum As Single, Nombre$, Numerazo#
Pero sea como fuere, en todos los ejemplos se ha especificado el tipo que queremos asignar.
Por supuesto tambin podremos declarar varibales de esta forma:
Dim unaVariable, otraVariable, terceraVariable
Pero, surge esta pregunta de que tipo son estas tres variables? (al menos se espera que te surja...)
La respuesta es bien sencilla, si se ha entendido toda la "retahila" que te he soltado anteriormente:
Sern del tipo Variant o del especificado con el DEFINT A-Z (es decir Integer)
Voy a suponer que la tercera recomendacin no la ests poniendo en prctica, por tanto seran del tipo
Variant.
Pero fijate que podras caer en el error, sobre todo si has programado algo en C, de pensar que esta
lnea:
Dim Numero, otroNumeroInt, elTercero As Integer
o esta otra:
Dim Numero As Integer, otroNumeroInt, elTercero
estn declarando tres nmeros Integer y no es as, lo que se est declarando sera, en el primer caso:
Numero y otroNumeroInt como Variant y elTercero como entero.
en el segundo caso slo Numero sera del tipo entero y las otras dos variables del tipo Variant.
Sera "ideal" que fuese como aparenta, pero el VB no hace estas "virgueras", ni incluso en la versin 5.
Por tanto, cuando declares variables, fijate bien de que tipo son las que ests declarando, para no
llevarte sorpresas, sobre todo con los redondeos y errores de desbordamiento...
Un desbordamiento se produce cuando asignamos a un nmero un valor mayor del que est capacitado
para almacenar, as si un entero slo acepta valores de +/- 32767 (realmente acepta hasta -32768), al
asignarle un valor de 40000, nos dir que "turur" y dar error.
En cuanto a que tipo de variable usar en cada caso, tendrs que tener en cuenta que quieres hacer.
Normalmente en los bucles se suelen usar variables enteras, bien Integer, si sabemos que no nos vamos
a pasar de 32767, bien Long Integer que puede almacenar un valor de dos mil y pico millones... (quien
los tuviera, aunque fuese en calderilla!)
Vamos a ver un ejemplo (al fin algo de cdigo se escucha entre el pblico...), con este cdigo podrs
comprobar la velocidad de los bucles con los distintos tipos de varibales y as poder comprobar cual es la
ms adecuada.
Crea un nuevo proyecto y asigna unos cuantos Labels (6 en total) y un botn.
Cuando ejecutes este programilla, puedes ir tranquilamente a tomar caf, porque se tomar su tiempo...
En teora nos mostrar el tiempo que emplea en hacer unos bucles con tipos diferentes de datos. Para
que sea fiable, debers especificar unos valores altos, ya que con nmeros pequeos no es demasiado
fiable, e incluso con nmeros altos tampoco... la cosa era poner algo de cdigo para "rematar" el captulo
de hoy...
En la prxima entrega explicar las intrucciones que se han usado y en algunos casos, explicar hasta el
por qu de usarlas.
Osea esto es lo que se dice un programa intil que adems de consumir recursos del sistema y hacernos
perder el tiempo, no vale para nada... (es que despus de probarlo, me he dado cuenta de que o todos
los formatos son prcticamente igual de rpidos o yo he estado "engaado" durante todo este tiempo...)
Option Explicit
Private
Dim
Dim
Dim
Dim
Dim
Dim

Sub Command1_Click()
nInt As Integer
nLng As Long
nSng As Single
nDob As Double
nCur As Currency
nVar As Variant

Dim timer1#, timer2 As Double


Const minBucle = 1, maxBucle = 10
Command1.Caption = "Calculando..."

timer1 = Timer
For nInt = minBucle To maxBucle
Contar CInt(nInt), Label1
Next
timer2 = CDbl(Timer - timer1)
Label1 = "Duracin con Integer: " & timer2
DoEvents
timer1 = Timer
For nLng = minBucle To maxBucle
Contar CInt(nLng), Label2
Next
timer2 = CDbl(Timer - timer1)
Label2 = "Duracin con Long: " & timer2
DoEvents
timer1 = Timer
For nSng = minBucle To maxBucle
Contar CInt(nSng), Label3
Next
timer2 = CDbl(Timer - timer1)
Label3 = "Duracin con Single: " & timer2
DoEvents
timer1 = Timer
For nDob = minBucle To maxBucle
Contar CInt(nDob), Label4
Next
timer2 = CDbl(Timer - timer1)
Label4 = "Duracin con Double: " & timer2
DoEvents
timer1 = Timer
For nCur = minBucle To maxBucle
Contar CInt(nCur), Label5
Next
timer2 = CDbl(Timer - timer1)
Label5 = "Duracin con Currency: " & timer2
DoEvents
timer1 = Timer
For nVar = minBucle To maxBucle
Contar CInt(nVar), Label6
Next
timer2 = CDbl(Timer - timer1)
Label6 = "Duracin con Variant: " & timer2
DoEvents
Command1.Caption = "Calcular"
End Sub
Private Sub Contar(valor As Integer, etiqueta As Control)
Dim i As Integer
Dim unDoble As Double
Const elMaximo = 1000&
For i = 1 To elMaximo
unDoble = unDoble + 1
etiqueta.Caption = valor * elMaximo + unDoble
DoEvents
Next
End Sub

Curso Bsico de Programacin


en Visual Basic
Cuarta Entrega: 4/Jul/97.
por Guillermo "guille" Som
Estos son los links a las entregas anteriores, si no te las has leido, peor pa ti, pero deberas leertelas.
La Primera, la Segunda y la Tercera.

Buenaaas, aqu estamos de nuevo (tu, yo y mi otro yo), empiezo con correcciones, ya sabes, fallos que
tiene uno, y otras aclaraciones.
El primero es un fallo garrafal, que gracias a Antonio Banderas, al que le tengo que agradecer tambin
otras cosas, que espero que vaya en beneficio de los que estais leyendo todas estas cosas sobre el VB,
(si, aparte de nosotros tres hay otros que siguen este curso). Bueno, a lo que iba, que siempre me
despisto... en la segunda entrega, en el ltimo ejemplo de Num1, Num2, la asignacin: Num1 = Num1 +
Num2, debera ser: Num1 = Num1 & Num2 (s que te habrs dado cuenta del detalle, sobre todo por la
explicacin posterior), este "desliz" ya est corregido, as que si lo has leido despus del 30 de Junio (del
97), ya est como tena que estar.
La siguiente aclaracin, es un despiste, no demasiado grande, ya que doy por hecho de que algo habrs
leido sobre VB, bien los manuales, bien la Ayuda o algn libro sobre este lenguaje. Pues la cosa consiste
que en la tercera entrega se crea un procedimiento: Contar, para crear procedimientos o funciones,
tienes que usar el men Insert y seleccionar Procedure (esto en VB4), en VB3 si no recuerdo mal, estaba
en el men "View" y en VB5 est en Tools (Herramientas)
Bien, hechas estas aclaraciones, voy a explicar, tengo que hacerlo, ya que me compromet y... lo
prometido es deuda o eso dicen, a saber...
Antes del cdigo hice este comentario:
Osea esto es lo que se dice un programa intil que adems de consumir recursos del sistema y
hacernos perder el tiempo, no vale para nada... (es que despus de probarlo, me he dado cuenta de que
o todos los formatos son prcticamente igual de rpidos o yo he estado "engaado" durante todo este
tiempo...)
Y la cosa es que antes de hacer este ejemplo, yo crea que algunos tipos de datos eran ms rpidos
que otros, (y a pesar de que el ejemplo demuestra, o casi, lo contrario, sigo creyendolo...). La cosa es
que en 32 bits un Long debera ser ms rpido que el resto. Y los enteros ms rpidos que los de coma
flotante... voy a probarlo en un 386 sin copro, a ver... ahora vuelvo...
Ya puestos a probar, he probado, aqu se demuestra lo "morruo" (o cabezn) que soy, y en esta
tabla (pulsando en el link), tienes los diferentes valores en distintos equipos y con distintas versiones de
VB.
Vers que sorprecilla te llevas... Lo has visto?
Dejar este tema, que ya es mucho lo que le he dedicado, vamos a ver el programa y as cambiamos de
tercio...
Para introducir cdigo en cualquiera de los eventos de los controles o del formulario, lo nico que tienes
que hacer es seleccionar el control y el evento que queremos codificar de las listas desplegables, en el

mdulo de cdigo, pulsando en Cdigo en la ventana en la que se muestra los mdulos y formularios que
forma un proyecto. En la lista de la izquierda seleccionamos el control y en el de la derecha nos mostrar
todos los eventos soportados por VB para ese control. Si sabemos el nombre del control y el del evento,
podemos teclearlo directamente o bien si copiamos cdigo de otro sitio, simplemente con pegarlo, se va
a su sitio.
En el caso de querer aadir al cdigo, una funcin o procedimiento se puede hacer de varias formas, lo
acabo de decir, pero lo repito un poco ms claro:

1.

Directa: Escribir el cdigo directamente, con lo cual se crear un nuevo "apartado" en la lista de
las funciones/ procedimientos. En caso de que no sea un evento soportado por los controles de
nuestro formulario, se mostrar en la lista de la izquierda, estando seleccionada en la derecha
"General"

2.

Copiar/Pegar: Pues eso, si copias una funcin/procedimiento y lo pegas en la ventana de


cdigo...

3.

Por men de VB: Segn las distintas versiones de VB, ser un men u otro, debers especificar
el nombre del procedimiento o la funcin, marcando la casilla correspondiente. En VB4/VB5
vers que aparte de los Procedimientos (Sub) y las Funciones (Function) hay tambin
Propiedades (Property), estas las veremos en otra ocasin. Tambin vers que puedes
declararlas Pblicas o Privadas. Esto no es posible en VB3, al menos en los procedimientos y
funciones de los formularios.

En otra ocasin veremos todas estas cosas y con ejemplos, que es lo que "mola".
Bueno, toda esta "retahila" vena a cuento de cmo introducir cdigo en los eventos de los controles o
del formulario y cmo crear nuetras propias instrucciones (esto es lo que ms me gust del QuickBasic
4.0, poder crear mis propias instrucciones (subs) y funciones).
Ya es hora de coger el listado de la entrega anterior y "destriparlo". Vamos a ver cada cosa por separado,
que aunque parezca que es mucho cdigo, realmente est "repetido", o casi...
Option Explicit
Esto nos obliga a declarar todas las variables que usemos en el mdulo, ponerlo es una recomendacin,
incluso te la impondra como norma. Para que salga de forma automtica en cada nuevo mdulo,
selecciona del men Tools/Advanced la opcin Declare variables required (o algo parecido, que viene a
significar Requiere la declaracin de variables)
Siguiendo nuestro recorrido por el cdigo, no encontramos con:
Private Sub Command1_Click()
Lo de Private significa que slo se puede acceder a este procedimiento desde dentro del mdulo en el
que est declarado. Es decir no se puede llamar desde otro form o mdulo BAS.
Sub indica que es un procedimiento, no una funcin, ni una propiedad. Los Subs actuan como
intrucciones propias del lenguaje. Las funciones tambin, pero devuelven un valor, mientras que los subs
no devuelven nada, lo que cogen se los quedan ellos, aunque en su momento veremos que tambin nos
pueden dar algo a cambio.
Command1_Click, este es el nombre que habr que usar para acceder a l desde cualquier punto de
ste mdulo.
Los parntesis sin nada dentro, indica que este procedimiento no recibe parmetros; los parmetros lo
veremos dentro de un "ratillo"
Toda esta lnea es la descripcin del procedimiento y cuando se le llame, bien desde nuestro propio
cdigo, bien porque se pulse sobre el botn, se ejecutar todo lo que est dentro de l. El final del
procedimiento est marcado por End Sub.
Las lneas con DIM indican que estamos declarando las variables y lo que se especifica despus
del AS es el tipo de variable, los cinco primeros son de cada uno de los tipos numricos soportados (otro
da veremos otro tipo cuasi-numrico), el sexto es Variant, el multi-uso, el que vale para todo.

Veamos ahora que es lo que se hace con esta lnea:


Dim timer1#, timer2 As Double
Aqu he declarado dos variables del tipo Double. Al separarlas con comas no hay que repetir la
palabra DIM, pero s el tipo de cada variable. Ya vimos en la entrega anterior que algunos tipos de
variables se podan indicar mediante unos caracteres especiales, (estos tipos son los heredados de
versiones anteriores al Visual Basic 2, en esa versin, se introdujo el tipo Variant), en este caso # es lo
mismo que Double, por tanto se podra haber hecho tambin de cualquiera de estas tres formas:
Dim timer1#, timer2#
Dim timer1 As Double, timer2#
Dim timer1 As Double, timer2 As Double
Ahora fijate que esta otra no hara la misma tarea:
Dim timer1, timer2 As Double
Esto funcionara con lenguajes como el C, (realmente el tipo se pone delante), pero en Basic no declara
las dos variables como Double. La segunda variable si es Double, pero la primera es del tipo por defecto,
en nuestro caso Variant.
As que mucho ojito con las declaraciones de las variables. En algn sitio, no voy a decir dnde, porque
lo mismo fu un "lapsus" del autor, pero deca que de esta forma declaraba tres variables Integer: Dim i,
j, k As Integer
Sigamos nuestra andadura, ahora veamos esta declaracin/asignacin:
Const minBucle = 1, maxBucle = 10
Aqu lo que se declaran son dos constantes, stas a diferencia de las variables, no pueden cambiar de
valor, de ah su nombre, por tanto permanecern siempre con el mismo valor. Cuando se declara una
constante, no es necesario especificar el tipo, VB se encarga de adivinarlo y usar el tipo adecuado,
realmente lo que hace es sustituir estas "palabras" por el valor que hay despus del signo igual. En caso
de hacer esto: cNombre = "Una palabra". Visual Basic sabe que es una cadena de caracteres y cada
vez que se encuentre con cNombre lo sustituir por "Una palabra".
Ahora viene la explicacin del "por qu" usar constantes. Adems de "esclarecer" los listados, los hace
ms fciles de comprender, tambin nos permite modificar un valor en un slo sitio, con lo que ganamos
en "confianza", al asegurarnos de que no omitiremos alguno de los sitios dnde tengamos o queramos
cambiar el valor antiguo por uno nuevo.
En nuetro ejemplo, minBucle y maxBucle se usan en seis partes diferentes del procedimiento, si
quisieras probar con otros valores, tendras que cambiar en seis sitios esos valores, pero al declararlos
como constantes, slo cambiando el valor asignado, tenemos todo el trabajo hecho. Esto adems de ser
ms fiable y legible, nos puede ahorrar algn que otro quebradero de cabeza y si adems le aadimos
que no ocupan espacio extra, salvo en la tabla de smbolos, una vez compilado el programa slo se
"compilarn" las constantes usadas. Sin embargo con las variables no ocurre esto, ya que aunque no se
usen, ocupan memoria.
Un inciso, esto de explicar tan detalladamente los listados, no va a ser norma, ya que al final todos nos
aburriramos, slo lo har cuando lo crea conveniente o bien si lo solicitas, en este caso, no tendr ms
remedio que cumplir tus deseos...
Command1.Caption = "Calculando..."
Cambiamos el texto mostrado en el botn, para avisarnos de que est haciendo algo...
timer1 = Timer
Asignamos el valor de la funcin Timer a la primera de las dos variables que usaremos para calcular el
tiempo empleado por cada uno de los bucles. Esta funcin devuelve el nmero de segundos
transcurridos desde la media noche.
For nInt = minBucle To maxBucle
Esto es un bucle, que se repetir desde minBucle (1) hasta maxBucle (10) y la variable nInt es la que
llevar la cuenta o la que se usar para saber el valor actual del bucle.
Deberamos ver primero la declaracin del procedimiento Contar, para entender lo que hace la lnea que
viene despus del For.
Private Sub Contar(valor As Integer, etiqueta As Control)
Declaramos un procedimiento privado llamado Contar (acta como una instruccin ms del VB, ya que
no representa a ningn control ni evento), entre los parntesis estn declarados los dos parmetros que
espera recibir en la llamada, el primero es un nmero entero y el segundo (separado por una coma), un

Control, que puede ser cualquier control de VB.


El resto del procedimiento ahora no es demasiado significativo
Ahora veamos esta lnea:
Contar CInt(nInt), Label1
Contar es el nombre del procedimiento y a continuacin se deben indicar los parmetros que espera
recibir. En este caso no sera necesario CINT ya que lo que hace esta funcin es convertir el nmero que
se pone dentro de los parntesis en un nmero entero y como resulta que nInt es un nmero entero...
pues no hay nada que convertir!
El segundo parmetro es el control Label1, ya sabes que tenemos 6 etiquetas en nuestro programa
desde Label1 a Label6
Cuando llegue estos datos al procedimiento Contar, valor tomar lo que valga nInt y etiqueta se
aduear de Label1.
Next
Continua repitiendo el bucle hasta que se alcance el valor mximo, realmente el Next lo que hace es lo
siguiente:
nInt = nInt + 1
Es nInt menor o igual que maxBucle? Si la respuesta es SI, sigue con lo que haya despus de la lnea
FOR, en caso negativo contina con la lnea siguiente al Next (realmente en la siguiente instruccin
despus del Next, ya veremos esto en otra ocasin)
timer2 = CDbl(Timer - timer1)
Asignamos a la segunda variable que usamos para el clculo del tiempo la diferencia entre el nuevo valor
de los segundos transcurridos desde la media noche (Timer) y el valor que tena timer1, es decir cuantos
segundos... antes de empezar el bucle.
El CDBL es una fucin que devuelve un valor Doble. Es decir hace la resta y ese valor resultante lo
convierte en doble.
Label1 = "Duracin con Integer: " & timer2
Esta asignacin realmente es Label1.Caption, si se omite la propiedad, Visual Basic usa la que tiene por
defecto, que segn los manuales, suele ser la propiedad que se usa con ms frecuencia. En este caso el
Caption, es decir lo que se muestra en la etiqueta.
DoEvents
Esta es una instruccin "controvertida" y a la que muchos programadores no les hace demasiada gracia
usar, no porque no tenga su utilidad, sino porque hay que saber realmente lo que hace y tener cuidado
cuando la usamos, ya que algunas veces puede crear errores o confusin... relmente no es tan drstico,
pero casi...
DoEvents, detiene la ejecucin del programa y devuelve el control a Windows, para que ejecute los
mensajes que tiene pendientes en la cola de mensajes... ? no te preocupes si no te enteras, es as y
punto. por qu la uso? Pues para dar tiempo a que se vea el contenido del Label; prueba a quitarla y
vers lo que ocurre, o debera ocurrir... que ya a estas alturas no me sorprendera nada que se
mostrara...
El resto del programa es idntico a este bucle, pero usando distintas variables y las dems etiquetas. El
caso es que Contar espera una variable de nmero entero y un control, en el caso del control es obvio
que se estn poniendo las distintas etiquetas y en el caso del nmero se convierte a entero, porque eso
es lo que espera nuestra instruccin y si no lo hacemos as, se quejar.
Ya slo queda ver una lnea del procedimiento Contar:
etiqueta.Caption = valor * elMaximo + unDoble
unDoble contar desde 1 hasta elMaximo, en cada vuelta del bucle, se asignar al caption de la etiqueta
pasada al procedimiento y el DoEVents que viene a continuacin se encargar de que se muestre ese
contenido. Bueno, tambin se asigna valor * elMaximo, es decir que cuando valor valga 1, se estar
mostrando 1000 + unDoble, realmente para hacer un contador se tendra que haber usado lo siguiente:
etiqueta.Caption = (valor -1) * elMaximo + unDoble, para que mostrara desde el 1, en lugar de
empezar desde el 1001.
Una vez que Contar termina, por el End Sub, vuelve el control al bucle que lo llam y se ejecuta la
siguiente instruccin. Por tanto Contar se llamar tantas veces como dure el bucle en el que se
encuentra.

Creo que queda todo ms o menos claro y aunque este cdigo no es muy til por s, ha servido para ver
algunas cosillas del VB.
Para terminar vamos a ver una serie de cambios y a ver si adivinais que es lo que hace... as os servir
de ejercicio, cosa que algunos me habeis pedido, pero que an no es el momento de hacerlos.
En las declaraciones generales aade esta declaracin:
Dim Contando As Integer
En Contar, aade lo siguiente despus del DoEvents:
If Contando = 0 Then Exit For
Al principio del Command1_Click, aade estas lneas:

If Contando Then
Command1.Caption = "Calcular"
Contando = 0
DoEvents
Exit Sub
End If
Contando = 1
En cada uno de los bucles, pon esto despus de llamar a Contar...
If Contando = 0 Then Exit Sub
Y antes del End Sub aade esto otro:
Command1.Caption = "Calcular"
Contando = 0
Bueno, ah dejo esto y como ejercicio podras aadir dos controles TextBox para especificar los valores
de maxBucle y elMaximo, de forma que segn los valores introducidos, que por defecto deben ser 10 y
1000, se usen los que especifiques en cada TextBox y se tengan en cuenta cuando pulsas (haces click)
en el botn.
Como pista te dir que las variables usadas y/o declaradas dentro de un procedimiento son slo visibles
dentro de ese procedimiento. No te quejars del "pedazo" de pista que te he dado...

Curso Bsico de Programacin


en Visual Basic
Quinta Entrega: 26/Jul/97.
por Guillermo "guille" Som
Te recomiendo que leas las entregas anteriores, aqu tienes los links:
La Primera, la Segunda, la Tercera y la Cuarta.

Hoy no voy a pasar lista, porque me imagino que los que faltan estarn aprovechando el puente este de
Santiago o estarn preparando las maletas para irse de vacaciones... que suerte! Quin pudiera estar
en la costa! con las playas "abarrotadas" de gente... j, j... yo no estoy de vacaciones, pero tengo la
playa a menos de 50 metros de mi casa...

...que no se te pongan los dientes largos y limpiate las babas... para tu consuelo te dir que an no he
pisado la arena de la playa... O 8-|
Vale, vale, tambin puedes irte al campo con los mosquitos... se nota que me gusta ms la playa? y que
conste que la sierra que tenemos por esta zona es una maravilla... no, no soy del Patronato de Turismo...
Bueno, una vez dado un "repaso" veraniego, vamos al cdigo, que es lo que te ha traido a esta pgina.
Hoy no tengo nada que rectificar de la entrega anterior... salvo varios errores tipogrficos... De todas
formas si lees estas entregas y hay posteriores, sera conveniente que fueses a la siguiente y te leyeras
el principio, ya que aparte de poner algn comentario "chorra", suelo dar un repaso a los "errores" de la
entrega anterior.
Ahora viene el contenido real de la quinta entrega.
No voy a dar la solucin al problema/ejercicio planteado en la entrega anterior, voy a dejar que la
deduzcas. Para que tengas base suficiente, te voy a contar un poco cmo funciona el Visual Basic y por
extensin todas las aplicaciones de Windows.
En la segunda entrega creamos un programa que mostraba un form en el que teniamos una caja de
texto (TextBox), un botn (CommandButton) y dos etiquetas (Label).
Cuando, despus de pulsar F5 o CRTL+F5, se ejecuta la aplicacin, de lo nico que podemos tener
certeza es que se ejecutar el cdigo que se encuentra en el procedimiento Form_Load. Este
procedimiento (sub) en concreto es lo que se llama un evento, y se produce cada vez que el formulario
(form) se carga (load) en la memoria. Antes de entrar en detalles del porqu podemos tener la certeza de
que ese cdigo se va a ejecutar, tengo que seguir con mi 'ponencia' de cmo funcionan las aplicaciones
Windows.
Se dice, (otros lo dicen y yo me lo creo), que Windows es un sistema o entorno operativo 'dominado' por
los eventos. Esto ya lo dej caer al principio de la segunda entrega. En Windows cada vez que movemos
el ratn, pulsamos una tecla, tocamos una ventana o cualquiera de los controles que estn en ellas, se
produce un evento. Cuando se 'dispara', (los anglosajones usan 'fire' para indicar que se produce el
evento), uno de estos eventos, Windows le dice al form, (de forma bastante rpida, aunque en algunas
ocasiones no tanto como nos hubiera gustado), que se ha movido el ratn y que el ratn ha pasado por
encima de tal ventana o de ese control y as con todas las cosas. La verdad, no es de extraar que de
vez en cuando falle el sitema, es que no para de disparar!!! y algunos disparos se le puede escapar y...
...que chiste ms malo, verdad? Ya pensabas que el comentario ese del 'fire' era porque "el Guille se
cree que est traduciendo un artculo de VB Online"...
Lo que quiero dejar claro es que a diferencia de los lenguajes que funcionan en MS-DOS, en Windows
no podemos 'predecir' cual ser el cdigo que se va a ejecutar. No debes 'planificar' tu programa dando
por sentado que... "despus de esto el usuario 'tiene' que hacer esto otro y as yo podr hacer una
comprobacin para..." NO ! Aqu (en Windows) no existe la programacin lineal, no des nunca por
hecho que esto es lo que va a ocurrir..., porque casi con toda seguridad no ocurrir!
Veremos cmo podemos 'controlar' que algunas cosas se hagan cuando nosotros queramos, pero esto
ser slo cuando el usuario de nuestra aplicacin realice una 'accin' que estaba prevista; tambin
codificaremos para que se ejecute parte del cdigo cuando el usuario no haga lo que habamos previsto
que hiciera. Pero eso lo iremos viendo poco a poco...
Todo programa de Windows tiene un punto de entrada; en el caso de Visual Basic, puede ser bien un
formulario o bien un procedimiento de un mdulo BAS, (de debe llamarse obligatoriamente Main); los
mdulos los veremos en otra ocasin.
Normalmente las aplicaciones suelen tener ms de un formulario y algn que otro mdulo. Pero tenga
uno o ciento, siempre hay un nico punto de entrada (o de inicio). Por regla general suele ser un
formulario. En nuestro ejemplo slo tenemos un form en el proyecto, por tanto no hay duda alguna de
cual ser el punto de entrada del programa.
Perdona si me extiendo en esto, pero tanto si t lo sabes como si no, creo que t ahora lo sabes... (es
difcil esto de escribir una cosa para tanta gente con distintos niveles...)
Cuando Windows inicia el programa, 'debe' cargar el formulario en la memoria. Y desde el momento que
se prepara para hacerlo, ya est con los 'tiritos' y mandando 'mensajes' a la ventana (todo formulario es
una ventana), pero no slo le est avisando a la nuestra que la accin ha empezado, sino que lo hace
prcticamente a los cuatro vientos; si otra aplicacin quiere enterarse de lo que ocurre en Windows, slo
tiene que conectarse a la 'mensajera' de ste entorno operativo y leer las 'noticias'... pero esto ya es
complicarse la vida y todava no nos la vamos a complicar tanto... o ms... (pensar alguno despus de

respirar aliviado...)
Lo que ahora interesa es saber que el 'evento' Form_Load se produce cuando esta ventana pasa del
anonimato a la vida pblica, aunque no la veamos, estar en la memoria de Windows y se producir el
primer evento del que tenemos 'certeza', por tanto este es un buen sitio para poner cdigo de
inicializacin.
Realmente el Form_Load no es lo primero que puede ocurrir al iniciarse un formulario, pero por ahora
vamos a pensar que s; porque sino esta entrega no la termino hasta despus del verano... que me
gusta darle vueltas a las cosas!!!
Ahora que se ha cargado el form en la memoria... que ocurrir? Pues, si el usuario se va a tormar unas
caas: nada. Slo ocurrir algo cuando interactuemos con el form, es decir, le demos razones a Windows
para 'pegar tiritos'.
Nuestra aplicacin, (te recuerdo que tena, entre otras cosas, un textbox y un botn), esperar a que se
produzca algunas de las acciones para las que est preparada.
Y la pregunta es que es lo que puede ocurrir? Para saber 'todas' las cosas que pueden ocurrir en
nuestra ventana, (no recuerdo si has pulsado F5 o no), finaliza el programa y muestra la ventana de
cdigo.
En la parte superior de la ventana hay dos listas desplegables, la de la izquierda tiene todos los
controles, (en otra ocasin veremos que no siempre es as), que tenemos en el form, incluido ste,
adems de uno especial que se llama General.
Pulsa en la lista de la izquierda, para que se despliegue y te mostrar esto:

Estos son los cinco controles, incluyendo el form, que pueden recibir mensajes de Windows. Pulsa en
cualquiera de ellos. En la lista de la decha estn todos los procedimientos (eventos) soportados por el
control de la izquierda. Cada control mostrar los eventos que VB y/o Windows permite que se
produzcan. Estos ocurrirn por distintos motivos, cada uno tiene su 'tarea', nos pueden avisar de que se
ha pulsado el ratn, que se acaba de pulsar una tecla, que se ha modificado lo que antes haba, etc.
Una llamada a la precaucin.
Los eventos son 'procedimientos' y no slo se puede llegar a ellos porque se produzca una accin del
usuario o del propio Windows y si me apuras, incluso de Visual Basic... Nosotros podemos 'provocarlos'
cmo? simplemente haciendo una llamada al SUB que queramos o actuando en el control de manera
que ocurra alguno de los eventos soportados.
Por ejemplo, en el Form_Load tenemos que se asignan cadenas vacias tanto al Label2 como al Text1:
Label2 = ""
Text1 = ""
Cuando VB asigna una cadena vaca (o cualquier otra cosa), al Label2 est borrando el contenido del
'Caption' de esta etiqueta y asignando algo nuevo, es decir lo est cambiando. En nuestro programa no
ocurre nada, salvo que se borra lo que all hubiera, pero realmente se est produciendo el evento
Label2_Change, porque hemos cambiado el contenido. VB sabe que no hemos escrito cdigo para
manejar esta situacin, asi que... hace la vista gorda y simplemente cambia el contenido del
Label2.Caption sin hacer nada ms.
Pero al asignar una cadena vaca al Text1, tambin se borra el contenido y se produce un Change, slo
que en este caso, al no tener Caption, lo que se borra es el Text; de todas formas sea como fuere, se
produce el evento Text1_Change. Nuestro querido amigo Visual Basic, sabe que hemos escrito cdigo
para este evento y sabe que tiene que hacer lo que all se dice...
En este caso, nuestro cdigo se ejecuta, pero realmente no hace nada de inters o por lo menos nada
que se pueda apreciar de forma visual. No voy a explicar para que sirve ese cdigo, porque ya lo hice en
su da, lo que espero es que hoy lo entiendas mejor...
Cmo? que no sabes de qu cdigo estoy hablando... pues del ejemplo de la segunda entrega, creo
que ya lo dije al principio... a ver si prestamos ms atencin y dejamos de pensar en las vaciones...
estos nios!

El cdigo interesante es el que se ejecuta cuando se pulsa en el botn:


Label2 = "Hola " & Text1
Aqu se asigna al Caption del Label2 lo que hay despus del signo igual, en este caso acta 'casi' como
una variable. Y ya sabrs que antes de asignar un valor a una variable, se procesa todo lo que est
despus del signo igual, por tanto, Visual Basic tomar el contenido del Text1, es decir lo que se haya
escrito y lo unir (&) a la palabra "Hola ", una vez hecho esto, lo almacena en el Caption del Label2.
Y si en lugar de guardarlo en un control label, lo asignaramos a una variable... y si en lugar de escribir
nuestro nombre, escribiesemos un nmero... y si la variable en la que guardamos ese nmero se
llamara, por ejemplo, maxBucle o elMaximo...
Pues que tendramos una parte resuelta de la tarea esa que puse como ejercicio en la entrega anterior.
Pero, este form de la segunda entrega no nos sirve. Tendremos que cargar el de la vez pasada y aadirle
un par de cajas de textos y un par de etiquetas, para que indique lo que se debe introducir en cada
textbox; el aspecto sera este:

Pero nos encontramos con un problema: cmo puedo asignar un valor a maxBucle, si las constantes no
pueden cambiar de valor? Fcil, conviertela en variable. Pero debes recordar la pista que di al final: "Las
variables declaradas dentro de un procedimiento son solamente visible dentro de ese procedimiento".
De este tipo de variables se dice que son locales.
Alumno: Que significa esto?
Guille: Que slo pueden usarse dentro del procedimiento en el que se han DIMensionado o declarado.
A: Vale, "mu bonito" y que pasa?
G: Esto... que no pueden usarse en otro sitio...
Recuerdas la recomendacin de usar Option Explicit?
Pues gracias a Option Explicit, se solucionan el 99% de los fallos 'involuntarios' con las variables... y no
exagero!!!
Es super-fcil escribir de forma incorrecta el nombre de una 'bariable' y no vengas con el cuento de que a
t nunca te ocurre, porque no me lo voy a creer... bueno, de t si, pero no todos son tan minuciosos como
t...
(para que nadie se sienta ofendido/a, quiero que veas en esto que acabo de poner... la intencin que
tiene, es decir que me dirijo a ms de un "ti"... ya s que no eres tan torpe como para no haberlo
'captado', pero con esta aclaracin me quedo ms tranquilo.)
Segn cmo y dnde se declare una variable, su 'visibilidad' o rea de cobertura, ser diferente...
tambin se puede usar la palabra mbito... es que como en las emisoras de radio se habla de la
cobertura... pues...
Una variable puede tener estas coberturas:
--Privada o Local a nivel de procedimiento (Sub, Function, etc.)
--Privada o Local a nivel de mdulo (FRM, BAS, etc.)
--Pblica o Global a nivel de aplicacin (en este tipo hay una forma especial de usar las variables que
veremos en otra ocasin)
Explicando los dos primeros puntos.
Cuando declaramos o dimensionamos una variable 'dentro de' un procedimiento, sta slo es visible en
ese procedimiento; fuera de l no es conocida y cualquier uso que se intente hacer de ella, producir un
error... si has sido obediente y has usado el Option Explicit. En caso de que no hayas puesto la
'obligacin' de declarar todas las variables, te llevars una sorpresa de que no tiene el valor esperado.

A: JA!
G: No te lo crees? Vale. Vamos a comprobarlo.
Abre un proyecto nuevo, pon un textbox y un botn..
Abre la ventana de cdigo, borra el Option Explicit.
En el Form_Load haz esta asignacin: Incredulo = "No me lo creo"
En el Command1_Click escribe esto otro: Text1 = Incredulo
Pulsa F5 y haz click en el botn...
Que ha pasado?
(Tengo que comprobarlo, para no meter la pata, pero se supone que el texto se borrar sin poner nada...)
Bien, eso ocurre porque la variable usada en el Form_Load no tiene nada que ver con la usada en el
Command1_Click.
Con esto comprobamos o demostramos que podemos tener variables diferentes con el mismo nombre.
La nica condicin es que no pueden estar juntas, aunque hay un truco para juntarlas sin que ellas se
enteren...
En este ltimo ejemplo, nuestra intencin es tener una variable que sea 'conocida' en todo el form.
Cuando necesitemos variables con un mbito a nivel de mdulo, tenemos que declararla o dimensionarla
en la seccin de las declaraciones generales; ya sabes, en la lista izquierda de la ventana de cdigo
seleccionas General y en la de la derecha Declarations ( Declaraciones).
Muestra la ventana de cdigo y en General/Declaraciones escribe:
Option Explict 'retornamos a las buenas costumbres
Dim Incredulo As String
Pulsa F5 para ejecutar el programa, pulsa en el botn y... AHORA SI!
Tenemos una variable que puede ser 'vista' en todo el form. Ya puedes usar 'Incredulo' donde quieras,
ahora siempre ser la misma variable y contendr lo ltimo que se le haya asignado.
A partir de la versin 4 del VB, entra en juego una nueva palabra, 'Private', que suele usarse en las
declaraciones de las variables a nivel de mdulo, de esta forma es ms fcil entender la intencin de la
misma; por tanto la declaracin anterior podemos hacerla tambin as:
Private Incredulo As String
Hay veces, sobre todo si ya has programado antes en MS-DOS, que usamos variables como a, b, c, i, j,
k...etc., (al menos yo estoy acostumbrado a llamar i, j, k a las variables que uso en los bucles FOR),
cuando hago un bucle dentro de un procedimiento uso i como variable ndice, (o variable 'contadora'),
pero que ocurre si esta 'costumbre' quiero aplicarla en varios procedimientos? Pues que dimensiono
una variable i en cada uno de ellos y aqu no ha pasado nada!!!
Usar el mismo nombre de variable en distrintos procedimientos
Como indica el encabezado de este nuevo prrafo, cosa que ya he comentado antes, podemos tener
distintas variables con el mismo nombre en distintos procedimientos; para ello, slo hay que
dimensionarlas y el VB las almacenar en distintas posiciones de la memoria para que no se 'mezclen'.
En la entrega anterior, teniamos un procedimiento llamado Contar que se usaba para eso, contar...
En este ejemplo vamos a usar un sub tambin llamado contar, para ver en accin todo esto que estoy
diciendo.
Situate en la parte General/Declarations de la ventana de cdigo y escribe o "copia/pega" lo siguiente:

Private Sub Contar()


Dim i As Integer
For i = 1 To 2
Print "i en contar= "; i
Next
End Sub
Ahora en el Form_Load, escribe esto otro:

Dim i As Integer
Show
For i = 1 To 3
Print "i en el Form_Load= "; i

Contar
Next
Ejecuta el programa y ...
Has visto lo que ocurre... A pesar de que ambas variables tienen el mismo nombre, son diferentes. La
variable i del Form_Load no es la misma que la variable i de Contar.
Cuando usamos variables locales es como si cambiasemos el nombre y se llamaran
NombreProcedimiento_Variable.
S que puede ser una forma 'rebuscada' de explicarlo, pero asi te haces una idea.
Todas las variables declaradas en un procedimiento, slo son visibles en ese procedimiento. Si has
usado QuickBasic o el compilador Basic de Microsoft (que usaba el QuickBasic Extended QBX), esto ya
exista y tambin exista la forma de hacer que una variable declarada en un procedimiento, fuese visible
fuera de l; para ello declarabas la variable como Shared (compartida); pero en VB eso NO EXISTE. La
nica forma de compartir una variable es declarndola en la seccin General de las declaraciones.
Prueba ahora esto. Sustituye el procedimiento Contar por este otro:

Private Sub Contar(j As Integer)


Dim i As Integer
For i = 1 To j
Print "i en contar= "; i
Next
End Sub
Aqu hacemos que Contar reciba un parmetro y el valor que recibe lo usamos como el lmite final del
bucle For, es decir contar desde UNO hasta el valor de j.
Sustituye la llamada a Contar del Form_Load por esta:

Contar i
Le damos a Contar el parmetro i. Por tanto cada vez que se llame a este procedimiento le estamos
diciendo que i es el valor mximo que tomar el bucle For que tiene dentro.
Cmo reaccionar? Se confundir? ...
No, no voy a dejarlo para la siguiente entrega, es tan obvio que lo voy a explicar ahora mismo:
Al procedimiento Contar le da igual que se use una varibale llamada i o cualquier otra, incluso un
nmero. Lo nico que necesita y espera, es recibir un valor numrico (del tipo Integer) y lo asignar a la
variable j. Por tanto no ocurrir nada extrao. Ejecuta el programa y fijate en lo que ocurre. S que lo has
deducido, eso est bien... vas aprendiendo... 8-)
Cmo? Que t an no lo has captado? Pues dimelo...
Otra cosa sera pretender usar una variable declarada a nivel de mdulo, dentro del procedimiento, que
tuviese el mismo nombre.
Si te has quedado 'con la copla', tu mismo sabrs la respuesta... Efectivamente! Si dentro de un
procedimiento tenemos una variable dimensionada con el mismo nombre de una declarada a nivel de
mdulo o a nivel global, (para usarla en cualquier sitio de la aplicacin), tendr 'preferencia' la variable
local... sta 'tapar', ocultar o como prefieras decirlo a cualquier otra variable del mismo nombre...
En la prxima entrega veremos ms casos y cosas de las variables. Comprobaremos cmo usarlas a
nivel Global. Pero por ahora vamos a terminar con el programa que tenamos planteado en la entrega
anterior:
Aunque relamente deberas saber cmo solucionarlo...
Lo que seguramente no sabrs, es cmo hacer que estas variables tomen el valor...
De acuerdo, lo explicar. Carga el ejemplo de la cuarta entrega.
Hay varias soluciones a este problema; una sera usar variables locales, esta decisin no 'justifica' el
'pedazo' de pista que te di... pero esto es lo que hay.
La lnea Const minBucle = 1, maxBucle = 10. Debe quedar asi:

Const minBucle = 1
Dim maxBucle As Integer

Esto har que maxBucle deje de ser una constante y pase a ser una variable, con lo cual podremos
asignarle cualquier valor.
Pero, cmo le asignamos el valor?
Vamos a dar por sentado que lo que se escriba en el Text1 ser el valor que debe tener maxBucle;
entonces lo nico que haremos es asignar a maxBucle lo que se escriba en el Text1...
Vale, pero dnde?
Pues... por ejemplo, despus de la declaracin, asi que en la siguiente lnea al Dim maxBucle... escribe
los siguiente:

maxBucle = Text1
Esto en teora no dara problemas, al menos en condiciones normales, ya que el contenido de un textbox
es del tipo Variant y ya vimos que un Variant puede almacenar cualquier cosa, por tanto si es un nmero
'intentar' convertir al tipo de la variable que recibir el valor.
Esto no siempre funciona, sobre todo si el contenido del Text1 no es numrico. Por ahora vamos a
hacerlo simple, si el usuario (en este caso t), escribe algo no numrico lo vamos a considerar CERO... o
casi...
Cambia la asignacin anterior por esta otra...
ALTO !!! Antes de hacerlo, pruebalo e intenta escribir una palabra en lugar de un nmero... que
ocurre?
Pues que VB no se complica la vida y te dice que 'nones'... (realmente dice Type Mismatch... Error de
Tipos, es decir que lo que has escrito no es capaz de convertirlo a Integer)... as que escribe esto otro:
maxBucle = Val(Text1)
Con esto lo que hacemos es convertir el contenido del Text1 a un VALor numrico y lo asignamos en la
variable...
Problemas? Que el valor sea mayor del que se puede guardar en un Integer, pero eso ya no es asunto
de esta entrega...
Ahora nos queda convertir elMaximo en variable y asignarle el valor que hay en el Text2. Efectivamente!
hacemos lo mismo, slo que esta vez dentro del procedimiento Contar, por tanto la declaracin Const
elMaximo = 1000&, la tienes que quitar y poner estas dos lneas:

Dim elMaximo As Integer


elMaximo = Val(Text2)
Aqu el nico inconveniente es que esta asignacin se hace cada vez que se entra en este
procedimiento... y eso, amigo mio, no es un buen estilo de programacin... Sobrecargamos de forma
innecesaria al procesador... ten en cuenta que la conversin a nmero y la asignacin se ejecuta cada
vez que se entra en Contar!!!
Lo mejor para este caso sera declarar elMaximo como variable a nivel de mdulo. Por tanto, borra el
Dim elMaximo... del sub Contar y colocalo en la parte de las declaraciones generales del form.
Ahora... dnde asignamos el valor para evitar la sobre-carga? Ya que tenemos la variable a nivel de
mdulo, sta ser 'vista' en todos los procedimientos del formulario, por tanto lo lgico sera hacerlo en el
Command1_Click, ya que cuando nos interesa a nosotros saber cuanto tenemos que contar es
precisamente cuando pulsamos en el botn...
Pero... dnde exactamente?, despus de Contando = 1
Bien, ahora est la cosa mejor... haz tus pruebas y si an no lo tienes claro... preguntame.
Prcticas y ejercicios
Quieres algo para practicar?
Este ejercicio se lo pona a mis alumnos, cuando daba clases de BASIC, hace ya unos 10 aos o ms...
y consista en pedir el nombre, pedir la edad y mostrar el nombre tantas veces como aos tengamos...
Claro que con el BASIC del MS-DOS era ms directo y se sabia cuando se debia empezar a mostrar el
nombre, para solventar esto, se mostrar el nombre 'edad' veces cuando se pulse en un botn. El
aspecto del form sera algo as:

No creo que sea complicado, as que vamos a complicarlo un poco ms:


Mostrar el nombre 'edad' veces, dentro de un label, para ello el label deber ocupar la parte izquierda del
form.
Y una tercera versin, sera lo mismo que esta ltima, pero cada vez que se muestre el nombre se haga
en una lnea diferente.
La pista: En la segunda entrega vimos de pasada el CHR. Pues decirte que si aadimos a una variable
un CHR(13), lo que hacemos es aadirle un retorno de carro, es decir lo que venga despus se mostrar
en la siguiente lnea... siempre que se 'concatene'. Tambin existe una constante definida en VB4 o
superior que es vbCrLf, esto es un retorno de carro (Cr) y un cambio de lnea (Lf)

Curso Bsico de Programacin


en Visual Basic
Quinta Entrega: 26/Jul/97.
por Guillermo "guille" Som
Te recomiendo que leas las entregas anteriores, aqu tienes los links:
La Primera, la Segunda, la Tercera y la Cuarta.

Hoy no voy a pasar lista, porque me imagino que los que faltan estarn aprovechando el puente este de
Santiago o estarn preparando las maletas para irse de vacaciones... que suerte! Quin pudiera estar
en la costa! con las playas "abarrotadas" de gente... j, j... yo no estoy de vacaciones, pero tengo la
playa a menos de 50 metros de mi casa...
...que no se te pongan los dientes largos y limpiate las babas... para tu consuelo te dir que an no he
pisado la arena de la playa... O 8-|
Vale, vale, tambin puedes irte al campo con los mosquitos... se nota que me gusta ms la playa? y que
conste que la sierra que tenemos por esta zona es una maravilla... no, no soy del Patronato de Turismo...
Bueno, una vez dado un "repaso" veraniego, vamos al cdigo, que es lo que te ha traido a esta pgina.
Hoy no tengo nada que rectificar de la entrega anterior... salvo varios errores tipogrficos... De todas
formas si lees estas entregas y hay posteriores, sera conveniente que fueses a la siguiente y te leyeras
el principio, ya que aparte de poner algn comentario "chorra", suelo dar un repaso a los "errores" de la
entrega anterior.
Ahora viene el contenido real de la quinta entrega.
No voy a dar la solucin al problema/ejercicio planteado en la entrega anterior, voy a dejar que la
deduzcas. Para que tengas base suficiente, te voy a contar un poco cmo funciona el Visual Basic y por
extensin todas las aplicaciones de Windows.

En la segunda entrega creamos un programa que mostraba un form en el que teniamos una caja de
texto (TextBox), un botn (CommandButton) y dos etiquetas (Label).
Cuando, despus de pulsar F5 o CRTL+F5, se ejecuta la aplicacin, de lo nico que podemos tener
certeza es que se ejecutar el cdigo que se encuentra en el procedimiento Form_Load. Este
procedimiento (sub) en concreto es lo que se llama un evento, y se produce cada vez que el formulario
(form) se carga (load) en la memoria. Antes de entrar en detalles del porqu podemos tener la certeza de
que ese cdigo se va a ejecutar, tengo que seguir con mi 'ponencia' de cmo funcionan las aplicaciones
Windows.
Se dice, (otros lo dicen y yo me lo creo), que Windows es un sistema o entorno operativo 'dominado' por
los eventos. Esto ya lo dej caer al principio de la segunda entrega. En Windows cada vez que movemos
el ratn, pulsamos una tecla, tocamos una ventana o cualquiera de los controles que estn en ellas, se
produce un evento. Cuando se 'dispara', (los anglosajones usan 'fire' para indicar que se produce el
evento), uno de estos eventos, Windows le dice al form, (de forma bastante rpida, aunque en algunas
ocasiones no tanto como nos hubiera gustado), que se ha movido el ratn y que el ratn ha pasado por
encima de tal ventana o de ese control y as con todas las cosas. La verdad, no es de extraar que de
vez en cuando falle el sitema, es que no para de disparar!!! y algunos disparos se le puede escapar y...
...que chiste ms malo, verdad? Ya pensabas que el comentario ese del 'fire' era porque "el Guille se
cree que est traduciendo un artculo de VB Online"...
Lo que quiero dejar claro es que a diferencia de los lenguajes que funcionan en MS-DOS, en Windows
no podemos 'predecir' cual ser el cdigo que se va a ejecutar. No debes 'planificar' tu programa dando
por sentado que... "despus de esto el usuario 'tiene' que hacer esto otro y as yo podr hacer una
comprobacin para..." NO ! Aqu (en Windows) no existe la programacin lineal, no des nunca por
hecho que esto es lo que va a ocurrir..., porque casi con toda seguridad no ocurrir!
Veremos cmo podemos 'controlar' que algunas cosas se hagan cuando nosotros queramos, pero esto
ser slo cuando el usuario de nuestra aplicacin realice una 'accin' que estaba prevista; tambin
codificaremos para que se ejecute parte del cdigo cuando el usuario no haga lo que habamos previsto
que hiciera. Pero eso lo iremos viendo poco a poco...
Todo programa de Windows tiene un punto de entrada; en el caso de Visual Basic, puede ser bien un
formulario o bien un procedimiento de un mdulo BAS, (de debe llamarse obligatoriamente Main); los
mdulos los veremos en otra ocasin.
Normalmente las aplicaciones suelen tener ms de un formulario y algn que otro mdulo. Pero tenga
uno o ciento, siempre hay un nico punto de entrada (o de inicio). Por regla general suele ser un
formulario. En nuestro ejemplo slo tenemos un form en el proyecto, por tanto no hay duda alguna de
cual ser el punto de entrada del programa.
Perdona si me extiendo en esto, pero tanto si t lo sabes como si no, creo que t ahora lo sabes... (es
difcil esto de escribir una cosa para tanta gente con distintos niveles...)
Cuando Windows inicia el programa, 'debe' cargar el formulario en la memoria. Y desde el momento que
se prepara para hacerlo, ya est con los 'tiritos' y mandando 'mensajes' a la ventana (todo formulario es
una ventana), pero no slo le est avisando a la nuestra que la accin ha empezado, sino que lo hace
prcticamente a los cuatro vientos; si otra aplicacin quiere enterarse de lo que ocurre en Windows, slo
tiene que conectarse a la 'mensajera' de ste entorno operativo y leer las 'noticias'... pero esto ya es
complicarse la vida y todava no nos la vamos a complicar tanto... o ms... (pensar alguno despus de
respirar aliviado...)
Lo que ahora interesa es saber que el 'evento' Form_Load se produce cuando esta ventana pasa del
anonimato a la vida pblica, aunque no la veamos, estar en la memoria de Windows y se producir el
primer evento del que tenemos 'certeza', por tanto este es un buen sitio para poner cdigo de
inicializacin.
Realmente el Form_Load no es lo primero que puede ocurrir al iniciarse un formulario, pero por ahora
vamos a pensar que s; porque sino esta entrega no la termino hasta despus del verano... que me
gusta darle vueltas a las cosas!!!
Ahora que se ha cargado el form en la memoria... que ocurrir? Pues, si el usuario se va a tormar unas
caas: nada. Slo ocurrir algo cuando interactuemos con el form, es decir, le demos razones a Windows
para 'pegar tiritos'.
Nuestra aplicacin, (te recuerdo que tena, entre otras cosas, un textbox y un botn), esperar a que se
produzca algunas de las acciones para las que est preparada.
Y la pregunta es que es lo que puede ocurrir? Para saber 'todas' las cosas que pueden ocurrir en
nuestra ventana, (no recuerdo si has pulsado F5 o no), finaliza el programa y muestra la ventana de
cdigo.

En la parte superior de la ventana hay dos listas desplegables, la de la izquierda tiene todos los
controles, (en otra ocasin veremos que no siempre es as), que tenemos en el form, incluido ste,
adems de uno especial que se llama General.
Pulsa en la lista de la izquierda, para que se despliegue y te mostrar esto:

Estos son los cinco controles, incluyendo el form, que pueden recibir mensajes de Windows. Pulsa en
cualquiera de ellos. En la lista de la decha estn todos los procedimientos (eventos) soportados por el
control de la izquierda. Cada control mostrar los eventos que VB y/o Windows permite que se
produzcan. Estos ocurrirn por distintos motivos, cada uno tiene su 'tarea', nos pueden avisar de que se
ha pulsado el ratn, que se acaba de pulsar una tecla, que se ha modificado lo que antes haba, etc.
Una llamada a la precaucin.
Los eventos son 'procedimientos' y no slo se puede llegar a ellos porque se produzca una accin del
usuario o del propio Windows y si me apuras, incluso de Visual Basic... Nosotros podemos 'provocarlos'
cmo? simplemente haciendo una llamada al SUB que queramos o actuando en el control de manera
que ocurra alguno de los eventos soportados.
Por ejemplo, en el Form_Load tenemos que se asignan cadenas vacias tanto al Label2 como al Text1:
Label2 = ""
Text1 = ""
Cuando VB asigna una cadena vaca (o cualquier otra cosa), al Label2 est borrando el contenido del
'Caption' de esta etiqueta y asignando algo nuevo, es decir lo est cambiando. En nuestro programa no
ocurre nada, salvo que se borra lo que all hubiera, pero realmente se est produciendo el evento
Label2_Change, porque hemos cambiado el contenido. VB sabe que no hemos escrito cdigo para
manejar esta situacin, asi que... hace la vista gorda y simplemente cambia el contenido del
Label2.Caption sin hacer nada ms.
Pero al asignar una cadena vaca al Text1, tambin se borra el contenido y se produce un Change, slo
que en este caso, al no tener Caption, lo que se borra es el Text; de todas formas sea como fuere, se
produce el evento Text1_Change. Nuestro querido amigo Visual Basic, sabe que hemos escrito cdigo
para este evento y sabe que tiene que hacer lo que all se dice...
En este caso, nuestro cdigo se ejecuta, pero realmente no hace nada de inters o por lo menos nada
que se pueda apreciar de forma visual. No voy a explicar para que sirve ese cdigo, porque ya lo hice en
su da, lo que espero es que hoy lo entiendas mejor...
Cmo? que no sabes de qu cdigo estoy hablando... pues del ejemplo de la segunda entrega, creo
que ya lo dije al principio... a ver si prestamos ms atencin y dejamos de pensar en las vaciones...
estos nios!
El cdigo interesante es el que se ejecuta cuando se pulsa en el botn:
Label2 = "Hola " & Text1
Aqu se asigna al Caption del Label2 lo que hay despus del signo igual, en este caso acta 'casi' como
una variable. Y ya sabrs que antes de asignar un valor a una variable, se procesa todo lo que est
despus del signo igual, por tanto, Visual Basic tomar el contenido del Text1, es decir lo que se haya
escrito y lo unir (&) a la palabra "Hola ", una vez hecho esto, lo almacena en el Caption del Label2.
Y si en lugar de guardarlo en un control label, lo asignaramos a una variable... y si en lugar de escribir
nuestro nombre, escribiesemos un nmero... y si la variable en la que guardamos ese nmero se
llamara, por ejemplo, maxBucle o elMaximo...
Pues que tendramos una parte resuelta de la tarea esa que puse como ejercicio en la entrega anterior.
Pero, este form de la segunda entrega no nos sirve. Tendremos que cargar el de la vez pasada y aadirle
un par de cajas de textos y un par de etiquetas, para que indique lo que se debe introducir en cada
textbox; el aspecto sera este:

Pero nos encontramos con un problema: cmo puedo asignar un valor a maxBucle, si las constantes no
pueden cambiar de valor? Fcil, conviertela en variable. Pero debes recordar la pista que di al final: "Las
variables declaradas dentro de un procedimiento son solamente visible dentro de ese procedimiento".
De este tipo de variables se dice que son locales.
Alumno: Que significa esto?
Guille: Que slo pueden usarse dentro del procedimiento en el que se han DIMensionado o declarado.
A: Vale, "mu bonito" y que pasa?
G: Esto... que no pueden usarse en otro sitio...
Recuerdas la recomendacin de usar Option Explicit?
Pues gracias a Option Explicit, se solucionan el 99% de los fallos 'involuntarios' con las variables... y no
exagero!!!
Es super-fcil escribir de forma incorrecta el nombre de una 'bariable' y no vengas con el cuento de que a
t nunca te ocurre, porque no me lo voy a creer... bueno, de t si, pero no todos son tan minuciosos como
t...
(para que nadie se sienta ofendido/a, quiero que veas en esto que acabo de poner... la intencin que
tiene, es decir que me dirijo a ms de un "ti"... ya s que no eres tan torpe como para no haberlo
'captado', pero con esta aclaracin me quedo ms tranquilo.)
Segn cmo y dnde se declare una variable, su 'visibilidad' o rea de cobertura, ser diferente...
tambin se puede usar la palabra mbito... es que como en las emisoras de radio se habla de la
cobertura... pues...
Una variable puede tener estas coberturas:
--Privada o Local a nivel de procedimiento (Sub, Function, etc.)
--Privada o Local a nivel de mdulo (FRM, BAS, etc.)
--Pblica o Global a nivel de aplicacin (en este tipo hay una forma especial de usar las variables que
veremos en otra ocasin)
Explicando los dos primeros puntos.
Cuando declaramos o dimensionamos una variable 'dentro de' un procedimiento, sta slo es visible en
ese procedimiento; fuera de l no es conocida y cualquier uso que se intente hacer de ella, producir un
error... si has sido obediente y has usado el Option Explicit. En caso de que no hayas puesto la
'obligacin' de declarar todas las variables, te llevars una sorpresa de que no tiene el valor esperado.
A: JA!
G: No te lo crees? Vale. Vamos a comprobarlo.
Abre un proyecto nuevo, pon un textbox y un botn..
Abre la ventana de cdigo, borra el Option Explicit.
En el Form_Load haz esta asignacin: Incredulo = "No me lo creo"
En el Command1_Click escribe esto otro: Text1 = Incredulo
Pulsa F5 y haz click en el botn...
Que ha pasado?
(Tengo que comprobarlo, para no meter la pata, pero se supone que el texto se borrar sin poner nada...)
Bien, eso ocurre porque la variable usada en el Form_Load no tiene nada que ver con la usada en el
Command1_Click.
Con esto comprobamos o demostramos que podemos tener variables diferentes con el mismo nombre.
La nica condicin es que no pueden estar juntas, aunque hay un truco para juntarlas sin que ellas se
enteren...

En este ltimo ejemplo, nuestra intencin es tener una variable que sea 'conocida' en todo el form.
Cuando necesitemos variables con un mbito a nivel de mdulo, tenemos que declararla o dimensionarla
en la seccin de las declaraciones generales; ya sabes, en la lista izquierda de la ventana de cdigo
seleccionas General y en la de la derecha Declarations ( Declaraciones).
Muestra la ventana de cdigo y en General/Declaraciones escribe:
Option Explict 'retornamos a las buenas costumbres
Dim Incredulo As String
Pulsa F5 para ejecutar el programa, pulsa en el botn y... AHORA SI!
Tenemos una variable que puede ser 'vista' en todo el form. Ya puedes usar 'Incredulo' donde quieras,
ahora siempre ser la misma variable y contendr lo ltimo que se le haya asignado.
A partir de la versin 4 del VB, entra en juego una nueva palabra, 'Private', que suele usarse en las
declaraciones de las variables a nivel de mdulo, de esta forma es ms fcil entender la intencin de la
misma; por tanto la declaracin anterior podemos hacerla tambin as:
Private Incredulo As String
Hay veces, sobre todo si ya has programado antes en MS-DOS, que usamos variables como a, b, c, i, j,
k...etc., (al menos yo estoy acostumbrado a llamar i, j, k a las variables que uso en los bucles FOR),
cuando hago un bucle dentro de un procedimiento uso i como variable ndice, (o variable 'contadora'),
pero que ocurre si esta 'costumbre' quiero aplicarla en varios procedimientos? Pues que dimensiono
una variable i en cada uno de ellos y aqu no ha pasado nada!!!
Usar el mismo nombre de variable en distrintos procedimientos
Como indica el encabezado de este nuevo prrafo, cosa que ya he comentado antes, podemos tener
distintas variables con el mismo nombre en distintos procedimientos; para ello, slo hay que
dimensionarlas y el VB las almacenar en distintas posiciones de la memoria para que no se 'mezclen'.
En la entrega anterior, teniamos un procedimiento llamado Contar que se usaba para eso, contar...
En este ejemplo vamos a usar un sub tambin llamado contar, para ver en accin todo esto que estoy
diciendo.
Situate en la parte General/Declarations de la ventana de cdigo y escribe o "copia/pega" lo siguiente:

Private Sub Contar()


Dim i As Integer
For i = 1 To 2
Print "i en contar= "; i
Next
End Sub
Ahora en el Form_Load, escribe esto otro:

Dim i As Integer
Show
For i = 1 To 3
Print "i en el Form_Load= "; i
Contar
Next
Ejecuta el programa y ...
Has visto lo que ocurre... A pesar de que ambas variables tienen el mismo nombre, son diferentes. La
variable i del Form_Load no es la misma que la variable i de Contar.
Cuando usamos variables locales es como si cambiasemos el nombre y se llamaran
NombreProcedimiento_Variable.
S que puede ser una forma 'rebuscada' de explicarlo, pero asi te haces una idea.
Todas las variables declaradas en un procedimiento, slo son visibles en ese procedimiento. Si has
usado QuickBasic o el compilador Basic de Microsoft (que usaba el QuickBasic Extended QBX), esto ya
exista y tambin exista la forma de hacer que una variable declarada en un procedimiento, fuese visible
fuera de l; para ello declarabas la variable como Shared (compartida); pero en VB eso NO EXISTE. La
nica forma de compartir una variable es declarndola en la seccin General de las declaraciones.

Prueba ahora esto. Sustituye el procedimiento Contar por este otro:

Private Sub Contar(j As Integer)


Dim i As Integer
For i = 1 To j
Print "i en contar= "; i
Next
End Sub
Aqu hacemos que Contar reciba un parmetro y el valor que recibe lo usamos como el lmite final del
bucle For, es decir contar desde UNO hasta el valor de j.
Sustituye la llamada a Contar del Form_Load por esta:

Contar i
Le damos a Contar el parmetro i. Por tanto cada vez que se llame a este procedimiento le estamos
diciendo que i es el valor mximo que tomar el bucle For que tiene dentro.
Cmo reaccionar? Se confundir? ...
No, no voy a dejarlo para la siguiente entrega, es tan obvio que lo voy a explicar ahora mismo:
Al procedimiento Contar le da igual que se use una varibale llamada i o cualquier otra, incluso un
nmero. Lo nico que necesita y espera, es recibir un valor numrico (del tipo Integer) y lo asignar a la
variable j. Por tanto no ocurrir nada extrao. Ejecuta el programa y fijate en lo que ocurre. S que lo has
deducido, eso est bien... vas aprendiendo... 8-)
Cmo? Que t an no lo has captado? Pues dimelo...
Otra cosa sera pretender usar una variable declarada a nivel de mdulo, dentro del procedimiento, que
tuviese el mismo nombre.
Si te has quedado 'con la copla', tu mismo sabrs la respuesta... Efectivamente! Si dentro de un
procedimiento tenemos una variable dimensionada con el mismo nombre de una declarada a nivel de
mdulo o a nivel global, (para usarla en cualquier sitio de la aplicacin), tendr 'preferencia' la variable
local... sta 'tapar', ocultar o como prefieras decirlo a cualquier otra variable del mismo nombre...
En la prxima entrega veremos ms casos y cosas de las variables. Comprobaremos cmo usarlas a
nivel Global. Pero por ahora vamos a terminar con el programa que tenamos planteado en la entrega
anterior:
Aunque relamente deberas saber cmo solucionarlo...
Lo que seguramente no sabrs, es cmo hacer que estas variables tomen el valor...
De acuerdo, lo explicar. Carga el ejemplo de la cuarta entrega.
Hay varias soluciones a este problema; una sera usar variables locales, esta decisin no 'justifica' el
'pedazo' de pista que te di... pero esto es lo que hay.
La lnea Const minBucle = 1, maxBucle = 10. Debe quedar asi:

Const minBucle = 1
Dim maxBucle As Integer
Esto har que maxBucle deje de ser una constante y pase a ser una variable, con lo cual podremos
asignarle cualquier valor.
Pero, cmo le asignamos el valor?
Vamos a dar por sentado que lo que se escriba en el Text1 ser el valor que debe tener maxBucle;
entonces lo nico que haremos es asignar a maxBucle lo que se escriba en el Text1...
Vale, pero dnde?
Pues... por ejemplo, despus de la declaracin, asi que en la siguiente lnea al Dim maxBucle... escribe
los siguiente:

maxBucle = Text1
Esto en teora no dara problemas, al menos en condiciones normales, ya que el contenido de un textbox
es del tipo Variant y ya vimos que un Variant puede almacenar cualquier cosa, por tanto si es un nmero
'intentar' convertir al tipo de la variable que recibir el valor.
Esto no siempre funciona, sobre todo si el contenido del Text1 no es numrico. Por ahora vamos a
hacerlo simple, si el usuario (en este caso t), escribe algo no numrico lo vamos a considerar CERO... o
casi...
Cambia la asignacin anterior por esta otra...

ALTO !!! Antes de hacerlo, pruebalo e intenta escribir una palabra en lugar de un nmero... que
ocurre?
Pues que VB no se complica la vida y te dice que 'nones'... (realmente dice Type Mismatch... Error de
Tipos, es decir que lo que has escrito no es capaz de convertirlo a Integer)... as que escribe esto otro:
maxBucle = Val(Text1)
Con esto lo que hacemos es convertir el contenido del Text1 a un VALor numrico y lo asignamos en la
variable...
Problemas? Que el valor sea mayor del que se puede guardar en un Integer, pero eso ya no es asunto
de esta entrega...
Ahora nos queda convertir elMaximo en variable y asignarle el valor que hay en el Text2. Efectivamente!
hacemos lo mismo, slo que esta vez dentro del procedimiento Contar, por tanto la declaracin Const
elMaximo = 1000&, la tienes que quitar y poner estas dos lneas:

Dim elMaximo As Integer


elMaximo = Val(Text2)
Aqu el nico inconveniente es que esta asignacin se hace cada vez que se entra en este
procedimiento... y eso, amigo mio, no es un buen estilo de programacin... Sobrecargamos de forma
innecesaria al procesador... ten en cuenta que la conversin a nmero y la asignacin se ejecuta cada
vez que se entra en Contar!!!
Lo mejor para este caso sera declarar elMaximo como variable a nivel de mdulo. Por tanto, borra el
Dim elMaximo... del sub Contar y colocalo en la parte de las declaraciones generales del form.
Ahora... dnde asignamos el valor para evitar la sobre-carga? Ya que tenemos la variable a nivel de
mdulo, sta ser 'vista' en todos los procedimientos del formulario, por tanto lo lgico sera hacerlo en el
Command1_Click, ya que cuando nos interesa a nosotros saber cuanto tenemos que contar es
precisamente cuando pulsamos en el botn...
Pero... dnde exactamente?, despus de Contando = 1
Bien, ahora est la cosa mejor... haz tus pruebas y si an no lo tienes claro... preguntame.
Prcticas y ejercicios
Quieres algo para practicar?
Este ejercicio se lo pona a mis alumnos, cuando daba clases de BASIC, hace ya unos 10 aos o ms...
y consista en pedir el nombre, pedir la edad y mostrar el nombre tantas veces como aos tengamos...
Claro que con el BASIC del MS-DOS era ms directo y se sabia cuando se debia empezar a mostrar el
nombre, para solventar esto, se mostrar el nombre 'edad' veces cuando se pulse en un botn. El
aspecto del form sera algo as:

No creo que sea complicado, as que vamos a complicarlo un poco ms:


Mostrar el nombre 'edad' veces, dentro de un label, para ello el label deber ocupar la parte izquierda del
form.
Y una tercera versin, sera lo mismo que esta ltima, pero cada vez que se muestre el nombre se haga
en una lnea diferente.
La pista: En la segunda entrega vimos de pasada el CHR. Pues decirte que si aadimos a una variable
un CHR(13), lo que hacemos es aadirle un retorno de carro, es decir lo que venga despus se mostrar
en la siguiente lnea... siempre que se 'concatene'. Tambin existe una constante definida en VB4 o
superior que es vbCrLf, esto es un retorno de carro (Cr) y un cambio de lnea (Lf)

Curso Bsico de Programacin


en Visual Basic
Sexta Entrega: 11/Ago/97.
por Guillermo "guille" Som
Si quieres linkar con las otras entregas, desde el ndice lo puedes hacer

Solucin de los ejercicios de la Quinta Entrega


Pulsa este link para ver la solucin de los ejercicios de la quinta entrega (aunque el nombre la pgina
sea: basico06_sol)
Como hemos visto en el apndice de la entrega anterior, la instruccin IF... THEN... nos permite tomar
decisiones segn el valor de una variable o el resultado de una expresin. En esta entrega veremos
como sacarle rendimiento a esta instruccin.
Pero antes de entrar en detalles, veamos cmo podemos decirle al Basic que haga las cosas. En
realidad vamos a ver la forma en que se le puede decir que las haga...
Forma de especificar las instrucciones en Visual Basic
Las instrucciones en Basic no tienen porqu estar cada una en una lnea. Se pueden escribir varias
instrucciones en la misma lnea, pero separndo cada una de ellas con el signo : (dos puntos).
Cuando VB encuentra los dos puntos, deja de 'interpretar' la instruccin y pasa a la accin, una vez
traducido a su lenguaje interno, toma lo que hay despus del signo : y sigue su camino en busca de
ms instrucciones o el final de la lnea.
Veamoslo de forma prctica:
Nombre = "Pepe" : Print Nombre
Esta lnea tiene dos instrucciones: una asignacin y una instruccin Print.
Podemos poner cuantas instrucciones queramos, separadas con los dos puntos.
Pero, (siempre hay un pero), si una de las instrucciones es el IF/THEN la cosa puede cambiar...
Ya vimos que IF comprueba la expresin que viene a continuacin, si es cierta, ENTONCES procesa lo
que haya despus de THEN. En caso de ser en la misma lnea, interpretar todas las instrucciones que
estn a continuacin; en caso de ser un bloque IF... THEN... END IF, ejecutar todo lo que est dentro de
ese bloque. Ahora bien, si la expresin es falsa pasa a la siguiente lnea, tanto si es o no un bloque. En el
caso del bloque la siguiente lnea a interpretar ser la que est despus de END IF.
En los tiempos del BASIC interpretado de MS-DOS, era habitual encontrar las lneas con varias
instrucciones separadas por dos puntos. En mi caso, cuando empec a usar el QuickBasic 2.0 y al poder
usar bloques IF... THEN... END IF, fui dejando a un lado el "mogolln" de instrucciones en la misma
lnea... Ahora prcticamente y salvo contadas excepaciones, escribo cada instruccin en una lnea.
Despus de este pequeo respiro, veamos cmo estara formada una lnea de VB para usar con un IF...
THEN...
[instrucciones:] IF <expresin> THEN <instrucciones si es cierto [:ms
instrucciones...]>
A continuacin de THEN podemos incluir cuantas instrucciones queramos, separadas por dos puntos.
Estas slo se ejecutarn cuando la expresin sea cierta. Si el resultado de la expresin es falso, se obvia
'todo' lo que hay despus de THEN y se pasa a la siguiente lnea.
Espero que lo hayas asimilado y que no te indigestes con lo siguiente...
Pero, (...), existe otra instruccin que PUEDE acompaar al IF... THEN... y es para los casos en los
cuales el resultado de la expresin sea FALSO.
Si, ya s que dije que cuando es falso se pasa a la siguiente lnea, pero eso es cuando no se usa la
clusula ELSE.

Con sta, la definicin de la instruccin "tomadora de decisiones" quedara as:


IF <expresin> THEN <si se cumple> ELSE <si no se cumple>
Tanto en <si se cumple> como en <si no se cumple> pondremos tantas instrucciones como
queramos, (separadas por dos puntos).
Pero no te recomiendo que lo hagas, es preferible, al menos para darle "claridad" a nuestro cdigo, usar
el bloque:

IF <expresin> THEN
<si se cumple>
ELSE
<si no se cumple>
END IF
S que esto puede ocupar ms lneas de cdigo, pero nuestro "coco" lo agradecer, ya que es ms fcil
de comprender, sino veamos un ejemplo:

IF numero > limite THEN


Print "tu nmero es grande"
ELSE
Print "OK, McKey!"
END IF
Ahora veamoslo en una sla lnea:
IF numero > limite THEN Print "tu nmero es grande" ELSE Print "OK, McKey!"
En este ejemplo, an queda claro, pero lo podramos complicar con ms instrucciones para ambos
casos, es decir, para cuando la expresin es cierta y tambin cuando es falsa.
En los tiempos del BASIC que venan incorporados con los ordenadores, cada lnea del programa haba
que numerarla, ya que todo lo que se escriba sin nmero de lnea, se ejecutaba inmediatamente; al igual
que ocurre con lo que se escribe en la ventana Inmediate del Visual Basic.
Los nmeros de lneas se usaban, adems de porque era obligatorio, para cambiar el orden de
ejecucin, sobre todo despus de una comparacin. De esta forma, an sin tener bloques
IF/THEN/ELSE/END IF, se podan simular.
Cmo se lograba?
Usando una instruccin que muchos creen que es "indecente, antisocial, etc"
La estrella del Basic: (redoble de tambores) "GOTO"
A partir de hoy, ms de un purista de la programacin no me dirigir la palabra... pero no me importa...
Se ha "denostado" (injuriado) con exageracin el uso de esta instruccin. Realmente es una instruccin
de "bifurcacin", es decir, sirve para "IR A" otro sitio de nuestro programa.
Su uso ha sido el ms criticado de los NO PARTIDARIOS del Basic y siempre han basado sus crticas en
el exagerado uso del GOTO en todos los programas Basic. Pero aclaremos que C tambin tiene esta
instruccin y que cualquier programa en cdigo mquina (ensamblador) est "plagado" de JMP que para
el caso es lo mismo que el sufrido GOTO, realmente una instruccin GOTO nmero_linea se convierte
en JMP nmero_linea.
No voy a recomendar el uso del GOTO, para nada, ya que hoy da es innecesario su uso. Antes no
tenamos ms remedio, porque el BASIC no dispona de instrucciones para poder estructurar el cdigo.
Pero sera una tontera querer hacer creer que no existe esta instruccin. Sabiendo que est y cmo
podemos evitarla, es preferible a decir que no existe y si por casualidad la descubres... a que la uses.
Por tanto, insisto en mi recomendacin, (de esta forma los PURISTAS volvern a dirigirme la palabra),
NO USES EL GOTO, ni an cuando creas que no tienes ms remedio... aunque, aqu entre nosotros,
algunas veces es ms cmodo usarlo... pero que no se entere nadie...
Este es un programa de los de antes, sirve para mostrar en pantalla los nmeros del 1 al 10 y sin usar el
FOR/NEXT

10 A = 1
20 Print A

30 A = A + 1
40 IF A <= 10 THEN GOTO 20
'Con el Commodore este programa se sola escribir as:
10 A=1
20 PRINTA:A=A+1:IFA<=10GOTO20
'Sin ESPACIOS NI NADA... TODO APELMAZADO... que ms daba usar el
GOTO?
Imagine there's no heaven... (es que est sonando J.Lennon... un momento...)
En este ejemplo, es obvio que podramos sustituirlo con:

10 For A = 1 To 10
20
Print A
30 Next
El NEXT hace lo mismo que la asignacin y la comparacin.
Pero hay otras maneras, para ello existe una serie de instrucciones que funcionan de manera similar,
veamos otros ejemplos con ms instrucciones para hacer bucles, seguir usando los nmeros de lnea
por aquello de la "nostalgia", pero salvo en el primer ejemplo, en los dems no es necesario.

10 A = 1
20 While A <= 10
30
Print A
40
A = A + 1
50 Wend
El WHILE/WEND ya casi ni se usa, porque tienen un sustituto ms verstil, ahora lo veremos, pero el uso
sera:
WHILE <expresin>
<instrucciones si se cumple>
WEND
Es decir, MIENTRAS la expresin sea cierta, repite todo lo que haya hasta el WEND.
Por supuesto podemos ponerlo todo en una sla lnea:
10 A = 1 : While A <= 10 : Print A : A = A + 1 : Wend
Pero esto tampoco es recomendable, queda algo "difuso"...
El WEND funciona como IF A <=10 THEN GOTO xxx, con la ventaja que evitamos el GOTO y lo que
hace es comprobar si la expresin que hay tras el WHILE es cierta o no, en caso de que sea verdadero
el resultado, (ya sabes, distinto de CERO), se ejecutar todo lo que hay entre WHILE y WEND. Estas
instrucciones ya existan en el GWBASIC (el basic de los PCs)
Hay que tener cuidado con esto de que la expresiones evaluan el cero como FALSO y cualquier otro
valor como VERDADERO, por ejemplo:

A = 1
While A
Print A
A = A + 1
Wend

o
While 1
Print A
A = A + 1
Wend

En ambos casos el bucle sera "infinito", realmente se detendra en un momento dado, ya que llegara a
"desbordarse" el valor mximo y en ese momento el programa acabara por producirse un error... pero
prueba esto y vers:

While 1
Print "Hola Mundo"
Wend

Esto nunca finalizar, salvo que pulses CRTL+BEAK (o INTERrumpir), para detener el programa.
Ms instrucciones para hacer bucles
Con el QuickBasic 3.0, (yo no llegu a tenerlo, pero creo que fue ah dnde se introdujo), entr en
funcionamiento una nueva forma de hacer bucles:
DO... LOOP
El ltimo ejemplo podramos escribirlo as:

Do
Print "Hola Mundo"
Loop
Pero la "gracia" de este tipo de bucle es que podemos usar dos nuevas clusulas para evaluar cuanto
durar el bucle.
La primera es WHILE y funciona igual que en WHILE/WEND

A = 1
Do While A <= 10
Print A
A = A + 1
Loop
La ventaja es que WHILE se puede poner tanto despus de DO como a continuacin de LOOP.
Si lo usamos como DO WHILE <expresin>... la forma de actuar es igual que WHILE/WEND, es decir, se
evalua la expresin y slo en caso de que sea cierta, se ejecta lo que est dentro del bucle, es decir
entre DO y LOOP.
Pero si evaluamos la expresin en LOOP, se ejecutar todo lo que hay tras el DO, como mnimo una vez
y se seguir repitiendo si se cumple la condicin. De esta forma, como he dicho, se ejecutar el
contenido del bucle, como mnimo una vez.
Veamos un ejemplo:

A = 1
Do
Print A
A = A + 1
Loop While A <= 10
El problema es que si A, en lugar de valer 1, tiene un valor superior a 10, tambin se ejecutar, al menos,
una vez.
A = 11 : Do : Print A: A = A + 1: Loop While A <= 10
Que mal queda en una sla lnea, verdad?
Pero con DO/LOOP tambin puede usarse UNTIL, en este caso, el bucle se repetir HASTA que se
cumpla la expresin

A = 1
Do Until A > 10
Print A
A = A + 1
Loop
Fijate que la expresin ha cambiado de <= (menor o igual) a > (mayor), ya que ahora se evala de esta
forma:
Hasta que A sea mayor que diez, REPITE todo hasta LOOP.
Por suepuesto tambin podemos usarlo despus del LOOP:

A = 1
Do
Print A
A = A + 1

Loop Until A > 10


Aqu hago la misma aclaracin que antes, si el valor incial de A es ms de 10 se ejecutar como mnimo
una vez.
Realmente para contar de forma secuencial y prcticamente para casi todo tipo de bucle, no es
necesario hacer los bucles con DO/LOOP, ya que FOR/MEXT lo hace bastante bien.
Sigamos con estos bucles, pero en lugar de contar de menor a mayor, vamos a contar "pa trs", es decir
de mayor a menor... quin sabe, lo msmo necesitas hacer un programa que cuente al revs...

A = 10
Do While A >= 1
Print A
A = A - 1
Loop
Cuando se muestre el 1, A=A-1 se convertir en A = 0 y la comparacin A >= 1 no se cumplir, por tanto
dejar de repetirse el bucle, pero esto tambin se puede hacer con FOR/NEXT:

For A = 10 To 1
Print A
Next
El nico inconveniente es que NO SE REPITE NI UNA VEZ... Por qu?
Porque si no se le indica lo contrario, FOR/NEXT siempre cuenta de forma ascendente y cuando ve que
A debe ir de 10 hasta 1 y que eso no es ascendente... pasa de ejecutar el bucle. Esto es una cosa a
tener en cuenta, FOR siempre evala los valores del bucle que tiene que hacer y si no est entre los
valores que debe, no se ejecuta ni una sola vez. En este caso debe empezar por DIEZ y llegar hasta
UNO, as que se da cuenta de que ya ha terminado... incluso sin haber empezado... que listo es el FOR!
Para que el FOR cuente hacia atrs, necesitamos un nuevo peldao (esto en ingls quedara "clavado"),
en la escala evolutiva del FOR/NEXT (ah queda eso!!!)
Ya sin coas, se necesita la palabra STEP para indicarle que no queremos ir de uno en uno de forma
ascendente, en nuestro ejemplo lo usariamos as:

For A = 10 To 1 Step -1
Print A
Next
De esta forma contar desde 10 hasta 1, restando uno en cada repeticin.
Pero, que hacer si queremos usar otros valores?
Simplemente ponerlo despus de STEP, por ejemplo:
For A = 10 To 1 Step -1
For A = 1 To 10 Step 3, etc, etc.
Insisto, todo esto est muy bien, pero en la prctica usaremos otras cosas adems de contar de forma
lineal, con incrementos o sin ellos... habr veces que queramos salir de un bucle.
Ya lo hemos visto, por ejemplo Exit Sub sala del procedimiento, recuerdas el Exit For?
Para salir de los bucles podremos Exit y a continuacin For, Do, etc. Pero NO podremos salir de un bucle
WHILE/WEND.
Ya veremos ejemplos para estos casos y otros que surgirn ms adelante.
Bien, creo que ya hemos dado demasiadas vueltas con tanto bucle, para terminar: los ejercicios esos
que tanto os gustan.
1.) Haz un programa que al pulsar en un botn (CommandButton) haga un bucle entre dos valores que
habrs introducido por medio de dos cajas de textos (una para el inicio y otra para el final)
2.) Otro que tenga una tercera caja de textos y que el valor introducido en ella sea el incremento.

3.) Como tercer ejercicio, una vez terminado el bucle, que muestre en un Label las veces que se ha
repetido.
Por ejemplo, si hacemos un bucle del uno al diez de uno en uno, se repetir diez veces; pero si lo
hacemos de dos en dos, se repetir cinco veces...
Como pista, decirte que no tendrs que hacer ninguna comparacin para obtener el resultado, la solucin
es tan SIMPLE que seguramente la descartars "porque no puede ser tan fcil"
Por supuesto, me gustara que los bucles los hicieras tanto con FOR/NEXT y DO/LOOP. Ya puestos,
podras hacerlo con el WHILE/WEND e incluso con el GOTO...
Feliz programacin!
Y seguimos con la costumbre esta de pedirte tus comentarios sobre el curso.
Sobre todo necesito saber si realmente est claro y entendible... ya que si no no valdr para mucho el
montn de horas que le dedico a cada una de las entregas... si, aunque no te lo creas, le dedico ms de
5 horas a cada entrega...
Si no pasa nada raro, seguramente en este mismo mes habr una nueva entrega.

Curso Bsico de Programacin


en Visual Basic
Sptima Entrega: 10/Sep/97.
por Guillermo "guille" Som
Te recomiendo que leas las entregas anteriores, aqu tienes los links:
La Primera, la Segunda, la Tercera, la Cuarta, la Quinta, la Quinta++, la Sexta.

Hola fans del curso bsico, es que poco a poco se estn apuntando ms gente a este cursillo y eso me
pone en un compromiso... me vais a obligar a terminarlo!!!
Bromas aparte, espero que te siga interesando y que se lo digas a tus vecinas, compaeros de clase,
gente de tu curro y dems personal que te encuentres por la calle, el bus, el metro, cuando llames a un
906 y sobre todo cuando te tomes unas copas con los amigos... a ver si al final entre todos me comprais
una casita de verdad...
Vamos a ver las soluciones de los ejercicios de la sexta entrega, para ver que nivel llevas, porque me
imagino que te has enterado de todo lo que pona, ya que ltimamente no recibo preguntas ni dudas ni
quejas porrque algo estuviera mal... salvo algn que otro despistadillo que ha empezado por la primera
entrega, hace los ejercicios y me "mailea" dicindome que no le muestra nada... y eso que lo he puesto
al final de la primera entrega y en letra GORDA pa que se vea bien...
Esto pasa por bajarse las pginas, guardarlas en el disco duro y despus leerla al montn de das...
Bueno, despus del rapapolvo... todo para que se te olvide que esta entrega iba a estar el mes pasado...
SOLUCIONES A LOS EJERCICIOS DE LA SEXTA ENTREGA:
1.)

Private Sub Command1_Click()


Dim A As Integer
Dim B As Integer
Dim i As Integer
A = Val(Text1)
B = Val(Text2)

For i = A To B
Print i
Next
Show
End Sub
'El bucle tambin se puede hacer de esta forma:
i=A
Do While i<=B
Print i
i=i+1
Loop
'Y de esta tambin
i=A
While i<=B
Print i
i=i+1
Wend
2.)
Private Sub Command1_Click()
Dim A As Integer
Dim B As Integer
Dim C As Integer
Dim i As Integer
A = Val(Text1)
B = Val(Text2)
C = Val(Text3)
For i = A To B Step C
Print i
Next
Show
End Sub
'Otra forma de solucionarlo
i=A
Do While i<=B
Print i
i=i+C
Wend
3.)
'Aadir estas lneas:
Dim D As Integer
'...
'...For
D = D +1
'...
Next
Label1 = "Nmero de repeticiones: " & D
Y eso es todo, no pongo otras posbles formas de obtener los resultados, porque tu mismo habrs
comprobado si estn bien o no.

Ahora empezamos con la entrega real, es decir la sptima.


Ya disponemos de instrucciones suficientes para empezar a "profundizar" en las cosas ms difciles... o
casi.
Ya sabes que hay que usar Option Explicit en todos los mdulos de cdigo... Esto no es obligatorio, pero

si no quieres que perdamos la amistad, usalo. Gracias.


Tambin cmo usar las variables y los diferentes tipos, puedes hacer bucles, tomar decisiones,
relamente es ms correcto decir: hacer que VB tome decisiones, ya sabes cmo pedir datos al usuario y
tambin cmo mostrarlos. Sabes crear tus propias instrucciones... Jo! Cuanto sabes! Me tienes
"anonadado"
Pero an no sabes una cosa: cmo crear Funciones
Qu son las funciones?
Para simplificar, te dir que una funcin es un procedimiento (como el Sub), que puede devolver un valor.
Normalmente se usa para que lo devuelva, aunque veremos que no siempre es necesario; de todas
formas, cuando necesites un procedimiento que no necesite devolver un valor, usa el Sub.
Cmo declarar/codificar una funcin?
mbito Function Nombre ([parmetros]) As Tipo
Dnde mbito puede ser Public o Private, dependiendo de la "cobertura" o visibilidad. Ya sabes, Private
slo es visible en el propio mdulo en el que se encuentra definido y Public es en todo el proyecto,
incluso fuera de l...
Los parmetros son los valores que esta funcin puede necesitar para "cumplir" su misin. stos son
opcionales, es decir puede tenerlos o no, incluso si tiene, puede ser uno o varios, para declarar varios
parmetros hay que separarlos por comas... Los corchetes, que se suelen usar en los manuales, la
ayuda, etc, sirven para indicar que son opcionales, pero no se te ocurra ponerlos en ninguna
funcin!, ya que no forman parte del lenguaje Basic...
El tipo es para saber que tipo de dato devolver la funcin.
El valor devuelto por una funcin lo podemos usar para asignarlo a una variable: a = MiFuncin()
o incluirlo en una expresin: If MiFuncin() + 15 > LoQueSea Then
La ventaja real frente a los Subs es la posibilidad de devolver un valor, imaginate que quieres crearte tu
propio procedimiento para averiguar si un determinado archivo existe... si lo hace como funcin podras
devolver un valor cero para indicar que no existe el archivo y un valor distinto de cero indicara que el
archivo en cuestin existe. Por tanto, podramos usarlo de esta forma:
If Existe(NombreArchivo) Then ...
Ya que estamos puestos, veamos cmo hacer esta funcin de forma simple y as te explico uan cosa
muy importante de toda funcin: poder devolver el valor!

Public Function Existe(sArchivo As String) As Integer


Existe = Len(Dir$(sArchivo))
End Function
Para devolver un valor, ste se asigna a una variable que tiene el msmo nombre que la funcin.
Ya vimos que LEN devuelve el nmero de caracteres de la cadena que ponemos entre los parntesis; si,
LEN tambin es una funcin, pero incluida en el propio Visual Basic.
Dir$ es otra funcin del VB que devuelve el nombre de un archivo, (slo el nombre), o una cadena vaca,
en caso de que no haya ninguno en la direccin pasada por el parmetro que se ha usado. Para saber
ms de esta funcin, as como de otras, puedes buscar en la ayuda...
Hemos visto que en las expresiones usamos unos operadores para hacer las comparaciones, aqu tienes
los seis posibles:
= igual, > mayor que, < menor que, >= mayor o igual, <= menor o igual y <> distinto.
Recuerda que el signo igual funciona de forma diferente, segn se use en un expresin o en una
asignacin.
Pero adems de estos signos, podemos usar en nuestras expresiones unos operadores lgicos, estos
son: AND, OR y NOT
Podramos desear hacer una comparacin y comprobar si varias cosas se cumplen, por ejemplo:
If A>10 And Len(Nombre)<>0 Then ...
Para que esta expresin se cumpla, deben ser ciertas las dos condiciones, es decir que A sea mayor que
10 "y" que la longitud de Nombre sea distinta de cero. Podemos usar tantas condiciones como
queramos, sin pasarnos demasiado para que la cosa funciones mejor. Aqu las dos condiciones deben
cumplirse, pero en este otro jemplo:
If A>10 Or Len(Nombre)<>0 Then ...
cumplindose cualquiera de las dos, se acepatara como vlido.
Cuando el If se procesa, se toma todo lo que hay entre IF y THEN y se considera como una sla
expresin.
Si quieres puedes asignar a una variable el resultado de una expresin, el valor devuelto siempres ser 0
(cero) en caso de que no se cumpla todo lo expuesto y -1 cuando sea cierta.

Para manejar estos valores de Cierto (-1) y Falso (0), Visual Basic tiene un tipo especial llamado
Boolean, los valores que puede aceptar una variable de este tipo son: True (verdadero) y False (falso).
Veamos un ejemplo:

Dim b As Boolean, i As Integer


Dim a As Integer, Nombre As String
Show
a = 15
Nombre = "Guille"
b=(a>10 And Len(Nombre)<>0)
i=(a>10 Or Len(Nombre)<>0)
Print "Valor de B "; b
Print "Valor de i "; i
Te has fijado en el detalle? B vale True (verdadero), sin embargo i vale -1. Pero para el caso los dos
valores significan lo mismo: si estas expresiones se hubiesen usado en una comparacin, las dos
hubiesen devuelto un valor verdadero.
El tercer operador lgico (Not) sirve para negar algo, es decir invertir el valor contenido en una variable, o
casi...
If Not A>10 Then ...
Parece lgico el resultado, verdad?, si no se cumple que A sea mayor que diez, ser cierto;
comprobemoslo:

Dim A As Integer
'recuedas que tienes que poner Show?
A = 5
If Not A>10 Then
Print A;"no es mayor que 10"
End If
BINGO! Funciona!
"Mu" bonito, pero... que eslo que ocurre?
Se toma A > 10 y se procesa, como A no es mayor que 10, se devuelve un valor falso (0) y despus se
hace Not 0 que da como resultado -1 (verdadero), por tanto se cumple la condicin.
Ya vimos que el valor devuelto por una variable se puede usar en una comparacin, si es cero se toma
como falso y si es distinto de cero, como verdadero.
Prueba ahora esto:

A=0
If Not A Then
Print A;"es cero"
Else
Print A;"es distinto de cero"
End If
Tambin funciona, ya que Not 0 es -1, por tanto el If lo da por cierto, si cambiamos el valor incial de A por
un valor distinto de cero:

A=5
If Not A Then
Print A;"es cero"
Else
Print A;"es distinto de cero"
End If

Que ha pasado aqu? Simple, que no es lo que esperabamos... Cuando hicimos Not 0 era evidente, ya
que se convierte en -1, pero Not 5 no se convierte en cero, sino en: -6 y ya sabes que el IF considera
como verdadero todo lo que no sea cero.
No quiero entrar en detalles de porqu ocurre esto, slo decirte que la responsable de todo es la
notacin binaria... los ceros y unos que dicen que es el lenguaje nativo de los cacharros estos... talvez
ms adelante tratemos un poco de la notacin binaria, pero no por ahora... recuerdo que en mis tiempos
del GwBasic la usaba bastante, incluso tena rutinas para "representar" en ceros y unos un nmero...
Vale, para que te entretengas probando... (este link es para el programa completo Dec2Bin.zip 1.75 KB)
Private Function Dec2Bin(sNumDec As String) As String
'Recibe una cadena que ser un nmero decimal
'Devuelve ese nmero representado por ceros y unos
'
Dim i As Integer
Dim lngNum As Long
'Long, por si las moscas
Dim sTmp As String
'Cadena temporal
lngNum = Val(sNumDec)
sTmp = ""
For i = MaxBits - 1 To 0 Step -1
If lngNum And 2 ^ i Then
sTmp = sTmp & "1"
Else
sTmp = sTmp & "0"
End If
Next
Dec2Bin = sTmp
End Function
Ahora puedes comprobar porqu NOT 5 da como resultado -6, usa esta rutina para probarlo, si escribes
5, te mostrar:
00000101 y si escribes -6 lo que muestra es: 11111010, fijate que ha cambiado todos los ceros por unos
y viceversa.
Eso es lo que hace el NOT, invertir los valores binarios y como un valor binario slo puede ser 0 1, no
se complica demasiado la vida. Prueba a escribir el valor 0 y el valor -1 y conviertelo a notacin binaria,
fijate lo que el Visual Basic normalmente ve.
Prueba con el tema de la notacin binaria, as sabrs realmente cmo funciona todo esto de las
comparaciones (por dentro).
Lo que nunca falla es completar la expresin, por ejemplo si haces esto:

If Not A<>0 Then


Print A;"es CERO"
Else
Print A;"NO es CERO"
End If
Esto siempre funcionar de la forma esperada.
Pero sera ms fcil, o al menos ms inteligible, hacerlo as:

If A=0 Then
Print A;"es CERO"
Else
Print A;"NO es CERO"
End If
Es que algunas veces se puede uno complicar la vida ms de lo necesario...
Cuando quieras comprobar un valor devuelto por cualquier expresin, puedes hacerlo asignndolo a una
variable o bien mostrando el valor: Print Not A

Cuando se usa AND pra evaluar varias partes de una expresin hay que tener presente que siempre se
procesan todas las condiciones y finalmente se decide si es cierto o no el valor devuelto. Esto que
parece lgico, algunas veces puede llevar a confusin e incluso producir efectos no deseados en el
programa.
Prueba con esta nueva versin de la funcin Existe. En un form debes poner una etiqueta Label1.

Private Function Existe(Archivo As String) As Integer


Existe = Len(Dir$(Archivo))
If Existe Then
Label1 = Archivo & " Si existe"
Else
Label1 = Archivo & " No existe"
End If
'Esto es ms corto, pero talvez menos evidente:
'Label1 = Archivo & IIf(Existe, " Si", " No") & " existe"
DoEvents
End Function
Private Sub Form_Load()
Dim A As Integer, Nombre As String
Show
Label1 = ""
Nombre = "C:\Autoexec.BIN"
A=5
If A > 10 And Existe(Nombre) Then
Print A; "mayor de 10 y " & Nombre & " existe"
Else
Print A; "no es mayor de 10 o " & Nombre & " no existe"
End If
End Sub
En el ejemplo comprobars que a pesar de que la segunda parte de la comparacin no se cumpla, a no
ser que tengas en tu disco C un archivo que se llame as, el caption del Label se ha cambiado. Es decir
que se ha procesado la segunda parte de la expresin a pesar de que la primera A>10 es FALSA.
Imaginate que en lugar de ser una funcin rpida, hubiese sido otra cosa que tardara un poquito ms de
la cuenta...
Para casos como estos, (la verdad es que no son demasiado habituales), deberas hacerlo as:

Private Sub Form_Load()


Dim A As Integer, Nombre As String
Show
Label1
Nombre
A = 5
If A >
If

= ""
= "C:\Autoexec.BIN"

10 Then
Existe(Nombre) Then
Print A; "mayor de 10 y " & Nombre & " existe"
Else
Print A; "es mayor de 10 pero " & Nombre & " no

existe"
End If
Else

Print A; "no es mayor de 10 o " & Nombre & " no existe"


End If
End Sub
Talvez sea ms largo y haya que usar ms cdigo, pero en ocasiones es ms "resultn".
Usando este nuevo "estilo", slo se comprobar si existe el archivo cuando A sea mayor que diez. Lo que
debes sacar en claro de todo esto es que despus de un THEN puedes "anidar" ms expresiones
IF...THEN...ELSE. Incluso se puede usar en una sla lnea, slo que el resultado "visual" del cdigo no
es tan "presentable"...

If A > 10 And Existe(Nombre) Then Print A; "mayor de 10 y " &


Nombre & " existe" Else Print A; "no es mayor de 10 o " & Nombre
& " no existe"
Aunque podramos usar el caracter _ que se puede usar en VB para separar lneas largas, pero es como
si estuviese toda en la misma lnea, as que la lnea anterior, se quedara as:

If A > 10 And Existe(Nombre) Then _


Print A; "mayor de 10 y " & Nombre & " existe" _
Else _
Print A; "no es mayor de 10 o " & Nombre & " no existe"
Fijate que a pesar de aparentar que es un BLOQUE IF, no tiene el END IF del final, esto es porque yo lo
he "estructurado" de esa forma, no porque sea lo mismo. El uso de _ es slo esttico y para VB todo se
trata de una misma lnea, por tanto tendr un lmite de caracteres posibles a usar, el lmite que VB le
ponga, que creo que es 1024... pero no me hagas demasiado caso...
Antes he mencionado la palabra "anidacin", sta se usa para indicar que una serie de instrucciones
estn dentro de otras. En este caso hemos anidado dos IF... THEN, pero lo ms habitual es hacerlo con
los bucles (FOR, DO, etc), veamoslo:

Dim i%, j%, c%


For i = 1 To 10
For j = 1 To 10
c = c + 1
Next
Next
Print c
Lo que debes saber, o al menos tener en cuenta, es que cuando anidamos varios bucles, lo externos
empiezan antes (elemental querido Watson), pero los internos finalizan primero (...) y hasta que no lo
hagan, no podrn continuar los de fuera.
En el ejemplo, por cada repeticin del bucle i, se completa un bucle j. Por eso el valor de c es 100
(10*10)
Esto, en ocasiones, puede ralentizar el programa, y dar la impresin de que el programa se ha quedado
"colgado", prueba a poner otro bucle dentro del j y cambia los valores mximo de los dos bucles internos
a 1000, te recomiendo que la variable c sea LONG y que te sientes... No hace falta que hagas la prueba,
es una chorrada...
Lo que interesa es que dentro de un proceso cualquiera y por supuesto tambin en los bucles,
podramos necesitar que el Visual Basic nos mostrara alguna indicacin de que est "ocupado", por
ejemplo cambiando la forma del cursor del ratn, como hacen otros programas, incluso el propio VB
cuando est "atareado". Para ello tendremos que cambiar la propiedad MousePointer para que muestre
el reloj de arena:
MousePointer = vbHourGlass 'vbHourglass es igual a 11, por si tienes usas el VB3
'... lo que sea
MousePointer = vbDefault '0 si usas VB3
Pero algunas veces el cursor no se cambia... para asegurarnos que cambie, usa el DoEvents despus de
asignar el valor para el reloj de arena. De esta forma permitimos que Windows procese sus mensajes
(recuerdas?) y as tiene ocasin de cambiar el puntero del ratn.

Bueno, hasta aqu llega esta entrega. No hay ejercicios, slo te pedira que revisaras la ayuda y te
leyeras lo que all pone referente a las instrucciones que vamos viendo... aunque me imagino que
tendrs otras cosas que hacer...
El caso es que no hay ejercicios y ya est

Curso Bsico de Programacin


en Visual Basic
Octava Entrega: 11/Sep/97.
por Guillermo "guille" Som
Te recomiendo que leas las entregas anteriores, aqu tienes los links:
La Primera, la Segunda, la Tercera, la Cuarta, la Quinta, la Quinta++, la Sexta, la Sptima.

Ya estamos de nuevo por aqu, esta vez he procurado ser un poco ms rpido para que no pierdas el
hilo...
(realmente he sido demasido rpido, pero no te acostumbres)
El problema de escribir las entregas, no es porque no sepa que poner... a este nivel an se bastantes
cosas... ejem! Lo que ocurre es que normalmente suelo hacerlo en papel... quien lo dira verdad?
Y es porque no tengo ordenador en mi "piso" y all es dnde aprovecho, por aquello de la tranquilidad,
para concentrarme en las cuatro chorradillas que voy a decir... despus toca pasarlo a "limpio" y como no
soy demasiado diestro en esto de escribir a mquina, hice rabona cuando tena clases de mecanografa,
pues algunas veces tardo ms de la cuenta. Pero como ahora estoy en unas vacaciones "virtuales", he
aprovechado y le he mangado el porttil a mi jefe, con la excusa de que se lo voy a limpiar de "basura" y
todo ese rollo.
Vale, no me enrollo ms con mis cosillas y vamos a pasar a un tema que, por su extensin, seguramente
lo voy a dar en dos entregas.
Empezamos. Ahora hay que ponerse "formal"...
Ya has visto todo el tema de las variables y sabes para que sirven, (al menos as debera ser, ya que
nadie me ha preguntado sobre el tema), pero hay veces que necesitamos ms.
Imaginate que quieres saber cuantas veces por hora te rascas la cabeza intentando comprender lo que
hay en mis pginas...
Podramos tener unas cuantas variables, una por cada hora del da, con nombres como: Hora1, Hora2,
etc. y cuando te arrasques a las 22 horas, haras esto:
Hora22 = Hora22 + 1
Con lo que aumentas en uno el contenido de la variable Hora22... y tu dirs... que problema hay?
Ninguno, pero es que se me ha ocurrido contarte esto como podra haberte contado otra cosa. Pero
imaginate que quieres sumar las veces que te has rascado la cabeza en todo el da, podras hacer:
VecesDia = Hora1 + Hora2 + ...+ Hora24
Tampoco hay problema, sumamos todas las variables (24 en este caso) y guardamos el total en la
variable VecesDia.
Pero la cosa se va complicando, verdad? No lo crees? Pues toma un poco ms de complicacin:
Cmo haras para saber la hora en que ms veces te has rascado la cabeza?
No te doy la solucin... Es demasiado largo y seguramente hasta complicado como para ponerlo como
ejemplo para que salgas de tu incredulidad... Ahora bien, si quieres hacerlo, hazlo, pero despus no me
preguntes si est bien o no... sera una prdida de tiempo, ya que, como vas a ver dentro de muy pocas
lneas, hay una forma de hacerlo bastante ms simple.
Toda esta retahila, es para explicarte la forma con que el Basic, y otros lenguajes, nos facilita la vida en
tareas de este tipo... realmente no creo que haya nadie que tenga una utilidad de este tipo, ya que no es

til esto de saber cuantas veces nos rascamos la cabeza por no comprender algo... ni an cuando ese
algo sea lo que yo escribo...
Un poco de historia (la ma)
La primera vez que me top con los ARRAYS (de eso va esta entrega), fu con un programa de dados,
en mi querido VIC-20. Lo copi de un libro ingls que tena 50 juegos para el Vic-20, saba que
funcionaba, pero no saba cmo...
Durante un montn de tiempo, a lo mejor fu una o dos semanas, es que antes los das duraban ms
que ahora, us mtodos parecidos, sin saber porqu funcionaba... slo saba que funcionaba y
simplemente lo aceptaba. Despus cay en mis manos un libro, esta vez en espaol, y me puse a leer la
parte que explicaba esto de las "matrices", antes no eran arrays... la verdad es que lo le como 20 veces
o ms... y pareca que nunca iba a lograr asimilarlo, es que soy bastante duro de mollera y antes, que
era ms joven, calculo que unas 14 veces ms joven que ahora, tena la cabeza ms dura. En aquella
ocasin si que me hubiese venido bien el programilla este de rascarme la cabeza...
Esto es lo que deca, el susodicho libro:
"El lenguaje BASIC permite definir otro tipo de variables numricas:
A(1), A(2)...A(N)
se llaman variables con ndice y estn formadas por un nombre de variable, [...], seguido de un nmero
natural entre parntesis. [...] el conjunto ordenado de estas variables se llama lista. [...]"
Ahora que lo he vuelto a leer, casi lo entiendo; pero para un pobre cateto ignorante como yo, aquello
sonaba a chino. Y si tu lo entiendes, me alegro por t...
Como te he comentado el parrafo ese est sacado de un libro que fue de los pocos que tuve, al menos
en castellanao, de los ingleses slo me interesaban los listados, que era lo nico que prcticamente
traan. La cosa que a pesar de eso, hasta aprend un poco, a duras penas, sobre todo porque en
aquellos tiempos no tena a quin preguntarle, ni quin me explicara algunas de las muchas dudas que
tena... y si no tena ms dudas era porque tampoco haba profundizado demasiado. Pero lo que he
sacado en claro es que para aprender a programar hay que practicar, practicar y seguir practicando... es
como todo, cuanto ms practicas... o terminas por aburrirte o aprendes...
Vamos al tema, pero sin teoras, las teoras se las dejo a los eruditos... ellos saben cmo explicar "bien"
las cosas... Y que conste que no tengo nada en contra de las teoras, lo que ocurre, al menos a mi, es
que prefiero entender las cosas de forma prctica, que soy "mu" torpe yo y si no lo veo funcionar, no me
entero...
En el ejemplo ese de las horas, nos vendra muy bien que pudiesemos usar otra variable para la hora de
nuestro "picor" y hacer algo como:
HoradelPicor = HoradelPicor + 1, dnde "delPicor" sera la hora en que nos rascamos la cabeza, as si
"delPicor" es 22, incrementar Hora22. Si, lo reconozco, una vez intent hacerlo, crea que se poda hacer
as:
delPicor = 22
HoradelPicor = HoradelPicor + 1
Pero el basic no haca lo que yo quera, ni siquiera me daba error, si en aquellos tiempos hubiese
existido el Option Explicit, me habra percatado de muchas cosas antes de tiempo...
Por suerte para todos, existen los ARRAYS (o variables con ndice) y realmente la forma de hacerlo es
casi como yo crea, lo nico que cambiaba era la forma... total, por un par de parntesis...
Hora(delPicor) = Hora(delPicor) +1
Con esto le decimos al Basic: coge lo que hay guardado en la variable que est en la posicin delPicor
del array Hora...
Vale, captado. Me estoy lanzando y an no te he presentado a los arrays.
Un Array es una serie de variables que tienen el mismo nombre y para acceder a cualquiera de esas
variables, usamos un nmero (ndice) para indicar cual de esas variables es la que nos interesa... Te
has enterado de que estoy hablando de variables o tengo que decirlo ms veces? Vale, adimito que
tampoco he sido demasiado claro, es que realmente no es tan fcil de asimilar, pero en cuanto lo veas
con algunos ejemplos, seguro que lo "asimilas".

El basic, que es "mu" listo, cuando ve esto:


Hora(delPicor), dice: "Cuanto vale lo que est dentro del parntesis?" (en caso de que sea una
expresin en lugar de un nmero o una variable, la evaluara primero y usara el resultado), una vez que
sabe cuanto vale lo que est dentro del parntesis... "ahora cojamos, del array, el contenido de la
variable que est en esa posicin" (para el basic un array no es ms que una serier de variables que
tienen el mismo nombre y lo nico que vara es "la direccin" en la que est guardado el valor.
Osea que maneja los arrays de la misma forma que a las variables simples, pero ampliando nuestros
horizontes "variablisticos".
Ahora fijate cmo podemos sumar las veces que nos hemos rascado la cabeza a lo largo del da:
For i= 1 to 24
vecesDia = vecesDia + Hora(i)
Next
Cada vez que i cambia de valor, (en este caso tomando valores desde 1 hasta 24), el Basic usa una
variable diferente del array Hora, cuando i vale 1 est usando Hora(1) y cuando i vale 22, usa Hora(22).
Lo de saber a que hora te has rascado ms veces la cabeza te lo dejo como ejercicio, slo te dir que si
haces esto:
masVeces = Horas(HoraMasVeces)
sabrs cuantas veces te has rascado a la hora HoraMasVeces...
Los elementos de un array se comportan como variables normales, pudiendo usarlas en expresiones y
en cualquier otro sitio en el que podamos usar una variable, realmente uno de los pocos sitios donde no
puede usarse es como ndice de un bucle FOR, pero por lo dems, en cualquier parte.
Imaginate que en la posicin 22 del array Hora, es decir en Hora(22) tenemos guardado un valor 15, al
hacer esto:
Print Hora(22) * 10
mostrara 150, porque el VB ha sustituido Hora(22) por su valor y lo ha multiplicado por 10, es como si
internamente hubiese hecho: Print 15*10.
Y tu dirs: esto mismo es lo que hace con las dems variables...
Efectivamente, ya que es una variable, especial, pero una variable al fin y al cabo.
Sigamos imaginando... suponte que quieres guardar en una variable a que horas te pones a leer, cada
da, las pginas del Guille y que sabes que sern tres veces diarias, lo hay masoquistas... Podras hacer
algo como esto:
Vez(1) = 20: Vez(2) = 22: Vez(3) = 23 '...(de nueve a diez vas a cenar)
con lo cual tendras un array con tres ndices. El valor de cada una de las variables del array "Vez", sera
la hora en que "guilleas" ... y si quieres incrementar los "rascones" de la hora que est en la posicin H,
(que puede ser 1, 2 3):
Ahora = Vez(H) 'Si H vale 1, Ahora sera igual a 20
Hora(Ahora) = Hora(Ahora) + 1
Pero esto podras hacerlo ahorrndotela variable Ahora, sera as:
Hora(Vez(H)) = Hora(Vez(H)) + 1
Complicado? Pues si... que quieres que te diga... pero dejemoslo estar...
Veamos cmo podemos usar en nuestros programas este tipo especial de variables. Antes yo las
llamaba: "variables dimensionadas", entre otras cosas porque era nicamente cuando necesitaba usar
DIM, al menos si iba a usar ms de 10 "posiciones", aunque tambin puede ser que lo leyera en algn
sitio, no importa...
Para decirle al Basic que vas a usar tres variables en el array Vez, hay que hacerlo de esta forma:
Dim Vez(3)
Ahora lo que necesitamos es un array para guardar los picores de las 24 horas del da:
Dim Hora(24)
Bueno, ya sabes casi todo lo que tienes que saber de los arrays... ahora comprate un buen libro "terico"
y estudiatelo... o leete lo que dice el manual del Visual Basic... que tambin puede valer.
An sigues por ah...?
Bueno, ya que insistes, te explicar algunas cosillas ms...
Los arrays son variables, algo especiales, pero variables al fin y al cabo.
Por tanto, podemos tener arrays numricas, de carateres y en definitiva de cualquier tipo que el Basic

permita, lo nico que tenemos que hacer es indicrselo al reservar memoria:


Dim Vez(3) As Integer
Dim Amigos(1000) As String
Dim Salario(1000) As Currency
Cuando declaramos un array, el Basic reserva memoria para cada una de las variables que vamos a
usar, o casi, ya que en realidad reserva una posicin ms, no por nada en especial, sino porque empieza
a contar desde cero; por ejmplo en el array Vez, el ndice ms bajo que podramos usar es el 0 y el ms
alto el 3.
Esto ha sido as desde siempre... aunque en un intento de "cambiar" las cosas, un listillo dijo: "El Basic
debera empezar a contar desde uno" y se sacaron una nueva instruccin de la manga, desde mi punto
de vista lo podran haber hecho mejor, pero como mis "preferencias" no las tuvieron en cuenta...
(tampoco tuve la oportunidad, la verdad sea dicha...), el caso es que dijeron:
OPTION BASE 1 para que el ndice menor de un array sea UNO y
OPTION BASE 0 para empezar por CERO, esta ser la predeterminada.
Por tanto si usamos este cdigo:
Option Base 1
Dim Vez(3) As Integer
Crea un array con tres variables (del 1 al 3)
Ms adelante, otro listillo, (este fu un poco ms inteligente), dijo: "Y si el usuario pudiera decidir el valor
menor y el mayor del ndice de una array"... "pues que bien", contest otro...
Y as fu. Imaginate que tu slo te rascas la cabeza de 10 a 23, puedes dimensionar as el array Hora:
Dim Hora(10 To 23) As Integer
De esta forma slo "reservas" la memoria que necesitas... Ya ves que todo son facilidades, aunque hay
una cosa "muy" importante que hay que tener en cuenta: Si pretendes acceder a una posicin del array
que no est reservada, el Visual Basic te avisa de que hay un error y detiene (termina) el programa. Esto
es lo nico grave, pero si tu aplicacin tiene informacin importante pendiente de guardar, o se
encontraba en medio de un proceso largo de clculo... realmente si que ser grave... en otra ocasin
veremos cmo detectar los errores y poder "manejarlos" para que no nos dejen en la "estacada"... Por
tanto si declaras un array que reserva tres posiciones, siempre consecutivas, no podremos acceder a
ninguna posicin anterior o posterior a las que tenemos declarada.
Pero... y si necesito ms espacio? Lo nico que tienes que hacer es re-dimensionar el Array:
ReDim Vez(5) As Integer
Problemas? Si, que ya has perdido lo que antes haba almacenado...
Cuando yo empec con el Basic (otra batallita?, habr que seguirle la corriente...), no exista el ReDim.
Pero si exista uan forma de conseguir esto mismo. El truco consita en "borrar" el array creado y volver a
dimensionarlo... tambin recuerdo que me di muchos quebraderos de cabeza adaptar mi cdigo (escrito
en el intrprete GwBasic... la GW ser Gates, William?) a un compilador... eso de usaar varias veces el
DIM no lo digera bien... pero eso es otra historia, que seguramente no contar...
Para borrar un array de la memoria, hay que usar ERASE seguido por el nombre del array, por ejemplo:
Erase Hora
Con esto conseguimos lo mismo que con Redim Vez(5) As Integer:
Erase Vez
Redim Vez(5) As Integer
Pero, y si no quisieramos perder los valores anteriores...
Pues copia los datos en otro Array temporal, borras el primero, lo vuelves a dimensionar con el nuevo
nmero de elementos y a continuacin copias los datos del array temporal en el array quie acabas de
redimensionar, despus borras el array temporal, ya que no lo necesitars...
No, no es necesario tantas cosas, pero esto es lo que haba que hacer con el VB antes de la versin 3 y
con el QuickBasic antes de la versin 4, ahora slo hars esto:
Redim Preserve Vez(5)
Adems cuando se ReDimensiona un array no hace falta volver a especificar el tipo de dato, ya que
tomar el mismo que se us inicialmente al declararlo.

La ventaja del ReDim, con o sin Preserve, (podra haber hecho un chiste malo con esto del Preserve,
pero me abstengo...), es que puedes ampliar o reducir el nmero de variables de un array... supn que
despus de dimensionar Vez a cinco, lo piensas mejor y decides que con dos veces es suficiente, pues
nada, haces esto: Redim Preserve Vez(2) y ya est. Lo importante es que slo reserves la memoria que
vas a necesitar.
En la siguiente entrega veremos ms cosas de los arrays, as como algunas otras instrucciones, pero no
te voy a adelantar nada, no sea que despus no est lo que tengo pensado y te mosquees.
Ahora vamos al apartado de los ejercicios, que adems del que te dije casi al principio, te voy a poner
otro ms:
1.) Tienes un array con un nmero cualquiera de elementos, averigua cual de las variables de ese array
es la que tiene el valor mayor.
2.) La que tiene el valor menor y que no sea cero.
Como ves no te quiero que te esfuerces demasiado.
Ya sabes, si hay algo que no hayas terminado de comprender, no dudes en comentarmelo, de esta forma
no seguir enrollandome con cosas que no hayan quedado "super claras". Esto ser en la prxima
entrega, que espero sea dentro de muy poquito, (aprovechando las vacaciones virtuales estas que
tengo), as que si vas a comentarme algo, hazlo pronto.

Curso Bsico de Programacin


en Visual Basic
Novena Entrega: 23/Sep/97.
por Guillermo "guille" Som
Te recomiendo que leas las entregas anteriores, aqu tienes los links:
La Primera, la Segunda, la Tercera, la Cuarta, la Quinta, la Quinta++, la Sexta, la Sptima, la Octava.

Hola, ya ves que no puedo dedicarle todo el tiempo que yo quisiera a esto del curso bsico. Pero lo
importante es que ste siga "pa lante" aunque haya un poco de lapso de tiempo entre cada una de las
entregas... No voy a prometerte que voy a ser ms aplicado y no tardar tanto entre cada entrega porque
a lo mejor no cumplo y despus me echas la bronca...
De todas formas intentar hacer un pequeo esfuerzo... y con la ayuda y compresin de todos vosotros
espero conseguirlo... cmo? pues muy fcil, me gustara que las consultas que recibo no tuviera que
contestarlas todas... es que son muchas, sobre todo se me acumulan los jueves y viernes, ya que esos
das los dedico por completo a la maquetacin de un peridico semanal de informacin local que
editamos en nuestra empresa... y no slo la maquetacin sino que me tengo que encargar de llevar y
recoger la filmacin y hay que hacerlo fuera de Nerja, por lo que a la "paliza" de la autoedicin hay que
aadirle la paliza del viaje de ida/espera (algunas veces larga)/vuelta.
As que si ests interesado en echarme un cable, dimelo y te pondr en la lista de colegas "respondones"
del Guille...
Gracias por adelantado.
Despus de la presentacin y el "comecoco", vamos con las soluciones de los ejercicios.
Solucin a los ejercicios de la Octava entrega
El primero:
'Poner este cdigo en el Form_Load
Dim Hora(24) As Integer

Dim i As Integer, Dim Mayor As Integer


'Llenar el array con nmeros...
'(en esta entrega veremos cmo hacerlo de forma aleatoria)
'...
'Comprobar cual es el mayor
For i = 1 To 24
If Hora(i) > Mayor Then
Mayor = Hora(i)
End If
Next
Print "El nmero mayor es:"; Mayor
Un poco de explicacin, ya que no creo que sea suficiente con ensear la solucin.
El problema que te has podido encontrar es, seguramente, la forma de asignar valores al array, aunque
siempre queda el recurso de poder "llenarlo manualmente"; pero eso lo veremos en esta misma entrega.
La cuestin es comparar el contenido de cada una de las horas con la variable que guardar el nmero
mayor. Al principio esta variable, como ya deberas saber, tiene el valor CERO, as que cuando se haga
la comparacin If Hora(i)>Mayor Then, si la variable que est en la posicin "i" del array "Hora" tiene un
valor mayor que cero, se cumplir la condicin y se pasar a asignar ese valor a la variable que
contendr el nmero mayor de los 24 que tenemos en el array.
El bucle contina y cada vez que se cumpla la condicin de que el contenido de Hora(i) es mayor que el
que tenemos en la variable Mayor, se asignar este y as hasta que se termine de dar vueltas...
Si no te has enterado... preparate para la solucin del segundo ejercicio.
El segundo:
'Los mismos comentarios iniciales que el primero
Dim Hora(24) As Integer
Dim i As Integer, Dim Menor As Integer
'
For i = 1 To 24
If Hora(i) Then
'Slo si no vale cero
If Menor = 0 Then
'Si an no tiene un valor
Menor = Hora(i)
'se lo asignamos
Else
If Hora(i) < Menor Then
'Si el contenido de Hora(i) es menor
Menor = Hora(i)
'lo asignamos como menor
End If
End If
End If
Next
Print "El nmero menor es "; Menor
Este est ms o menos explicado en los comentarios, pero voy a dejartelo un poco ms claro:
La cuestin consiste en comprobar primero si el contenido del elemento "i" del array "Hora" tiene un valor
distinto de cero, (si vale cero no lo tendremos en cuenta), lo siguiente que se hace es comprobar si el
contenido de "Menor" vale cero, si es as, quiere decir que an no le hemos asignado ningn valor, por
tanto le asignamos lo que tenga Hora(i). En posteriores comprobaciones lo que se hace es averiguar si el
valor guardado en el elemento del array es menor que el que tenemos en nuestra variable "Menor" y si
es as, quiere decir que tenemos un nmero ms pequeo, por tanto lo asignamos para que siempre
"Menor" tenga el nmero menor (valga la redundancia).
Pero y si quisieramos tener en cuenta tambin el CERO... Pues que tendramos que hacerlo de otra
forma, ya que esta es slo para el caso expuesto... te dejo que lo pienses, pero no es demasiado difcil,
incluso ms simple que esta solucin, lo que ocurre es que entran en juego pequeos detalles que
seguramente veremos en esta entrega...
Ahora vamos a empezar la Novena Entrega.
No voy a empezar, o mejor dicho, no voy a continuar con los arrays, pero no te preocupes que slo ser
un pequeo alto en el camino, lo que veremos primero es algo que nos va a facilitar hacer pruebas con
los arrays... se trata... (redoble de tambores) de:
Nmeros Aleatorios

En algunos casos vamos a necesitar generar nmeros aleatorios, (nmeros sacados al azar, al menos en
teora...), y si no necesitas usar nmeros aleatorios, vamos a usarlos en algunos de los ejercicios, as
que voy a explicar cmo va esto:
La funcin que se usa para generar nmeros aleatorios es: RND
Esta funcin devuelve un nmero que ser mayor o igual a CERO y menor que UNO. Creo que se
representa as: 0<RND<1, pero si no es as, da igual o algn "experto" me lo dir. Lo que interesa saber
es que nunca llegar a valer uno y que puede ser igual a cero.
Si hacemos esto: x = Rnd * 6 El valor X nunca llegar a 6, en la mayora de los casos se suelen quitar los
decimales usando INT, en este caso, haciendo x = Int(Rnd * 6), x podr valer 0, 1, 2, 3, 4 5 y si
hacemos esto otro: x = Int(Rnd * 6) + 1. Los valores sern de 1 a 6.
Si queremos valores del 65 al 90 la expresin sera esta: x = Int(Rnd * 26) + 65. Ya que Int(Rnd * 26)
producir un nmero que estar entre el 0 y el 25 (ambos inclusives), al sumarle 65... pues eso, estar
en el rango deseado.
Este ejemplo nos sirve para cuando necesitemos obtener un cdigo ASCII de una letra de la A a la Z, (en
maysculas), ya que los cdigos ASCII de las letras son: A=65, B=66... Z=90 en caso de que sean
maysculas, para obtener los valores en minsculas slo hay que aadirle 32 y ya los tendremos porque
a=97, b=98... z=122.
En estos rangos se excluye la ee, tanto maysculas como minsculas y las vocales acentuadas... es
que los seores que crearon esta norma (American Standard Code for Interchange Information, o algo
parecido y se suele pronunciar ASKI), eran de los USA y all no usan esas letras... recuerdo mis tiempos
de comics, cuando Alex Nio se llamaba Alex Nino, al menos en los crditos de los comics USA...
El problema de los nmeros aleatorios no son tan aleatorios, es decir cada vez que se inicia el programa
produce el msmo nmero, (al menos en los basics anteriores, he ledo que ahora el VB4 no genera la
misma secuencia cada vez que se inicia el programa, eso lo veremos despus), vamos a ver un ejemplo
para que lo compruebes, esto lo he comprobado con el VB2 (que es el que tengo en el porttil que me he
llevado a casa para escribir las entregas, hasta que mi jefe me lo pida... que ser en pocos das, puede
ser), se supone que en los dems funcionar igual, pero como te digo para el VB4 hay un "truco" que
veremos despus... cuando lo compruebe, j.
Escribe esto en el Form_Load del nuevo proyecto que habrs tenido que crear para probar... si no lo has
hecho, ya tardas...
Private Sub Form_Load
Show 'Aqu debe estar esto, sino no se ver nada... recuerdas?
Print Rnd * 25
End Sub
A m me ha mostrado 17.63869, ejecutalo varias veces y vers que siempre muestra el mismo nmero...
Existe una forma de solucionar esta falta de "aleatoriedad" y es cambiando la "semilla" que se usa como
base para la imPLANTAcin de nmeros aleatorios, para ello se usa Randomize seguido de un nmero,
pero si el nmero es el mismo... no conseguimos nada... Prueba poniendo Randomize 5 despus del
Show y antes del Print, prueba a ejecutarlo varias veces, a mi me ha mostrado 8.143144 todas las veces
que lo he ejecutado. El problema es que al usar un nmero "fijo" como semilla para la generacin de
nuevos nmeros, el nmero producido siempre es el mismo, esto est bien para hacer pruebas fijas o
cuando queremos "darnosla" de mago con los colegas que saben menos que nosotros, ya que podemos
"predecir" los nmeros que mostrar en una secuencia seguida... con este "truco" dejaba "alucinado" a
los chavales a los que le daba clases... slo tena que memorizar una serie de nmeros y se quedaban
"alucinados" cuando les deca el que iba a salir... claro que despus tena que poner "pies en polvorosa"
cuando les explicaba "la trampa".
Bueno, al tema, que no esplan de contar batallitas... El VB nos proporciona una funcin que devuelve el
nmero de segundos transcurridos desde la media noche (TIMER) y usando esta funcin como "semilla"
lograremos producir nmeros que "casi" ser aleatorios... al menos sern ms difciles de "pronosticar",
cambia el Randomize 5 por Randomize Timer y vers que ya no se produce el mismo nmero cuando
ejecutes varias veces el programa...salvo que hagas "trampas" cambiando la hora del equipo...
Eb VB4 y superior, se puede hacer esto mismo poniendo Randomize -1, de esta forma la "semilla" es
diferente cada vez que se ejecuta, pero prefiero usar el Timer ya que es ms "compatible".
Que tal un jueguecito para practicar?
Hay que hacer un programa que genere un nmero entre uno y cien y hay que intentar adivinarlo...
Si el nmero que damos es mayor o menor, que el VB nos avise y cuando acertemos que nos lo
comunique y termine el programa...
Para que VB se comunique, te voy a decir cmo hacerlo...
Para preguntarte el nmero y guardarlo en la variable N, haz esto:
N = Val(InputBox("Escribe un nmero entre 1 y 100")).
El InputBox muestra una pantalla reguntando y devuelve lo que escribamos o una cadena vaca si
pulsamos en cancelar, el Val convierte esa cadena en nmero.
Para avisar que el nmero N, (el que nosotros le decimos al VB), es menor o mayor, cambiar xxxx por lo
que corresponda:

MsgBox "El nmero " & CStr(N) & " es xxxx"


De esta forma se mostrar un cuadro de dilogo indicando si vamos bien encaminados o no...
Ya mejoraremos o ampliarremos este "ejercicio" para hacer ms cosas, incluso que el ordenador
averige el nmero... que sin ningn tipo de "suerte" lo adivinar en 5 6 veces, lo mismo que tu
debers hacer si sigues algunas normas o trucos... slo decirte lo de "divide y vencers" (no s porqu
me ha dado ahora por esa cita...)
En la prxima entrega veremos ms cosas sobre los arrays...
Si te atreves podras hacer los siguientes cambios al "problemilla" planteado anteriormente:
1. Comprobar que el nmero introducido en el InputBox est entre 1 y 100, en caso de que no sea as,
volver a preguntar.
2. Si se escribe CERO mostrar el nmero que el VB haba "pensado" y terminar.
3. Cuando lo acertemos que nos indique en cuantos intentos lo hemos conseguido.
4. Un programa que sea al revs, es decir: que nosotros pensemos un nmero del 1 al 100 y el VB
intente adivinarlo, para ello deber mostrarnos un nmero y nosotros indicarle si lo ha acertado.
5. Otro igual, pero indicndole si nuestro nmero es Menor, Mayor o es correcto... habr que darle las
mismas oportunidades... (este es el que tiene el "truco" del divide y vencers...
En los casos 4 y 5 que muestre tambin el nmero de intentos que le ha llevado solucionarlo...
La pista para que el ordenador sepa si es menor o mayor es usar el MsgBox, pero como funcin:
If MsgBox("Mi nmero es: " & CStr(x) & Chr$(13) & "He acertado?", 4) = 6 Then
MsgBox "Lo he acertado en " & CStr(v) & " veces."
Exit Do
'...
De esta forma mostrar un cuadro de dilogo con dos opciones "SI" y "NO", el nmero 4 es el encargado
de eso. El valor devuelto ser 6 si se pulsa en SI y 7 si se pulsa en NO.
Esto en VB4 se podra hacer as:
If MsgBox("Mi nmero es: " & CStr(x) & vbCrLf & "He acertado?", vbYesNo) =
vbYes Then
MsgBox "Lo he acertado en " & CStr(v) & " veces."
Exit Do
'...
Con lo cual, aunque sea en ingls, es ms intuitivo. Esto de los MsgBox lo veremos en una entrega
"especial"

Las soluciones estn en este link... no quiero que ests esperando las soluciones hasta la prxima
entrega... para que veas que algunas veces soy un poco "ms considerado"
Bueno, creo que esta entrega no debera tener demasiadas dudas... en los manuales o la ayuda viene
explicado esto de los nmeros aleatroios, pero si quieres dejarme algn comentario, hazlo e intentar
aclararte cualquier duda... pero no lo hagas sobre las soluciones, ya que las obtienes en el link del
prrafo anterior.
Que lo "randomices" bien...

Curso Bsico de Programacin


en Visual Basic
Dcima Entrega: 30/Sep/97.
por Guillermo "guille" Som

Desde aqu puedes enlazar con las entregas anteriores.


La Primera, la Segunda, la Tercera, la Cuarta, la Quinta, la Quinta++, la Sexta, la Sptima, la Octava, la
Novena

Hola, ya estoy de nuevo por estos lares... para seguir dndole caa al curso bsico.
La entrega anterior fu un pequeo alto en el camino antes de continuar nuestra andadura por los
escabrosos caminos de los arrays... UF! Quin ese ese que escribe? Guille!!!

Arrays Multidimensionales
En algunas ocasiones hasta los arrays se quedan cortos... al menos los arrays simples o
unidimensionales, (una sola dimensin), si en el ejemplo de la octava entrega, el de los rascamientos,
quisieras saber las veces que te has rascado cada da del mes... tendramos otra vez el problema,
podramos usar un array para cada da del mes: Dia1(24), Dia2(24)... pero de nuevo tendramos
complicaciones para algunos clculos...
Por suerte para nosotros, existe otra forma de usar los arrays.
En nuestro caso nos servira el que los arrays tuviesen dos dimensiones, al estilo de una tabla con filas
para cada da del mes y columnas para cada una de las horas del da en cuestin, para hacer esto,
dimensionaremos un array de esta forma:
Dim Dias(31, 24) As Integer
Para guardar o recuperar un valor lo haremos de la misma forma que con un array simple, pero
especificando dos valores separados por una coma:
Dias(DiaMes, HoraDia) = 1
y por supuesto, podemos usarlo con bucles FOR:
For Dia = 1 To 31
For Hora = 1 To 24
RascadasMes = RascadasMes + Dias(Dia, Hora)
Next
Next
Despus que estos dos bucles terminen, la variable RascadasMes tendr el total de veces que nos
hemos rascado cada uno de los das de el mes que estamos procesando.
Si queremos almacenar las rascadas de cada da de cada mes de un ao, No Problem!
Dim Meses(12, 31, 24) As Integer
De esta forma solucionaramos en problema, ya que al aadir una tercera dimensin, podemos usar esta
para cada uno de los meses, por ejemplo el total de veces que nos hayamos rascado a las 22 horas del
da 30 del mes 9 (septiembre), estara en: Meses(9, 30, 22)
Reconozco que este ejemplo de las rascada no es til, pero por lo menos hemos visto cmo usar los
arrays. Recuerda quelos arrays pueden ser de cualquier tipo: Integer, String, Double, etc.

Cuantos elementos tiene un array?


En algunas ocasiones podemos necesitar saber el nmero de elementos contenidos en un array, para
estos casos existen dos funciones, una para saber el ndice menor y otra para saber el mayor.
Por ejemplo si tenemos este array: Horas(8 To 22)
El menor sera 8 y el mayor 22, para averiguarlo:
Menor = LBound(Horas)
Mayor = UBound(Horas)
Esta forma es para los arrays unidimensionales, para averiguar estos valores en arrays con ms de una
dimensin, tendremos que especificar la dimensin de la que queremos averiguar ese valor menor o
mayor, por ejemplo, si tenemos Dias(1 To 31, 0 To 23)
MenorMes = LBound(Dias,1) 'Devolvera 1
MayorMes = Ubound(Dias, 1) 'Devolvera 31

MenorHora = LBound(Dias, 2) 'Devolvera 0


MayorHora = UBound(Dias, 2) 'Devolvera 23
Redimensionando arrays multidimensionales
Veamos ahora cmo funciona el Redim y Redim Preserve con los arrays con varias dimensiones: igual
S, da lo mismo que el array tenga una o muchas dimensiones. Lo nico que debemos saber es que no
podemos cambiar el nmero de dimensiones, aunque s el nmero de elementos de cada una de las
dimensiones.
Un ejemplo:
Tenemos inicialmente esta declaracin: Dim Meses(1 To 6, 1 To 31, 0 To 23) As Integer
y necesitamos ampliar la primera dimensin de 6 a 12:
Redim Meses(1 To 12, 1 To 31, 0 To 23) o
Redim Preserve Meses(1 To 12, 1 To 31, 0 To 23) si queremos conservar los valores almacenados.
Lo que no podemos hacer es esto: Redim Meses(1 To 31, 0 To 23)
porque pasamos de tener tres dimensiones a pretender tener slo dos y eso, no est permitido.
Ni al revs tampoco, es decir si tenemos un array con dos dimensiones y queremos que tenga tres.
Si queremos hacer esto ltimo, tendremos que eliminar el primer array y volver a dimensionarlo con las
dimensiones que queramos tener:
Dim Dias(31, 24)
Erase Dias
Dim Dias(12, 31, 24)
El problema es que perdemos los datos... cosa que, en caso de necesidad, podramos solucionar
copiando los datos a otra variable y volviendo a asignarla al nuevo array dimensionado...
Pero muchos de estos problemas se solucionan con las colecciones y el uso del tipo Variant, as como
con los objetos o clases definidas por nosotros... pero eso ser ms adelante... todava hay muchas otras
cosas "esenciales" que aprender y conceptos que siempre debes tener en cuenta... que poco a poco
estoy intentando recalcar para que tu "coco" vaya asimilndolos... espero conseguirlo.

Cuantas dimensiones puede tener un array?


Si la mente no me falla, el nmero de dimensiones es 256. Quin necesita tantas?
Los valores menor y mayor de los ndices estn comprendidos dentro del rango de un valor Integer del
VB, es decir entre -32768 y 32767 osea 65536 valores o ndices distintos. Esto lo comento como
"curiosidad" pero deberas comprobarlo en los manuales.

Unas cadenas, por favor


Ya he comentado en la octava entrega que los arrays tambin permiten asignar cadenas de caracteres,
realmente se pueden tener arrays de cualquier tipo de variables. Pero no mezcladas. Si un array se
dimensiona del tipo Integer slo podremos almacenar valores numricos enteros. Incluso cuando lo
Redimensionemos deber tener el mismo tipo con el que en un principio lo habamos dimensionado.
Este inconveniente se solucionar en una prxima entrega y con las colecciones.
Con lo que sabemos hasta ahora es con lo que vamos a trabajar. Y vamos a practicar un poco con los
arrays de caracteres, para ello vamos a crear un array de cadenas con caracteres aleatorios. No tiene
ninguna utilidad, pero servir para uno de los ejercicios.
Dimensionaremos un array de 100 elementos, a cada uno de esos elementos asignarle entre 10 y 50
caracteres comprendidos entre la A y la Z, recuerda que los cdigos ASCII de la A es el 65 y la Z el 90.
Ahora os pondr una forma "fcil" de clasificar ese array, la parte de la asignacin es la que t tendrs
que hacer.
'

Const MaxCadenas = 100


Dim cadena(1 To MaxCadenas) As String
Dim c As Integer
Dim sTmp As String
Dim i As Integer

Dim j As Integer
Randomize Timer
list1.Clear
'Asignar los valores
'...Escribe aqu tu cdigo...
'Clasificar
For i = 1 To MaxCadenas
For j = 1 To i - 1
'para ordenar de forma descendente:
'If cadena(i) > cadena(j) Then
If cadena(i) < cadena(j) Then
'intercambiar los valores
sTmp = cadena(i)
cadena(i) = cadena(j)
cadena(j) = sTmp
End If
Next
Next
list1.Clear
For i = 1 To MaxCadenas
list1.AddItem cadena(i)
Next
Creo que el procedimiento es lo suficientemente "simple" como para que lo entiendas... verdad?
Lo que debes "observar" en este mtodo es que cada uno de los elementos del bucle i se compara con
todos los anteriores, de forma que si alguno anterior es "mayor" se intercambien las posiciones...
Supn que en la posicin cadena(1) tienes almacenado "HOLA" y en la posicin 2 est la palabra
"AMIGO"
La condicin se cumplir cuando la variable i valga 2 y j valga 1, quedndo por tanto en el orden
correcto.
Lo que debes saber de las cadenas de caracteres es que cuando se hace una comparacin el Visual
Basic comprueba los valores ASCII de las letas que componen la palabra, en este caso la letra A est
antes que la H, as que A es menor que H.
Tambin debers saber que los nmeros estn antes que las letras, por tanto si una cadena de
caracteres empieza por una cifra del 0 al 9, se ordenar antes que la "A" y que la "a" estar despus que
la Z
Si quieres saber los valores ASCII de los caracteres "ms o menos" stndard, haz este bucle:
'Cdigos ASCII
For i = 32 to 122
Debug.Print i; chr$(i)
Next

Ahora los ansiados ejercicios, (realmente ha sido cortita esta entrega verdad?)
Para los ejercicios, usando este trozo para guardar nmeros aleatorios en un array unidimensional,
espero que no tengas problemas para guardarlos en un array multidimensional.
T = Int(Rnd * 31) + 20 'Nmero de rascadas, T valdr de 20 a 50
For i = 1 To T
H = Int(Rnd * 23) + 1 'H valdr de 1 a 23
Horas(H) = Horas(H) + 1
Next
Los ejercicios usando este ejemplo:

1.

Saber que hora tiene el valor mayor y a que hora empezastes a rascarte (es decir la primera
hora del array que contiene un valor)

2.

Que hora fue la tima en que te arrascaste (no necista explicacin...)

3.

Modificar el ejemplo anterior para que el nmero de veces que te rascas valga (aleatoriamente)
de 100 a 1000 y saber tambin cual de estas horas tiene el valor menor (en caso de que haya
varios, slo tienes que averiguar uno de ellos)

Para que no te compliques mucho la vida, decirte que con un par de lneas, puedes averiguar el mayor o
el menor... no sea que quieras hacer un mogolln de comparaciones.
A disfrutarlo!
Esta entrega no da ms de s, no es que haya querido hacerla deprisa y corriendo, es que realmente lo
"bsico" est aqu explicado, si quieres profundizar ms, ya sabes dnde buscar informacin... en los
libracos esos que venan con tu VB.
Si an as, piensas que no te has enterado, dimelo.

Curso Bsico de Programacin


en Visual Basic
Undcima Entrega: 15/Nov/97. (primera parte)
por Guillermo "guille" Som
Desde aqu puedes enlazar con las entregas anteriores.
La Primera, la Segunda, la Tercera, la Cuarta, la Quinta, la Quinta++, la Sexta, la Sptima, la Octava, la
Novena, la Dcima
La segunda parte de la undcima entrega

Cuanto tiempo, verdad? Pues ya ves que no desisto, te costar librarte de mis cursos, j,,j.
Antes de empezar, quiero agradecer a: Pedro Jos Gonzlez Casares piter@arrakis.es por haberse
entretenido en corregir los errores tipogrficos esos que uno suelta de vez en cuando... gracias.
A ver si me acostumbro a escribirlos en el Word y as pasarle el corrector, es que me da algo de pereza y
como me entiendo bien con el FrontPage Express este que incluye el IE4, pues para que cambiar.
Quizs te preguntars porqu no uso el FrontaPage 98 (la beta que es la gratuita) y as puedo pasarle el
corrector... pues porque el diccionario que incorpora est en "gringo" y as cualquiera corrije...
Lo primero es lo primero, as que, en este link tienes las soluciones de los ejercicios de la dcima
entrega.
Y ya vamos al tema de hoy:
Nuestras propias variables
Ya has visto prcticamente la totalidad de tipos de variables que Visual Basic soporta, tambin has visto
cmo agrupar variables para crear arrays.
Ahora voy a explicar cmo puedes crear tus propias variables. Realmente no es crear una variable, sino
un tipo de variable especial en el que se pueden agrupar variables de distintos tipos; es lo que en otros
lenguajes se llaman estructuras.
En Basic son tipos definidos por el usuario (TDU o UDT User Defined Type, que dirian los Englishspeaken esos)
En un UDT podemos incluir variables que estn relacionadas, realmente puedes incluir casi todo lo que
se te ocurra, pero no tendra mucho sentido incluir cosas que no tengan relacin, vamos, digo yo.
Imaginate que quieres hacer una utilidad que dibuje puntos en la pantalla y necesitas tener la posicin

de, digamos 1000 puntos, una solucin sera declarar dos arrays, una para la posicin de la fila y otra
para la columna de cada punto:
Dim PuntoY(1000) As Integer, PuntoX(1000) As Integer
Cuando necesitemos dibujar el punto N en X,Y, haramos algo como esto:
PuntoY(N) = y: PuntoX(N) = x
Y si lo que pretendemos es averiguar la posicin del punto A, lo sabriamos as:
y = PuntoY(A): x = PuntoX(A)
Simplemente estariamos usando un array para la fila (PuntoY) y otro para la columna (PuntoX), para
simplificar todo esto, podemos crear un tipo en el cual tendramos almacenado la posicin de cada punto,
para ello, hay que hacer una declaracin de la siguiente forma:
Type tPunto
X As Integer
Y As Integer
End Type
cada vez que necesitemos una variable de este Nuevo tipo, tendremos que declararla como cualquier
otra variable:
Dim unPunto As tPunto
Mu bonito, pero cmo asignamos los valores?
De una forma muy especial, para acceder a cada uno de los datos que puede almacenar nuestra variable
tendremos que especificar el nombre de la variable, un punto y a continuacin la variable interna que nos
interese...
Veamoslo:
unPunto.X = 100
unPunto.Y = 20
Para saber el valor guardado en la X de nuestra variable lo sabriamos as: columna = unPunto.X
Siempre usando el punto despus de la variable interna, esto puedes encontrartelo en algunos libros o
manuales, usando la expresin: "para acceder a un miembro de una estructura de datos definida por el
usuario..." pero el significado, al final, es el mismo...
Bien, ahora si queremos crear un array para guardar los mil puntos esos a los que me refera al principio:
Dim Puntos(1000) As tPunto
Para almacenar la posicin del punto N:
Puntos(N).X = x: Puntos(N).Y = y
Y seguro que ahora sabrs como obtener la posicin del punto A.
Pero tambin podemos almacenar el punto actual en una variable normal de este tipo y asignar ese valor
a un elemento del array:
Dim PuntoActual As tPunto
PuntoActual.X = un_valor: PuntoActual.Y = otro_valor
Puntos(N) = PuntoActual

Distintos tipos de variables en un tipo definido

Los tipos definidos, no slo sirven para "mezclar" variables del mismo tipo, sino que puedes tener
variables de varios tipos, incluso variables de tipos definidos... S, un verdadero lo...
Espero que despus de leerte esta entrega y con los ejemplos que veremos en las prximas, (cuando le
toque el turno al manejo de ficheros), se te aclararn las dudas.

Otro ejemplo clsico


Este es uno de los ms usados para este tipo especial de variables y la verdad es que es tambin el ms
usado, enseguida sabrs porqu.
Situacin:
Datos:
El Tipo:

Tener los datos de todos los colegas y otros que no lo son tanto.
Nombre y apellidos, direccin, telfono fijo, telfono mvil, direccin e-mail, URL y
cualquier otra cosa que se te ocurra.
Para un caso como este, (simplificando un poco), podramos usar este tipo
definido:
Type tColega
Nombre
As String
Apellidos As String
Direccion As String
Poblacion As String
Edad
As Integer
VecesQueLeHeMandadoUnMailYNoContesta As Long 'Esto por
si soy yo 8-)
End Type

Fijate en el ltimo "campo" del tipo, es una chorrada (aunque ms de uno no pensar as), pero es para
que veas que se pueden usar nombres de variables "super-largos", hasta 40 caracteres! Es decir, que si
te gust Mary Poppins, podras tener una variable que se llamara:
MeGustaSupercalifragilisticoespialidoso.
Ya en serio, no es conveniente el uso de nombres tan largos, no hagas caso de la propaganda esa que
te dicen que es mejor usar nombres descriptivos, ya que es una lata tener que escribirlos!!!
En caso de que te de el "punto" de escribir nombres largos, puedes hacerlo, incluso puedes usar ms de
40 letras, slo que las primeras 40 tienen significado... es decir que si al supercali... ese le aades ms
letras, slo reconocer las 40 primeras.
Por ejemplo:
SupercalifragilisticoespialidosoChitiChitiBangBangVolando
SupercalifragilisticoespialidosoChitiChitiBangBangParado
Para el VB ser la variables (un momento que cuente las letras): SupercalifragilisticoespialidosoChitiChi
De todas formas sigo pensando que es algo tedioso eso de escribir nombres tan largos...
Otro caso de las variables, creo que este an no lo hemos visto, es este:
Cuando vayamos a usar este tipo de variables para guardar los datos en ficheros (dentro de un par de
entregas ya los estars usando), es conveniente "definir" la longitud mxima de las cadenas de
caracteres, por ejemplo:
Reservar 20 caracteres para el nombre 50 para la direccin, en este caso la declaracin de las
variables se haran as:
Dim Nombre
As String * 20
Dim Direccion As String * 50
Y si estn en un tipo definido:
Type tFijos
Nombre
As String * 20
Direccion As String * 50
End Type

La ventaja de hacerlo as: al tener una longitud fija, podemos acceder a cualquier registro haciendo unos
pequeos clculos... aunque de esto se encarga de forma automtica el propio Basic y como he dicho
antes: lo veremos ms despus.

Vamos con algunos ejemplos.


Ya tenemos definido el tipo tColega, si queremos usarlo slo hay que DIMensionar una variable para que
sea de ese tipo:
Dim unColega As tColega
Y para guardar el nombre de ese colega:
unColega.Nombre = "Pepito"
Con los dems campos se hara igual.
Ahora, se nos presenta la situacin de que tenemos, por poner un ejemplo, 50 colegas; as que vamos a
reservar espacio para todos ellos:
Dim misColegas(1 To 50) As tColega
Para almacenar el nombre del colega nmero uno:
misColegas(1).Nombre = "Maria de las Mercedes"
Para mostrarlos, simplemente hacemos un bucle que recorra este array y asunto concluido:
For i = 1 To 50
Print misColegas(i).Nombre, misColegas(i).Apellidos, ...etc.
Next
Que quieres imprimir de forma aleatoria uno de los 50 nombres, digamos para gastarle una inocentada,
pues haces esto:
Print misColegas(Int(Rnd*50)+1).Nombre
Ya sabes, si no lo sabias, ahora lo sabrs, que el ndice de un array, el numerico ese que se pone dentro
de los parntesis, puede ser cualquier expresin numrica, que de como resultado un valor que est
dentro de los lmites de la cantidad de variables que tiene ese array... S, es que si ese valor no est
"dentro" de los elementos que tienes dimensionados, te "regaar" el VB diciendote: Index Out of
Range (osea: T'as pasao, colega)

Un alto en el camino.
Toma papel y lapiz, porque esto es una nueva instruccin.
Ya has visto en el ejemplo de imprimir los 50 nombres, que cada vez que accedes a uno de los campos
(o variables internas) del tipo definido, tienes que usar el nombre de la variable el punto y despus el
campo.
Pues a partir del VB4, este asunto se ha simplificado y no slo para los tipos definidos, ya vers, en un
futuro no muy lejano, calculo que antes del ao 2010, que se puede usar en todas las situaciones en las
que "algo" tenga otros "algos" dentro de l y haya que acceder por medio del punto... Si no lo captas, no
te preocupes, ya te enterars bien...
La palabra mgica es: WITH

No te voy a hacer una presentacin formal de esta instruccin, ya tienes el manual del VB o la ayuda y
all seguro que estar bien "definida", vamos a ver cmo usarla en el ejemplo este que nos traemos entre
manos:
For i = 1 To 50
With misColegas(i)
Print .Nombre, .Apellidos, .Direccion, ...etc.
End With
Next
Ves que fcil! Hasta he puesto otro de los campos...
De esta forma no tienes que repetir el nombre de la variable, el Visual ya sabe que te ests refiriendo
a misColegas(i), porque esa es la variable que has usado despus de With.
Esto mismo se puede usar con cualquier objeto del VB, los tipos definidos no son objetos, pero se
parecen, en unas cuantas de miles de entregas ms, te enterars del porqu...
Por ejemplo para asignar varias de las propiedades de un TextBox llamado Text1:
With Text1
.SelStart = 0
.SelLength = Len(.Text)
End With
Este mismo ejemplo sin With, como lo tendran que hacer con el VB3, sera esto:
Text1.SelStart = 0
Text1.SelLength = Len(Text1.Text)
Como comprobars, est ms claro si se usa el With
Adems, se pueden anidar varios Withs... unos dentro de otros, pero siempre el PUNTO har referencia
al ltimo que se ha puesto, esta situacin ni la voy a "ejemplificar" ya que cuando le toque el turno, le
tocar...

Curso Bsico de Programacin


en Visual Basic
Entrega Doce: 10/Ene/98.
por Guillermo "guille" Som
Desde aqu puedes enlazar con las entregas anteriores.
La Primera, la Segunda, la Tercera, la Cuarta, la Quinta, la Quinta++, la Sexta, la Sptima, la Octava, la
Novena, la Dcima, la Undcima

Antes de empezar, recordarte que ya estn las soluciones de la dcima entrega. Te recomiendo que las
veas y "las estudies", ya que tiene "truco"... y sera conveniente que te enteraras bien del porqu...
Echale un vistazo y vers porqu te lo digo.
Ya vamos al tema de esta entrega... la nmero doce, (duodcima), es que es un lio esto de los nmeros
ordinales, as que usar nmeros normalitos, que todos los entendemos mejor...

Con esta entrega, empiezo la serie de manejo de datos almacenados en disco. As que presta atencin a
esta y las siguientes entregas, para que esto del manejo de la informacin almacenada en disco te sea
fcil de usar.
Adems de las bases de datos, que tambin veremos en este curso bsico... o en las secuelas que
pueda tener... existe una forma de almacenar los datos que nuestra aplicacin pueda manejar. Porque de
qu servira hacer, por ejemplo, un programa tipo editor de textos si no pudiesemos almacenar lo que se
ha escrito...
No, an no te voy a explicar cmo hacer un editor de textos, antes hay que ver algunas cosillas ms,
pero todo llega en esta vida, as que no desesperes...
El Basic maneja tres tipos de ficheros: secuenciales, aleatorios y binarios.
Cada uno tiene una serie de caractersticas en la forma de acceder a los datos.
El ms bsico y tambin el ms empleado, es el secuencial; con este tipo de fichero, los datos se
almacenan y recuperan de forma secuencial, es decir: un dato despus de otro...
El inconveniente que tiene esta forma de almacenar los datos, es que para recuperar lo que est en la
dcima posicin, tenemos que leer los nueve anteriores...
Si tenemos que guardar, por ejemplo, el contenido de un array de strings, lo normal es que lo hagamos
secuencialmente, es decir primero el contenido de la primera variable del array, despus la segunda,
tercera, etc., hasta llegar a la ltima.
Para recuperar estos datos, actuaramos de igual forma, pero asignando al array los datos leidos del
disco. Recuerda que para asignar una posicin N, antes tendremos que leer las N-1 posiciones
anteriores.
La ventaja de esta forma de almacenar los datos, es que la longitud de las cadenas, por ejemplo pueden
ser variables... esto, ahora te parecer una cosa normal, pero lo entenders cuando veamos los otros
tipos de accesos.
Tambin permite que puedas almacenar distintos tipos de datos... no te preocupes, ya sabes que en
estas entregas todo est "demostrado"... ms o menos, ya que la teora est bien para los tericos, pero
para los torpes como yo... lo mejor es la prctica... no es que quiera llamarte torpe... pero, as me siento
menos solo... j, j.
El inconveniente es, como ya he repetido, que para acceder a un dato en concreto, se deben "leer" todos
los anteriores.
Esta inconveniencia del acceso secuencial se arregla usando el acceso aleatorio. Con este tipo de
acceso, puedes leer del fichero el dato almacenado en cualquier posicin, sin tener que leer primero
todos los anteriores... Pero, no todo es perfecto... tambin tiene un "pequeo" inconveniente... que los
datos guardados en un fichero aleatorio deben ocupar el mismo espacio, osea que sean de la misma
longitud... Si guardas cadenas de caracteres, todas ocuparn el mismo espacio en el disco, aunque unas
tengan ms caracteres "vlidos" que otras... Tambin se pueden mezclar nmeros y cadenas de
caracteres... pero eso tiene tambin sus "inconvenientes" o mejor dicho su "truco" para poder usarlo sin
armar un KAOS...
Ya que estamos con los distintos tipos de acceso, te dir as por encima de que va el tipo Binario, ste es
un poco especial y permite leer la informacin almacenada de la forma que queramos, todo depender
de la longitud de la variable que usemos para acceder al fichero... todo estas cosas quedarn explicadas
y aclaradas en esta o en prximas entregas...
Bien, ya sabes que tipos de ficheros puedes manejar con el Visual Basic, ahora vamos a ver como
hacerlo, por supuesto, con las instrucciones correspondientes para poder hacerlo, ya que de eso se
trata... o es que esperabas poder acceder a la informacin de los ficheros sin usar instrucciones del
VB?
Cada vez que quieras abrir un fichero, tienes que usar un nmero de "canal" por el que VB nos
suministrar la informacin, este canal. El canal se indica por medio de un nmero de 1 a 255. Gracias a
este nmero, el Basic se comunica con el sistema operativo para acceder a los datos. El Basic nos
facilita la tarea de conseguir ese nmero, con idea de que no usemos una lnea que est en uso... La
instruccin, en realidad es una funcin, para conseguir un nmero de canal libre, es: Freefile. Esta
funcin devuelve un nmero entero, el cual se almacenar en una variable y as podremos usarlo para el
manejo de los datos almacenados.
NumFic = Freefile

Una vez que conozcamos un canal por el que poder acceder, tendremos que abrirlo:
Open "Prueba.txt" For Output As NumFic
Con esta lnea, abrimos el fichero Prueba.txt de forma secuencial para poder escribir en l.
Una vez que tenemos una "via" de comunicacin, podremos escribir informacin usando una versin un
poco maquillada de la instruccin Print... El maquillaje es el nmero de canal con el que podemos
acceder al fichero:
Print #NumFic, "Lo que sea"
#NumFic es el nmero de fichero (o canal) por el que accedemos al fichero abierto y despus de ese
nmero, usamos una coma y a continuacin lo que queremos guardar en el fichero.
Cuando hayamos acabado de guardar cosas, tendremos que cerrar el fichero que hemos abierto, para
poder liberar ese canal abierto y as poder usarlo en otra ocasin, esto se consigue con el
comando Close:
Close NumFic
Es importante esto de cerrar el fichero abierto, ya que en ese momento es cuando el Basic guarda la
informacin que an tiene "temporalmente" almacenada en una memoria intermedia que usa para que el
acceso a datos sea, al menos en teora, ms rpido. A esta memoria intermedia se le llama "buffer". El
VB la usa para ir guardando la informacin que vamos a grabar fsicamente en el disco, antes de
grabarla, la guarda ah y cuando est llena, la escribe en el disco y la libera, esto se consigue con el
close, para asegurarnos que todo lo que tenga que estar guardao, realmente lo est. El valor de este
bfer para los ficheros secuenciales y aleatorios puede ser de 32767 bytes como mximo, antes con el
Basic del DOS el valor por defecto era de 128 bytes y el mximo de 255 caracteres, pero esto hace
tiempo que cambi y ahora incluso, (al menos en el acceso de 32 bits), aunque en la ayuda no lo indique
as, puede ser mayor que todo eso... Ya tendremos ocasin de comprobarlo.
Todo esto est muy bien, pero si quieres especificar esa longitud... cmo y/o dnde se especifica?
Ahora sabrs cmo y dnde. Para ello vamos a ver cmo se usa al completo la orden OPEN y sus
posibilidades de uso.
Open RutaAcceso [For Modo] [Access acceso] [tipo de bloqueo] As [#]nmerofichero
[Len=longitudregistro]
Lo que est entre corchetes son parmetros opcionales.
Fijate en el detalle que FOR Modo est entre corchetes, esto significa que si no se especifica el modo, el
Visual Basic entiende que quieres acceder de forma aleatoria. La explicacin de cada uno de estos
parmetros los tienes en la ayuda, as que si no quieres esperar a que los explique todos, vete a la
ayuda y le echas un vistazo.
Yo empezar a explicarte lo que ahora necesitas saber y poco a poco iremos viendo las distintas
posibilidades... Pero si no quieres esperar... ya sabes... echa mano del F1 y accede a la explicacin de la
ayuda o del manual...
Vamos a ver lo que nos interesa de esta instruccin:

RutaAcceso

Modo

As NmeroFichero

El path completo, o a medias, de dnde queremos que se almacene el fichero


o el lugar en el que est almacenado.
Por ejemplo: C:\Datos\Un directorio\Prueba.txt
.\Algo\Prueba.txt, siempre que en el directorio actual haya un directorio que
se llame "Algo"
o simplemente Prueba.txt (esto le indicar que estar en el directorio actual)
Output, para ficheros de salida, es decir para guardar los datos.
Si el fichero existe, lo borrar (sobreescribir) y si no existe, lo crear.
Input, para leer los datos de un fichero ya existente.
Append, como el Output, pero aadiendo la informacin al final del fichero,
si este ya existe.
Random, para acceso aleatorio.
Binary, para acceso binario.
Aqu se indica el nmero de fichero (canal) por el que accederemos a la
informacin.
El signo de nmero (#) es opcional. Y NmeroFichero, puede ser una variable
o una constante.

Las otras opciones ya las veremos, ahora nos centraremos en las cosas que son ms fciles, siempre
hay tiempo para complicarse la vida, as que nos la complicaremos ms adelante, cuando ya tengamos
un poco de idea de todo este folln...
RutaAcceso, a estas alturas deberas saber de que va todo esto del PATH, pero si no lo sabes, te lo
explico por encima: un path es una ruta de acceso a un fichero... comor? Pues eso, si quieres guardar
la informacin en el disco, tendrs que saber en que parte del disco la quieres guardar, incluso en que
disco quieres almacenarla. Y lo ms importante, cmo vas a llamar el sitio en el que se guardar. Esto es
un poco como las variables, si quieres tener distintas cosas en la memoria del Basic, usas distintos
nombres de variables, pues lo mismo con los ficheros, usando distintos nombres de ficehros puedes
tener informacin diferente almacenada en el disco.
Para empezar, debes saber que tienes que usar un nombre en el que almacenar la informacin que
quieres "conservar", para despus poder acceder a ella en el momento que la necesites.
La ventaja de esto con respecto a los nombres de las variables es que puedes usar distintas partes del
disco para guardar esa informacin, aunque el nombre "real" del fichero sea el mismo...
A ver, si quieres guardar los rascones esos que te dabas en las entregas anteriores, pudes decirle al
Basic que quieres usar un fichero que se llame: rascones. Pero suponte que quieres tener todos los
rascones de todos los meses del ao almacenados en distintos ficheros, uno para cada mes. Podras
hacer algo como esto: darle a cada fichero un nombre diferene o bien usar la "extensin" del fichero para
cada uno de los meses...
Por ejemplo: rascones.ene para enero, rascones.dic para los de diciembre... etc.
Y si quieres que esos datos se guarden en el disco A, pues slo tienes que decirle que el fichero se
llama: A:\rascones.ene
Si tienes la intencin de guardar cada grupo de ficheros en carpetas (directorios) diferentes, tambin
puedes indicarselo en la ruta esta de acceso: C:\Datos\A1998\rascones.ene
Por supuesto para poder hacer esto ltimo debes tener un disco C (quin no lo tiene?), un directorio
A1998 que est dentro de otro llamado Datos que est a su vez en el directorio raz del mencionado
disco C.
En caso que no se especifique la ruta completa, el Visual Basic usar el directorio actual para acceder al
fichero.
Debes saber que el visual crear el fichero indicado, pero si no existen los directorios o no puede tener
acceso a ellos, dar error y no abrir el fichero. Que error? El nmero 76: Path not found (No se ha
encontrado la ruta de acceso)
Hay ms errores, muchos, pero estos ya te los irs encontrando y en su meomento veremos cmo poder
detectarlos.
Veremos tambin cmo crear las rutas esas de acceso, en caso de que no existan, para as asegurarnos
que existen antes de guardar la informacin en el disco... pero todo a su debido tiempo...
Ahora lo que vamos a ver es unos ejemplos de cmo guardar informacin y despus poder "leerla", ya
que esto es lo ms bsico y lo que en principio debemos saber.

Cmo guardar la informacin?


Ya te he dicho antes de que con Print se puede guardar la informacin en el disco, veamos cmo:
Print #NumFic, Nombre
Print #NumFic, 125
Tambin podemos guardar esta misma informacin as:
Print #NumFic, Nombre, 125
Es decir que si quieremos guardar varias cosas con una misma instruccin, lo haremos usando una
coma como separador. De esta forma cada cosa que est separada se guardar en el disco en "lneas"
distintas.

Cmo leer la informacin?


Para poder leer la informacin, adems de abrir el archivo para lectura modo INPUT, hay que usar una
de estas instrucciones:

Input #NumFic, Variable


Tambin con: Line Input #NumFic, variable.
La diferencia entre el Input y el Line Input la veremos dentro de un ratillo.
Antes tendremos que ver cmo acceder a ese nombre y a ese nmero que antes hemos guardado...
Input #NuFic, unNombre, unNumero
Un detalle que debes tener en cuenta es que si el Nombre que guardamos tiene alguna coma, puede que
no accedas a los datos como pretendas... Vamos a verlo con un ejemplo. Crea un nuevo proyecto en el
VB y aade dos botones (CommandButton), escribe este cdigo y pruebas:

Private Sub Command1_Click()


Dim Nombre$, Num%
Dim NumFic%
Nombre = "Prez, Pepito"
Num = 22
NumFic = FreeFile
Open "C:\Prueba.txt" For Output As NumFic
Print #NumFic, Nombre, Num
Close NumFic
End Sub
Private Sub Command2_Click()
Dim Cadena$, Numero%
Dim nF%
nF = FreeFile
Open "C:\Prueba.txt" For Input As nF
Input #nF, Cadena, Numero
Close nF
MsgBox "Cadena= " & Cadena & vbCrLf & _
"Nmero= " & Numero
End Sub
Ahora pulsa en F5 y dale primero al botn Command1, despus le das al Command2 y vers que no te
muestra lo esperado.
En lugar de mostrar:
Cadena= Prez, Pepito
Nmero= 22
Te ha mostrado:
Cadena= Prez
Nmero= 0
Que ha ocurrido?
En primer lugar, decirte que esto mismo con el Basic del MS-DOS hubiese dado un error, pero debido a
como maneja el VB las variables, se ha tragado lo que ha encontrado... Que ha encontrado? Pues que
tiene que asignar a Cadena la "palabra" Prez y a la variable Numero el "nmero" Pepito... que al no ser
un nmero, le ha dado el valor cero...
Esto es debido a que cuando INPUT lee los datos espera una coma o el final de lnea para "distinguir"
entre los diferentes datos a asignar a las variables indicadas.
Vale, dirs, pongamoslo en distintas lneas y as los leer correctamente:
Input #nF, Cadena
Input #nF, Numero

Pero con esto no lo solucionars, pruebalo y vers que tengo razn.


De gente desconfiada est el mundo lleno! ...no te he dicho que dara el mismo resultado... HUM!
Bien, cmo solucionarlo?
Lo has adivinado? Pues eso mismo, usando el Line Input... Pero con Line Input no se pueden
especificar ms de una variable en la misma instruccin... as que ponlas en dos lneas.
Line Input #nF, Cadena
Line Input #nF, Numero
OPS! Que ha ocurrido?
Si has pulsado simplemente F5, te habr dado un error al pulsar en el segundo botn... Y si has pulsado
Control+F5, te habr indicado, con el mismo error, que los tipos no coinciden, (si usas la versin inglesa:
Type Mismatch)
Esto es debido a que Line Input slo puede leer cadenas de caracteres, mejor dicho slo se pueden usar
variables de tipo string (cadena), ya que esta instruccin lee todo lo que hay en la lnea actual del fichero
abierto, hasta el final de la lnea.
Cmo solucionarlo?
Usando una variable intermedia o simplemente usando el INPUT normal para leer el nmero.
Veamos cmo sera de las dos formas:
Line Input #nF, Cadena
Input #nF, Numero
Dim sTmp$
Line Input #nF, Cadena
Line Input #nF, sTmp
Numero = Val(sTmp)
Ahora si que tendremos el resultado correcto:
Cadena= Prez, Pepito
Nmero= 22
EXACTO! Tampoco nos ha mostrado esto...
Por qu?
Muy sencillo, realmente no es sencillo, sino que despus de que me haya ocurrido como dos millones de
veces, resulta hasta lgico... 8-(
Si miras el contenido del ficehro C:\Prueba.txt, te dars cuenta de que el contenido de este fichero es:
Prez, Pepito 22
Entre Pepito y el 22 hay un tabulador, chr$(9). Esto es debido a que Print x, y muestra los valores en
distintas "posiciones" de tabulacin, lo mismo ocurre cuando se guarda en el disco...
Para solucionar todo esto y hacer que la cosa funcione bien, te aconsejo que cada dato lo guardes con
distintas instrucciones Print, de esta forma cada dato se guarda en distintas lneas del fichero.
As que cambia el cdigo del Command1, para que en lugar de un slo Print, haya dos:
Print #NumFic, Nombre
Print #NumFic, Num
Ahora todo debe funcionar bien.
Vale, pruebalo si no te fias...
Tena yo razn? Pues claro, ...ya que lo he comprobado antes... ;-)
Si no sabemos el tipo de datos que tenemos almacenado, lo mejor es usar la intruccin Line Input y as
nos curamos en salud, pero si sabemos que, por ejemplo, todos los datos son numricos y se han
almacenado sin usar comas...
Mejor un ejemplo:
En este caso vamos a guardar en un array una serie de nmeros aleatorios, los vamos a guardar en un
fichero y despus los leeremos para asignarlos en otro array y los mostraremos en un label.

Para hacerlo, crea un nuevo proyecto, el anterior lo puedes borrar ya que es de una inutilidad total.
Aade un Label que ocupe prcticamente todo el Form, salvo la parte de abajo, en la que pondrs dos
botones.
Pega el cdigo este que te pongo, pulsa F5 y primero pulsa en el Command1, para despus pulsar en el
Command2
Private
Dim
Dim
Dim

Sub Command1_Click()
Numeros(1 To 10) As Integer
i%
nFic%

Randomize
'Asignamos los valores
For i = 1 To 10
Numeros(i) = Int(Rnd * 100) + 1
Next
'Abrimos el fichero
nFic = FreeFile
Open "C:\Prueba.txt" For Output As nFic
For i = 1 To 10
Print #nFic, Numeros(i)
Next
Close nFic
Label1 = "Nmeros guardados en el disco"
End Sub
Private
Dim
Dim
Dim

Sub Command2_Click()
MasNumeros(1 To 10) As Integer
i%
nFic%

'Abrimos el fichero para leer los datos


nFic = FreeFile
Open "C:\Prueba.txt" For Input As nFic
For i = 1 To 10
Input #nFic, MasNumeros(i)
Next
Close nFic
'Asignamos estos nmeros al label:
Label1 = ""
For i = 1 To 10
Label1 = Label1 & MasNumeros(i) & vbCrLf
Next
End Sub
Este es un ejemplo sencillo de cmo asignar datos a un array, guardarlos en el disco y despus leerlos.
Y hasta aqu hemos llegado...
Como ejercicio, haz un programa que al pulsar en un botn, te pida diez nombres, los guarde en un
fichero y despus pulsando en otro botn los muestre en un label.
No es necesario que uses un array para guardar los datos, pero podras hacer dos versiones, con y sin
un array.
Como pista te recordar que la funcin InputBox puede servirte para esto de preguntar, ya que el valor
que devuelve es la cadena de caracteres introducida en la caja de dilogo que muestra.
Esto del InputBox ya lo vimos en la novena entrega, o en las soluciones, pero te explico brevemente
cmo funciona:
variable$=InputBox("Escribe un nombre")
Facil, verdad? Pues esa es toda la pista que te voy a dar.

Ahora se "legal" y no veas las soluciones de esta entrega hasta que lo hayas hecho t.
En la pgina de las soluciones tienes un "extra", as que aunque sepas cmo hacerlo... te pasas a verla...
vale?
Espero que te haya resultado instructiva esta entrega, a pesar de haberte dejado con la miel en la boca,
pero as son las cosas y no es plan de darlo todo de golpe.
Para cuando la siguiente entrega? Ah!, misterios de la vida... eso ni se sabe. As que permanece a la
escucha y ya vers cuando... no quiero prometer que ser pronto, que despus me regaas... as, que...
a esperar!
Si hay algo que no entiendas o simplemente quieres hacer algn comentario sobre esta entrega o
cualquier otro tipo de peloteo o lo que te de la gana decirme sobre el curso bsico, usa este link...
Pero no lo aproveches para las consultas... que te conozco rosco!

Curso Bsico de Programacin


en Visual Basic
Entrega Trece: 10/Feb/98
por Guillermo "guille" Som
Si necesitas ver cualquiera de las entregas anteriores, aqu tienes los links:
La Primera, la Segunda, la Tercera, la Cuarta, la Quinta, la Quinta++, la Sexta, la Sptima, la Octava, la
Novena, la Dcima, la Undcima, la Doce

Desde luego que los das pasan como horas... no s si ser la edad, pero... Jo! Cuando he visto la fecha
de la entrega anterior... Hace un mes !!!
No voy a prometerte nada, pero har un pequeo esfuerzo para acelerar los plazos de entrega, sino,
puede que te aburras o decidas cambiar de profe...
La solucin sera: disponer de un porttil... pero... en fin... Esto de la esponsorizacin no da para tanto...
lo mismo a t te sobra uno... ejem!
Bueno, despus de la "necesaria" introduccin, vamos a lo que te ha traido por aqu; ya que me imagino
que no es precisamente el saber que "necesito" un porttil... esto... si es un Pentium 200, con un mnimo
de 32 megas de RAM, pantalla SVGA color, disco duro de un par de Gigas y modem... pues mejor... je,je,
nunca se sabe si te puedes encontrar con un alma caritativa... y, como dice el refrn: "El que no llora no
mama..." ;-)
Guille! Djate de chorradas y vamos al tema! (esta es la voz de mi conciencia: mi otro yo)
En la entrega anterior ya vimos cmo guardar y recuperar informacin de un fichero; vamos a seguir con
el tipo secuencial, pero esta vez vamos a leer todo el contenido de una sola vez, para ello vamos a usar
dos nuevas funciones: LOF e INPUT.
No te confundas con la funcin INPUT, ahora vers que no se usa de igual forma de como usamos
anteriormente la "instruccin", recuerda que esta nueva, es una funcin y las funciones siempre
devuelven un valor. La que antes usamos era una instruccin y las instrucciones hacen algo, pero no
devuelven valores... ya vers que esto mismo se puede aplicar a las funciones; ya que estamos en ello, y
a ttulo de curiosidad, si no quieres usar el valor devuelto por una funcin, cosa que se hace muchas
veces con las llamadas al API de Windows, debers hacerlo anteponindole a la funcin la instruccin
CALL. Esto lo veremos cuando empecemos con el API, que, aunque te parezca que es un tema
avanzado, lo empezaremos a ver muy pronto.
Ahora veamos cmo usar esas dos funciones:
variable = LOF(#canal)
Esta funcin devuelve, en bytes, el tamao del fichero abierto con el canal indicado dentro del parntesis.

LOF es la abreviatura de: Length Of File (longitud del fichero).


Por tanto si queremos saber la longitud de un fichero, lo abrimos, asignamos a una variable el valor
devuelto por LOF y despus hacemos lo que tengamos que hacer... Que slo quieres averiguar la
longitud, pues lo cierras y ya est, por ejemplo:
Dim nFic As Integer
Dim sFic As String
Dim tamFic As Long
sFic = "C:\Autoexec.bat"
nFic = Freefile
Open sFic For Input As nFic
tamFic = Lof(nFic)
Close nFic
MsgBox "El tamao de " & sFic & vbCrLf & "es de " & tamFic & " bytes"
La verdad es que si lo que pretendes es saber la longitud de un fichero, puedes usar la funcin FileLen,
sta se usa poniendo el nombre del fichero entre los parntesis y tambin devuelve el tamao en bytes:
(Tanto una funcin como la otra devuelven un valor LONG)
Dim sFic As String
sFic = InputBox("Nombre del fichero:", "Mostrar tamao", "C:\Autoexec.bat")
If Len(sFic) Then
MsgBox "El tamao de " & sFic & vbCrLf & "es de " & FileLen(sFic) & "
bytes"
End If
Este trozo de cdigo te preguntar, (usando InputBox), el nombre de un fichero, por defecto te mostrar
C:\Autoexec.bat y si se ha escrito algo, mostrar el tamao en bytes.
Fijate que el valor devuelto por una funcin no slo se puede asignar a una variable, sino que tambin se
puede usar directamente. Si, ya s que lo he dicho en otras ocasiones, pero lo repito para que no te
quede duda.
Ahora veamos cmo "funciona" la funcin INPUT:
Esta funcin devuelve una cadena con el contenido de un fichero que est abierto... realmente devuelve
el nmero de caracteres que le indiquemos y esos caracteres los tomar del fichero abierto con el "canal"
indicado, veamos cmo usarla:
cadena = Input$(numCar, #canal)
El signo dlar ($), lo uso para saber que estoy trabajando con una funcin que devuelve un valor de
cadena...
La mayora de este tipo de funciones del Visual Basic, devuelven indistintamente un valor variant o string,
para obligarle a que devuelva una cadena, debemos ponerle al final el signo $, ni que decir tiene que
esto slo es vlido para las funciones que devuelvan cadenas de caracteres, no para las que devuelvan
otro tipo de datos... Pero no te preocupes de este tema, ya que el VB se encarga de hacer lo que tenga
que hacer para que obtengas lo que tienes que obtener... Que lio!!!
Ahora vamos a ver cmo podemos leer todo el contenido de un fichero y asignarlo en una variable de
cadena:
Dim
Dim
Dim
Dim

nFic As Integer
sFic As String
tamFic As Long
sContenido As String

sFic = InputBox("Nombre del fichero:", "Mostrar fichero", "C:\Autoexec.bat")


If Len(Dir$(sFic)) Then
nFic = FreeFile
Open sFic For Input As nFic
tamFic = LOF(nFic)

sContenido = Input$(tamFic, nFic)


Close nFic
MsgBox sContenido
End If
Fijate que uso un MsgBox para mostrarlo, en caso de que el contenido del fichero sea "demasiado"
grande, el botn Aceptar no se ver... tienes dos opciones: pulsar Intro o ESC, de esta forma quitars el
mensaje de la pantalla, a pesar de que no tenga "visible" el botn Aceptar.
Un par de detalles, la funcin Input$() devuelve una cadena de caracteres, el tamao mximo de
caracteres que admite estar delimitado por el sitema operativo y sobre todo por la versin del VB, en 32
bits este tamao "casi" no tiene lmite, pero en 16 bits, ser de 64 KB como mximo.
El otro detalle es que la comprobacin que se hace para saber si existe el fichero, no es a prueba de
"manazas". Me explico: si el nombre que se indica en sFic no existe y/o el path indicado tampoco, no
pasa nada, todo funcionar bien; pero si le indicas la unidad A, o cualquier otra, cuando no hay disco
insertado, la cosa deja de funcionar y te mostrar un error.
Pero todo esto tiene solucin, ahora mismo te dir cual es, pero antes voy a desglosarte el
funcionamiento de Len(Dir$(...))
Fijate que aqu se usan dos funciones:
Len(Cadena)

Esta funcin devuelve el nmero de caracteres de la cadena indicada

Dir$(sFichero)

Esta otra, lo que devuelve es el nombre del primer fichero que coincida con la
"especificacin" indicada en sFichero, en caso de que no haya coincidencias,
devolver una cadena vaca.

Por tanto, si no existe el fichero, Dir$ devuelve una cadena vaca y la longitud de una cadena vaca es
CERO, as que en la comparacin, If Len(Dir$(sFic)) Then Visual Basic sustituir Len(Dir$
(sFic)) por el valor devuelto, recuerda que para IF un cero significa FALSO y cualquier otro valor ser
VERDADERO, insisto en este punto, ya explicado anteriormente, para que se te quede claro.
Lo que quizs no sepas es que en Dir$(sFic), sFic puede contener signos comodines (? y/o *), para
indicar cualquier tipo de fichero. Esto se suele usar tambin en las rutinas de bsqueda que se hacen en
las bases de datos, as que mejor que te vayas enterando cmo usarlo y "buscar" por ah informacin, ya
que aqu te voy a explicar un poco el significado, para que lo puedas usar al indicar los ficheros.
Como "aadido", decirte que en el sistema de bsqueda del Windows 95, tambin puedes buscar
ficheros o contenidos, usando estos comodines.
La interrogacin (?) se usa para indicar que no nos importa el carcter que haya en esa posicin.
El asterisco (*) sirve para que nos devuelva todos los que tengan los caracteres anteriores a este
signo, pero que los restantes no los tenga en cuenta.
Ejemplos: (las pruebas se pueden hacer desde una ventana del MS-DOS, usando el comando DIR)
Dir Auto*.bat
Dir Auto*
o
Dir Auto*.*
Dir A?t*.*

Dir Dato??98.txt

Mostrar todos los ficheros que empiecen por Auto y que la extensin
sea .bat
Todos los ficheros que empiecen por Auto, sin importar ni la extensin ni
nada, ya que al usar .* se indica que cualquier cosa es vlida.
Es recomendable usar la segunda forma.
Mostrar todos los ficheros que la primera letra sea A y la tercera T,
como se usan *, esto indica que nos da igual lo que haya despus de la
T, por tanto si tuviesemos ficheros llamados: Arte.txt, Autoexec.bat,
Automovil.doc, Arial.ttf, nos devolvera los tres primeros, porque
coinciden en lo indicado.
Nos devolver todos los ficheros que tengan en las 4 primeras letras la
palabra dato y en las posiciones 7 y 8 el nmero 98, la extensin ser
txt. Adems en las posiciones 5 y 6 podr tener cualquier cosa, pero
deber tener 8 caracteres.
As que Dato0198.txt, dato1298.txt sera nombre encontrados, pero no lo
sera: data0198.txt ni dato0298.doc, en el primer caso, porque empieza
con la palabra data y en el segundo porque la extensin no es txt

Una vez visto, por encima, esto de los signos comodines, vamos a ver cmo hacer nuestra forma de
comprobar si existe un ficheros, algo ms fiable y segura.
Para ello, vamos a crear una funcin que se llame: Existe y esta funcin devolver FALSO (cero) si el
fichero no existe y en caso de que exista, devolver VERDADERO (-1)
Esta funcin podremos usarla de cualquiera de estas dos formas:
If Existe(unFichero) Then
'Si existe, hacer lo que corresponda
End If
If Not Existe(unFichero) Then
'El fichero en cuestin no existe
End If
Para poder "detectar", o interceptar, los posibles errores que se produzcan al intentar comprobar si existe
el fichero, usaremos esto:
On [Local] Error Resume Next
Con estas instrucciones, se le indica al Visual Basic que en caso de que se produzca un error, "pase" de
ese error y continue con la siguiente instruccin.
Esto est bien, pero... cmo sabremos que se ha producido el error? ya que, si continua... pues... eso,
no se detiene...
Respuesta: Usando la funcin ERR.
Esta funcin devuelve el nmero del error que se haya producido, o cero si no se produjo error.
A partir del VB4, esta funcin se puede sustituir por la propiedad Number del objeto Err, por
tanto Err.Number tambin nos dir que nmero de error se ha producido, ten en cuenta que Number es
la propiedad por defecto de este objeto.
Pero como quiero que este curso bsico sea lo ms genrico posible y no se incline slo por el VB4 o
superior... pues intentar usar funciones que sean compatibles... aunque tampoco prometo nada, as que
te recomiendo que dejes de lado las versiones de 16 bits o al menos la versin 3 del VB, porque esta
"consideracin" que estoy teniendo puede que cambie... de hecho seguramente pondr cosas que slo
estarn disponibles a partir de la versin 4... y cuando la cosa vaya avanzando ms, incluso slo cosas
de la versin 5... aunque para esas fechas ya estar en el mercado el VB7, por lo menos...
El caso es que yo estoy acostumbrado a usar ERR, as que... eso es lo que hay... je, je.
Y ya sin ms rodeos, veamos cmo quedara la funcin Existe, si te fijas es casi igual que la que puse
hace ya algunas entregas, pero usando la deteccin de errores:
Private Function Existe(ByVal unFichero As String) As Boolean
On Local Error Resume Next
Existe = Len(Dir$(unFichero))
If Err Then
Existe = False
End If
Err = 0
On Local Error GoTo 0
End Function
Te explico cada una de las lneas:
Private Function Existe(ByVal unFichero As String) As Boolean
Esta es la declaracin de la funcin, el Private es por si lo quieres usar en un form, o en cualquier otro
mdulo, pero que slo sea visible para el cdigo de ese mdulo.
Si quieres que est visible en todo el proyecto, cosa recomendable para este tipo de funciones, cambia el
Private por Public y escribe el cdigo en un mdulo BAS. As podrs usarlo en cualquier form o mdulo
que tengas en tu proyecto.
Veamos porqu he declarado el parmetro de esta forma: Byval unFichero As String
Este es el parmetro que le pasamos a la funcin, es decir: el fichero o especificacin que queremos

comprobar si existe. Lo de especificacin es porque puedes usar esta funcin para saber si existen
archivos que empiecen por la A, asignando al parmetro los comodines que creas necesarios: If
Existe("C:\A*.*") Thencomprobar si en el directorio raiz de la unidad C hay archivos que empiecen por
la letra A.
El ByVal le indica al Visual que use una copia del parmetro, con lo cual evitaremos que el cdigo de
nuestra funcin lo modifique; ya que al usar una copia, no tenemos acceso al original, esto tambin
acelera el manejo de nuestra funcin.
El As Boolean del final, es el tipo de dato que devolver nuestra funcin, tambin se podra usar Integer,
de esta forma, si ests usando el VB3, podrs usar la funcin, sin mayor problema.
On Local Error Resume Next
Esta es la instruccin que pone en marcha la deteccin de errores.
Local es para indicarle al VB que slo est operativa dentro de esta funcin, sirve para que, en caso de
que externamente haya otro mecanismo de deteccin de errores, el que est operativo sea el que
acabamos de declarar... cuando abandonemos la funcin seguir funcionando la otra rutina que hubiera.
Existe = Len(Dir$(unFichero))
Asigna a Existe la cantidad de caracteres devueltos por la funcin DIR. Al ser del tipo Boolean, el VB
automticamente asigna Verdadero o Falso.
En el caso de que la funcin se haya declarado como Integer, un cero indica que es falso y cualquier otro
valor que es verdadero, por tanto la cosa funcionar igualmente independientemente del tipo devuelto
por esta funcin.
Seguro?
Veamos un ejemplo:
If Not Existe("algo.txt") Then
MsgBox "El fichero indicado no existe"
End If
Prueba esto cambiando el tipo de dato devuelto por la funcin Existe, cuando lo pongas como
Integer, siempre te dir que no existe el fichero...
La explicacin de porqu ocurre esto, ya lo vimos anteriormente, y es porque NOT Un_Nmero,
devuelve un nmero, no un cero... Y recuerda que, cuando Existe es del tipo Integer, devuelve el nmero
de caracteres...
Si quieres que slo devuelva 0 -1 para que sea igual que False/True, podras hacer esto otro:
Existe = Len(Dir$(unFichero)) <> 0
De esta forma se evalua la expresin y en caso de que sea cierto que el resultado es distinto de cero, se
asignar un -1, en cualquier otro caso se asignar un cero y ahora si que actuar igual que si el tipo
devuelto fuese boolean.
If Err Then
Ahora comprobamos si se produjo algn error al intentar buscar el fichero en cuestin.
En el supuesto de que se produzca un error, se pasar a la lnea despus del IF, asignando FALSE al
valor que devolver la funcin. Como sabrs o te habrs imaginado, el valor que debe devolver una
funcin se asigna al nombre de la funcin, en otros lenguajes se usa RETURN valor, por ejemplo en C o
en el JavaScript...
Por tanto, Existe = False, slo se asignar cuando se produzca un error.
Err = 0
Esta es una de esas recomendaciones "obligatorias" que yo hara siempre que uses el Resume Next, en
este caso no es necesario porque el cdigo de la funcin termina ah, pero si hubiese ms cdigo, ese
valor de error seguira asignado a Err y cualquier otra comparacin posterior al objeto Err, podra "alterar"

el buen funcionamiento de nuestro programa.


(Recuerda que en VB4 o posterior, realmente se asigna a la propiedad Number del objeto Err)
On Local Error Goto 0
Esta ltima lnea "libera" la deteccin de errores de esta funcin, en nuestro caso, tampoco es necesaria,
ya que al finalizar un procedimiento, cualquier rutina de deteccin de errores se elimina. Esto, al igual
que lo dicho anteriormente, sirve si queremos dejar de detectar errores en las siguientes lneas de
nuestra rutina. Como ya no hay ms lneas de cdigo, la verdad es que no es necesaria, pero suelo
usarla siempre, costumbres que tiene uno de saber cuando dejo de interceptar los errores.
Bien, ya tenemos nuestra funcin a prueba de usuarios inexpertos o con malas intenciones... tambin
para los olvidadizos...
Por qu me miras?
Es que nunca has intentado acceder a la unidad A cuando an no has insertado un disquete?
Pues yo s... je, je...
Vamos a probarla.
Crea un nuevo proyecto, agrega un mdulo bas.
Asegurate que tiene Option Explicit al principio, ya sabes que esto es para que cualquier error tipogrfico
al escribir una variable, no obligar al VB a crearla, sino que nos avisar de que esa variable no existe,
es decir, sirve para obligarnos a declarar todas las variables que vayamos a usar.
Ahora copia y pega o escribela nuevamente, la declaracin de la funcin Existe, asegurate que sea
pblica y no privada.
Cierra el mdulo y asegurate que el Form1 est visible y en modo de diseo, es decir que se vea el
Form. Aade un Label, un TextBox y un CommandButton.
Modifica el caption del label para que contenga este texto: Fichero a comprobar:
En el caption del botn escribe: Comprobar.
Situa los controles para que tengan un aspecto "agradable" y escribe lo siguiente en el
Command1_Click:
Private Sub Command1_Click()
If Existe(Text1.Text) Then
MsgBox "Si existe el fichero: " & Text1.Text
Else
MsgBox "NO EXISTE el fichero: " & Text1.Text
End If
End Sub
Prueba a escribir en el TextBox signos comodines para comprobar que todo funciona, por ejemplo: *.bas
Igualmente escribe algn nombre que sepas que no existe... y para salir de dudas, intenta acceder a un
fichero de la unidad A, pero sin poner un disco...
Todo correcto, verdad?
Pues me alegro, de que as sea...
No, no te preocupes que no hay "gato" encerrado... bueno, s, los tres que tengo en mi casa, pero esos
no tienen nada que ver con el programa...
No te voy a poner ningn ejercicio en esta entrega, ya lo har en la siguiente, as que paciencia y no
desesperes, que ya la tengo escrita en papel, por tanto puede que maana mismo est en lnea... es que
si contino, se me va a pasar la hora y quiero que sea hoy dia diez el da que publique esta entrega...
chorradillas que se le ocurren a uno...

Como es habitual, y las buenas costumbres no hay que perderlas, si quieres hacer algn comentario
sobre esta entrega o sobre el curso bsico en general... o tienes ese porttil que me hara tan feliz... y
me lo quieres regalar, claro, usa este link

Curso Bsico de Programacin


en Visual Basic
Entrega Catorce: 14/Feb/98
por Guillermo "guille" Som
Desde aqu puedes enlazar con las entregas anteriores.
La Primera, la Segunda, la Tercera, la Cuarta, la Quinta, la Quinta++, la Sexta, la Sptima, la Octava, la
Novena, la Dcima, la Undcima, la Doce, la Trece

No ha sido al da siguiente, pero tampoco ha pasado un mes, as que espero que no te quejes
demasiado.
Voy a continuar con el tema del DIR$, para ello vamos a hacer un programilla que nos muestre todos los
ficheros que coincidan con la especificacin indicada... recuerdas lo de los comodines? Pues en eso
nos vamos a enfocar ahora, es decir, servir para que te muestre todos los ficheros BAS de un directorio
o lo que quieras...
Para ello vamos a usar un control que hasta ahora slo lo hemos visto, pero sin entrar en detalles sobre
l: el ListBox.
Tambin vamos a usar el DIR$ de otra forma... una de las varias disponibles...
Crea un nuevo proyecto, aade un ListBox, un Label, un TextBox y un CommandButton, el aspecto sera
ms o menos as:

Haz dobleclick en el Command1 y escribe:


Private Sub Command1_Click()
Dim sTmp As String
On Local Error Resume Next
sTmp = Dir$(Text1.Text)
If Err = 0 Then
Do While Len(sTmp)

'Repetir mientras haya ficheros

List1.AddItem sTmp
sTmp = Dir$

'Lo aadimos a la lista


'Asignar el siguiente fichero

Loop
End If
Err = 0
End Sub
Ejecuta el programa y escribe *.* en el TextBox, pulsa en el botn y te mostrar en el listbox todos los
archivos del directorio actual.
Vamos a ver que es lo que hace el cdigo:
sTmp = Dir$(Text1.Text)
Con esto, guardamos en sTmp el primer fichero que coincida con lo que hemos escrito en el Text1.
If Err = 0 Then
Si no se produce un error...
Do While Len(sTmp)
...se entra en el bucle, pero slo si el contenido de sTmp no es una cadena vaca. Recuerda que DIR$
devuelve una cadena vaca si no se ha encontrado un fichero que coincida con lo indicado...
List1.AddItem sTmp
Esto aade al ListBox el contenido de sTmp
sTmp = Dir$
Fjate que DIR$ se usa sin indicarle nada ms, salo de esta forma si quieres que siga comprobando si
hay ms ficheros que coincidan con la especificacin indicada la vez anterior que se le pas un
parmetro. Si el contenido del TextBox tena algn signo comodn, Dir$ devolver el siguiente fichero que
coincida, en caso de que no queden ms ficheros "coincidentes", devolver una cadena vaca.
Loop
Repite el bucle si se cumple la condicin que pusimos despus de DO WHILE, es decir: continuar si la
longitud, nmero de caracteres, de sTmp NO ES CERO.
Prueba, sin cerrar el programa, con varias cosas, por ejemplo: *.vbp, *.bas, etc.
Que pasa?
Si ests indicando varias cosas que buscar, y las encuentra, te dars cuenta que el listbox se va
llenando... es decir, adems de lo nuevo, que estar al final, sigue lo anterior...
Cmo solucionarlo?
Borrando el contenido del listbox.
Para borrar el contenido del listbox, usa esto:
List1.Clear
Dnde debo ponerlo?
En nuestro ejemplo, yo lo pondra justo despus del On Local Error..., o antes, da igual, ya que lo que se
pretende es que se borre al hacer CLICK en el botn.
Por supuesto no lo pongas dentro del DO...LOOP, ya que no servira para lo que queremos... puesto que
se borrara continuamente... S, ya s que no eres tan torpe como para hacerlo, pero...
Un detalle que puede que sea simple, pero que en nuestro ejemplo nos ahorrara pulsaciones. Si al
pulsar INTRO se simulara el CLICK del botn, nos ahorrara el tener que "desplazarnos" a ese botn
para que muestre lo que ha encontrado y si queremos seguir mostrando ms cosas, el tener que
desplazarnos nuevamente al TextBox.
Para conseguir esto, todo lo que tenemos que hacer, es indicarle al VB que el botn sea un botn "por
defecto".
Muestra el form, y pulsa una vez en el botn, te mostrar la ventana de propiedades de este control,
busca la propiedad DEFAULT y mrcala como TRUE, vers que el botn ahora est remarcado con un
borde negro.

Ejecuta de nuevo el programa, escribe cualquier cosa en el TEXT1 y pulsa INTRO, ahora te mostrar los
ficheros hallados, pero el cursor permanece en el TextBox, listo para poder escribir una nueva
especificacin...
Ahora vamos a los ejercicios:
1.- Modifica el ejemplo para que en lugar de guardar los ficheros hallados en un listbox, lo haga en un
array.
2.- Una vez hecho esto, aade al listbox todos los ficheros hallados... mejor dicho, para que no hagas
trampas, aade al listbox el contenido del array, es decir todos y cada uno de los ficheros previamente
asignados.
3.- Aade otro botn al form y al pulsar en l, que guarde en un fichero, (por ejemplo: hallados.txt), todos
los ficheros hallados, es decir los que estn en el array.
Creo que con esto, ya tienes para entretenerte un rato.
Como pista, ya sabes el tipo de pistas que doy..., te dir que la asignacin al array, puedes hacerla de
dos formas:
UNA: Usando un nmero mximo de ficheros a asignar.
DOS: Usando un nmero variable, es decir que se aadan slo la cantidad de ficheros hallados.
Y si haces los ejercicios de las dos formas posibles, mejor an.
Si ves que te atrancas y no sabes por dnde hincarle el diente, aunque sea postizo, chale un vistazo a
la entrega ocho y a la entrega doce, en ellas encontrars la solucin a estos ejercicios... bueno, la
solucin, lo que se dice la solucin: no, pero si unas verdaderas auto-pistas para poder solucionarlos.
Y como soy un poco "diablillo", no te voy a poner un link a las soluciones... al menos hasta que ponga la
siguiente entrega, as que... a rabiar unos das!
Es que algunas veces... Soy malo!
Pues nada, a esperar... que de seguro ser poco, pero mientras tanto...
Y recuerda que espero tu comentario, no me preguntes si lo ests haciendo bien o no, que de eso se
encargar la pgina con las soluciones, slo pregntame algo que no hayas entendido..., de esta
entrega, claro, no de otra cosa que no est en el curso... que casi de seguro estar en otra de las
secciones que hay en mis pginas...

Curso Bsico de Programacin


en Visual Basic
Entrega Quince: 23/Mar/98
por Guillermo "guille" Som
Si quieres ir a alguna de las entregas anteriores, usa estos links:
La Primera, la Segunda, la Tercera, la Cuarta, la Quinta, la Quinta++, la Sexta, la Sptima, la Octava, la
Novena, la Dcima, la Undcima, la Doce, la Trece, la Catorce, Solucin ejercicios entrega Catorce

Parece ser que pocos hicisteis caso de mi comentario, en la entrega trece, sobre el porttil, lo mismo es
que sois supersticiosos, pero la cuestin es que sigo sin l... as que no te quejes de que tarden tanto las
entregas sobre el curso bsico...
La verdad es que me hubiese gustado encontrarme con un mensajillo de un alma caritativa que me
hubiese dicho que pona a mi disposicin el susodicho porttil, pero me aguantar sin l... por lo menos
espero los comentarios sobre lo que te parece el curso, aunque ms espero comentarios sobre las cosas
que no entiendas, ya que la intencin es que sean claras y que consigas aprender a programar con este
lenguaje, que a pesar de que muchos dicen que es fcil, cosa que no dudo, tiene muchas cosillas como

para complicarnos un poco la vida y para eso estoy yo aqu, par intentar que no sean tan difciles... al
menos lo intento, a ver si lo consigo.
Una vez hecho el obligado comentario inicial, vamos a continuar nuestra andadura con los ficheros
secuenciales. En esta entrega vamos a preparar una pequea utilidad que nos permitir editar un fichero
de texto y guardar los cambios en el disco; no le pidas peras al olmo que no te las dar, as que no creas
que vamos a "programar" un verdadero editor... eso puede que sea ms adelante... supongo...
Realmente el acceso secuencial va a pintar poco en esto que vamos a hacer, pero nos servir para ir
"tomndole" cario a unos controles que usaremos en el 99.9% de nuestras aplicaciones.
Para esta tarea, crea un nuevo proyecto y aade un label, dos textbox y dos commandbutton.
Distribyelos de esta forma:

El Textbox grande (Text2) tiene la propiedad Multiline a True, de esta forma se ir mostrando todo el
contenido conforme lo vayamos rellenando.
Los nombres de los otros controles sern Label1, Text1, cmdAbrir para el botn de Abrir y cmdGuardar
para el de guardar.
El problema de los textbox es que no soportan ms de 64KB, aunque en teora si, pero en la prctica lo
que soportan son unos 32000 caracteres, que en la versin de 32 bits suponen esos 64KB, por si no lo
sabes en Windows de 32 bits cada carcter est representado por dos bytes.
Para solventar ese "pequeo" inconveniente, vamos a dar por hecho de que slo admite 32000
caracteres, de esta forma tambin nos servir el programa en VB de 16 bits.
A este proyecto hay que agregarle un mdulo BAS que tenga la funcin Existe que vimos en la entrega
trece, si no quieres aadir un nuevo mdulo, simplemente copia y pega esa funcin en este formulario.
Si la funcin la usas desde un mdulo BAS, debe ser pblica, si la pegas en este formulario, puede ser
privada. En el formulario tambin puede ser pblica, pero lo que nos interesa es que pueda accederse
desde el form, as que no es necesario declararla de esa forma.
Ahora aade el siguiente cdigo para el botn abrir:
Private Sub cmdAbrir_Click()
'Abrir

Dim i As Long, tamFic As Long


If Existe(Text1.Text) Then
Text2.Text = ""
i = FreeFile
Open Text1.Text For Input As i
tamFic = LOF(i)
Text2.Text = Input$(tamFic, i)
Close i
End If
End Sub
Esta rutina no est hecha a prueba de fallos, pero no te preocupes que ya lo hars... como ejercicio?
efectivamente!
Este es el cdigo del botn guardar:
Private Sub cmdGuardar_Click()
'Guardar
Dim i As Long
i = FreeFile
Open Text1.Text For Output As i
Print #i, Text2.Text
Close i
End Sub
Fjate que cdigo ms corto... as da gusto hacer programas!
Aunque tampoco est preparado para cualquier impedimento...
Vamos a aadirle una serie de mejoras, entre ellas el que avise, al guardar, si es que vamos a
sobreescribir un fichero existente.
Otra mejora sera comprobar si se ha modificado el contenido del Text2 y avisar antes de abrir un nuevo
fichero.
La tercera mejora que se me ocurre es comprobar que no se abra un fichero con ms caracteres de los
"permitidos"... aunque este lo dejar para que lo hagas t.
La razn de poner estas mejoras por separado, es decir, contrtelo antes de hacerlo, es para darte la
oportunidad de que lo hagas por tu cuenta... Ahora no recuerdo si tienes la base suficiente para hacerlo,
pero... podra ser... comprubalo por tu cuenta.
Antes de darte la solucin a dos de estas tres mejoras, voy a contarte un "rollito" para que as no se vean
las soluciones... no te preocupes que no te voy a contar una de mis batallitas, slo voy a "ampliar" tus
conocimientos... (que bien te ha quedado eso Guille)
Cuando usamos un textbox multiline, es decir en el que podemos escribir varias lneas de texto, el Visual
nos da la posibilidad de poder usarlo de varias formas, si no le decimos nada, conforme vayamos
escribiendo, se ir mostrando el texto en la siguiente lnea, a esto se le llama wordrap o algo as, que
viene a significar que no se corten las palabras al cambiar de lnea... para hacer esto mismo en el BASIC
normalito del MS-DOS, haba que crear una rutina para comprobar cuando haba que mandar una
palabra a la siguiente lnea... dejemos los viejos tiempos y continuemos con los nuevos...
Pero si lo que quieres es que cada lnea escrita se quede en la misma lnea hasta que pulses intro,
debers indicrselo al Visual Basic, dicindole que slo aada al textbox un scroll horizontal, prubalo y
decide...
Cmo aadirle los scrollbars... no pienses que tienes que usar los controles que el Visual tiene para
eso, slo debes modificar la propiedad ScrollBars del control Text2. Tienes varias opciones:
0- None

Ningn scrollbar

1- Horizontal
2- Vertical

Slo el scroll horizontal, para cambiar de lnea debes pulsar Intro


Slo el scroll vertical, esto es como sin scrolls, pero nos permite navegar

3- Both

hacia abajo.
Ambos scrolls, pues eso, una mezcla de los dos.

Si los compruebas, vers al asignar a esta propiedad el valor 0 y 2, el resultado es el mismo, al menos
en lo que se refiere a la hora de escribir en l, ya que el resultado visual es diferente; a lo que me refiero
es que el texto se ajustar automticamente haya o no un intro para separar cada lnea, la diferencia, es
que con el scroll vertical, podemos navegar fcilmente hacia la parte no visible del texto escrito.
Cuando especificamos el Scroll horizontal, tanto con el valor 1, como con el 3, ya te dars cuenta de que
cada lnea est separada, siempre que hayas pulsado Intro para cambiar de lnea. Tambin puedes usar
Shift+Intro o Control+Intro para efectuar un cambio de lnea.
Para comprobarlo, haz el textbox ms pequeo, al menos en anchura, por ejemplo ajstalo al tamao del
Text1 y escribe varias lneas, pulsando en algunas Intro y otras escribiendo bastante texto... Luego
decide que tipo de scroll prefieres.
Una cosa que debes saber es que esta propiedad es de slo lectura, al menos en tiempo de ejecucin,
osea que no puedes cambiar que scrolls deben mostrarse una vez que el programa est en
funcionamiento.
Me imagino que te habrs fijado que en el Notepad (Bloc de Notas) que incluye el Windows, existe una
opcin para ajustar las lneas automticamente, es decir para usar los dos scrolls o slo el vertical.
Cmo se consigue este efecto si no se puede cambiar la propiedad ScrollBars?
Pues... usando dos TextBoxes, uno de ellos con la propiedad ScrollBars a 2 (Vertical) y el otro asignando
el valor 3 (Both)
Para probarlo, debers crear un array del Text2, para ello, cpialo y vuelve a pegarlo, te preguntar si
quieres tener una matriz de este control, contstale que s. Al Text2(0), el que tiene el valor Index igual a
CERO, asgnale la propiedad ScrollBars a 2 y al otro, el valor 3. Sitalos en la misma posicin del form,
para que uno est encima del otro, no te preocupes de cual est encima, eso lo controlaremos nosotros.
Aade un nuevo botn, escribe en el Caption: Ajustar lneas y dale el nombre cmdAjustar.
Declara una variable a nivel de mdulo para saber cual es el TextBox que est activo:
Dim QueText2 As Integer
En el Form_Load escribe esto:
Text2(0).Zorder para que se ponga encima del otro TextBox.
En el evento Click del nuevo botn aade este cdigo:
Private Sub cmdAjustar_Click()
Dim QueText2Ant As Integer
'Valor del TextBox actual
QueText2Ant = QueText2
'Nuevo valor
QueText2 = QueText2 + 1
'si nos pasamos... volvemos al principio
If QueText2 > 1 Then QueText2 = 0
'asignar al nuevo textbox el contenido
Text2(QueText2).Text = Text2(QueText2Ant).Text
'Lo hacemos visible
Text2(QueText2).ZOrder
'borramos el contenido anterior
Text2(QueText2Ant).Text = ""
End Sub
Ahora tendrs que cambiar el cdigo usado para leer y escribir, simplemente cambia el Text2.Text por
Text2(QueText2).Text y asunto arreglado, ya que el text que estar visible es el que indica esa variable.
Ejecuta el programa, escribe algo en el textBox, preferiblemente alguna lnea larga y pulsa Intro para
crear otras, pulsa en el botn de ajustar lneas y vers el efecto.
Si quieres tener esta posibilidad en este programa, debers recordar de cambiar cualquier uso de Text2
por Text2(QueText2), ya que si no lo haces, el Visual Basic se encargar de recordrtelo...
Bueno, creo que el rollito este ha sido ms largo de lo que tena previsto, pero espero que haya valido la
pena.

Vamos a ver las soluciones a las mejoras... las soluciones las voy a dar suponiendo que no tienes esta
posibilidad de usar los dos TextBoxes para el ajuste de lnea, es que sino, me va a romper todo el
esquema que tena previsto y no es plan...
Para saber cuando se va a sobreescribir el fichero, lo que hay que hacer es comprobar primero si ese
fichero ya existe y despus de comprobarlo, avisar con un MsgBox si se quiere sobre-escribir, en caso
negativo simplemente no se guarda el contenido del TextBox en el fichero.
Vamos a ver el cdigo necesario, este deber estar en el botn de Guardar... (elemental mi querido
Watson)
Private Sub cmdGuardar_Click()
'Guardar
Dim i As Long
Dim SobreEscribir As Boolean
'Se asigna el valor Verdadero, por si no existe
SobreEscribir = True
'Si ya existe, preguntar
If Existe(Text1.Text) Then
If MsgBox("ATENCIN, el fichero ya existe." & vbCrLf & _
"Quieres sobreescribirlo?", vbQuestion + vbYesNo) = vbNo
Then

'Hemos contestado que no, as que...


SobreEscribir = False
End If
End If

'Si no existe o se quiere sobreescribir...


If SobreEscribir Then
i = FreeFile
Open Text1.Text For Output As i
Print #i, Text2.Text
Close i
End If
End Sub
Fjate en el MsgBox, al usar & _ es para que el VB pueda mostrar en lneas distintas lo que se debera
escribir en una misma.
Despus usamos vbQuestion para que muestre la interrogacin y vbYesNo es para que nos muestre los
botones SI / NO.
Si pulsamos en Si, no se cumple la condicin y si pulsamos en NO, si que se cumple, por tanto
asignamos un valor falso a la variable SobreEscribir para que en la siguiente comparacin no se cumpla
y no se guarde el contenido del Text2.
Al principio le he dado el valor VERDADERO a la variable que decide si se debe sobrescribir o no, esto lo
he hecho porque si no existe el fichero, no nos preguntar y si no le damos de "arrancada" el valor
Verdadero, nunca lo tendr, ya que la nica asignacin que hacemos es la darle un valor FALSO, en
caso de que no queramos guardar el contenido.
Como habrs podido comprobar, para poder guardarlo con otro nombre, debers escribir ese nombre en
el Text1.
Para la segunda mejora, necesitaremos una variable a nivel de mdulo, as que aade esta declaracin
en la seccin de las declaraciones generales del formulario:
Dim Modificado As Boolean
Como recordars de la segunda entrega, en los TextBoxes hay un evento, CHANGE, que se "dispara"
cada vez que cambia el contenido de la propiedad Text de estos controles. Usaremos este evento para
saber cuando se ha cambiado el contenido del Texto escrito.
Aade este cdigo al formulario:
Private Sub Text2_Change()
Modificado = True
End Sub

De esta forma, cada vez que se cambie el contenido de este control, se cambiar tambin el valor de esa
variable y as podremos saber si se ha cambiado o no.
Esto lo comprobaremos en el procedimiento Abrir, de forma que si se ha modificado, nos pregunte si
queremos guardarlo antes de abrir uno nuevo. El cdigo, ms o menos sera algo as:
If Modificado Then
If MsgBox("El texto se ha modificado..." & vbCrLf & _
"Quieres guardarlo?", vbQuestion + vbYesNo) = vbYes Then
'Guardarlo
'...
End If
End If
Realmente no sera tan simple. Ahora lo veremos al completo.
Con esto de comprobar si est modificado se nos presentan dos problemas:
El primero es que al no conservar el nombre del fichero abierto anteriormente, o con el que acabamos de
guardar lo que hayamos escrito antes de intentar abrir otro, no sabremos con que nombre guardarlo, ya
que al usar el contendido del Text1, ste puede cambiar y seguramente no conseguiramos nuestro
objetivo.
Por suerte, la solucin a este inconveniente es tan simple como la de usar una variable, a nivel de
mdulo, para guardar el nombre del fichero abierto o guardado por ltima vez.
Fjate que uso variables a nivel de mdulo para algunas cosas, de esta forma estas variables, como ya
deberas saber, estarn disponibles en cualquier parte del mdulo actual, en este caso: el formulario.
Aade esta declaracin en la parte general de las declaraciones del formulario:
Dim sFichero As String
Ahora modifica el cdigo para que podamos usar esta variable:
Private Sub cmdAbrir_Click()
'Abrir
Dim i As Long, tamFic As Long
Dim sTmp As String
If Modificado Then
If MsgBox("El texto se ha modificado..." & vbCrLf & _
"Quieres guardarlo?", vbQuestion + vbYesNo) = vbYes Then
'Conservar el nombre actual
sTmp = Text1.Text
'y asignar el anterior
Text1.Text = sFichero
'guardarlo...
cmdGuardar_Click
'Volvemos a dejar el Text1 como estaba
Text1.Text = sTmp
End If
End If
'Asignamos el nombre del fichero
sFichero = Text1.Text
If Existe(sFichero) Then
Text2.Text = ""
i = FreeFile
Open sFichero For Input As i
tamFic = LOF(i)
Text2.Text = Input$(tamFic, i)
Close i
End If
End Sub
Fjate en las asignaciones que hay que hacer antes de guardar el contenido del Text2, esto es necesario,
ya que en ese evento se usa el contenido del Text1, para saber en que fichero se debe guardar.

Bien, ya tenemos una parte resuelta, la otra es que una vez que la variable Modificado ha tomado el
valor TRUE no lo suelta.
Este valor debera de dejar de valer verdadero cuando lo guardemos, as que aade al final del
procedimiento que guarda el fichero, esta asignacin:
Modificado = False
Realmente debers ponerla despus del Close i y dentro de la comparacin que decide si se debe
guardar o no el contenido del Text2.
Tambin tendremos que asignar en este procedimiento el valor de la variable sFichero, para que al
asignarse en el evento Abrir su valor al TextBox, ste tome el que tuviera esa variable cuando se guard
un fichero.
Esto debers hacerlo una vez que se guarde el fichero, es decir, si no hemos cancelado la grabacin.
sFichero = Text1.Text
Aunque pueda parecer que realmente no tiene sentido el uso de esta variable, ya que tanto en Guardar
como en Abrir se le asigna el contenido del Text1, lo tiene en el caso de querer abrir uno nuevo, antes de
haber guardado los cambios, si no se tuviera esta variable, no conservaramos el nombre del fichero,
antes de haber modificado el contenido del Text1 para asignar un nuevo nombre...
Aunque parte de este "come-coco" se solucionara con el uso de un cuadro de dilogo que preguntara el
nombre del fichero a abrir o a guardar, de esta forma no sera necesario dejar siempre un TextBox para
que se pueda escribir el nombre.
An as, necesitaramos una variable para conservar el nombre del fichero...
Bien, vamos a probar esto... a ver si funciona bien...
Como podrs comprobar, no est todo lo "refinado" que quisiramos... Despus de abrir un fichero y sin
haber modificado el contenido del Text2, intenta abrir otro, te dir que el texto se ha modificado...
Por qu ocurre esto?
Cuando asignamos al Text2 el contenido del fichero, estamos "cambindolo", por tanto se produce el
evento Change y se asigna el valor de la variable Modificado, as que tambin tendremos que asignar
un valor FALSE a esta variable despus de abrir el fichero y asignarlo al Text2, es decir al final del
procedimiento Abrir.
De esta forma slo se activar la "alarma" cuando realmente se modifique el texto.
Este valor asignarlo justo despus de cerrar el fichero o despus de haber asignado al Text2 el contenido
del fichero.
Para finalizar, un par de cosillas para mejorar.
Cuando un form se abre, cosa que ocurre automticamente al iniciarse este programa, se produce el
evento Load, este ahora no nos interesa, el que nos interesa es el que se produce cuando el form se
cierra, cosa que tambin ocurre al cerrar la aplicacin, es decir el evento Unload.
En este evento tambin se puede poner una comprobacin para que, en caso de no haber guardado el
contenido del Text2, tengamos la oportunidad de poder guardarlo antes de cerrar definitivamente el form.
As que, aade este cdigo en el evento Form_Unload:
Private Sub Form_Unload(Cancel As Integer)
If Modificado Then
If MsgBox("El texto se ha modificado..." & vbCrLf & _
"Quieres guardarlo?", vbQuestion + vbYesNo) = vbYes Then
'Asignar el anterior
Text1.Text = sFichero
'guardarlo...
cmdGuardar_Click
End If
End If
Set Form1 = Nothing
End Sub

Aunque en el caso de que no hayamos usado ningn nombre, el contenido de sFichero, no sea
adecuado, as que tambin podramos tener un valor por defecto en esta variable, que sera el que se
mostrase al iniciarse el programa, por tanto vamos a aadir un valor por defecto a esta variable y al
Text1, esto lo haremos en el evento Form_Load:
Private Sub Form_Load()
sFichero = "Prueba15.txt"
Text1.Text = sFichero
End Sub
Fjate que al final del Form_Unload he puesto Set Form1 = Nothing, esto se suele usar cada vez que
descarguemos un formulario, para asegurarnos que se libere la memoria que pudiera estar ocupando...
de esto ya veremos ms cuando nos topemos con las clases y la creacin de objetos... piensa que cada
control y formulario es un objeto y cuando un objeto no se usa, debemos indicarle al Visual que se
deshaga de l... Pero esto lo veremos en otra ocasin.

Ahora los ejercicios:


1.- Como ya he comentado, los TextBoxes no soportan todos los caracteres que quisiramos, para
redondear, digamos que soportan 32000. Esto es casi cierto en VB de 16 bits, realmente admiten 32767
(32 KB).
En 32 bits en teora soportan 64 KB, pero como el entorno de 32 bits usa caracteres de 2 bytes, estos 64
kas se quedan en 32.
Para 16 bits, existe una funcin del API de Windows que permite asignar 64 KB a un TextBox, en 32 bits
no tiene ningn efecto ya que, como he repetido ms de una vez... admite 64 KB.
Para no liarte ms de lo que ya puedas estar, vamos a dar por sentado que slo se pueden asignar a un
TextBox 32000 caracteres, que en 32 bits no es lo mismo que 32000 bytes... (je, que me gusta liar al
personal)
Lo que tienes que hacer es que a la hora de abrir un fichero, compruebes que no tenga ms de 32000
caracteres y en caso de que el fichero los tenga, no abrirlo.
2.- En este segundo ejercicio, lo que vas a hacer es leer slo 32000 caracteres del fichero que tenga
ms de esos... as al menos podrs editar esa parte de los ficheros grandes, cosa que no es
recomendable, sobre todo si lo guardas, ya que podras "cargarte" un fichero que puede ser necesario...
El que avisa...
Aunque, para curarte en salud, podras impedir que se guardase un fichero del cual no se hayan ledo
todos los caracteres que tuviese... por tanto, un tercer ejercicio:
3.- Si el fichero abierto tiene ms de 32000 caracteres, leer slo esta cantidad y usar un "flag" para
impedir que se guarde...

Bueno, espero que esta entrega te haya sido provechosa y que seas capaz de completar los ejercicios,
la solucin de los cuales te pongo en este link, adems en la pgina de las soluciones tendrs el cdigo
para usarlo con los dos Textboxes para permitir el ajuste de lnea.
Y como suele ser costumbre al terminar una entrega, ya sabes que espero tu comentario,

Curso Bsico de Programacin


en Visual Basic

Entrega Diecisis: 6/Abr/98


por Guillermo "guille" Som
Si quieres linkar con otras entregas, desde el ndice lo puedes hacer

Habrs notado que ya no aparecen los links al principio de esta entrega, ello se debe a que he aadido
una nueva pgina, desde la cual puedes linkar con todas las entregas, adems de poder ver una lista de
las "palabras" tratadas en todas las entregas aparecidas, as como en que entrega(s) apareci esa
palabra, no es nada "preciso", pero intentar ir "depurndolas".
La intencin es que puedas saber de un vistazo en que entrega se ha tratado y... espero hacerlo pronto,
en cual de ellas es en la que se ha explicado, porque una cosa es que se use la palabra y otra diferente
que se explique...
Como digo, es slo un primer intento, que espero ir mejorando, para que te sea fcil encontrar la palabra
o tema que te interesa.
Decirte que esa lista la he "sacado" con una utilidad, que seguramente pondr pronto en mis pginas y
que trata de mostrar cada una de las "palabras" que aparecen en los ficheros que se procesen... adems
de esa utilidad, he tenido que ir leyndome cada una de las palabras y tomndo nota, por lo tanto alguna
se me ha podido escapar...
Bueno, ya vale... vamos al tema de la presente entrega: Los ficheros aleatorios (Random)
Pues eso, ahora le toca el turno a los ficheros aleatorios. Ya te coment que este tipo de fichero se suele
usar cuando todos los datos que incluye tienen la misma longitud. Normalmente a cada uno de los datos
guardados se les llama registro. Todos los registros tienen la misma longitud, o al menos deberan
tenerla... no, no es una contradiccin, pero si quieres que funcione bien, deben ser iguales, porque el
sistema que usa el VB para acceder a cada uno de los registros es una simple operacin:
Posicin_Actual = (Nmero_Registro -1) * Tamao_del_Registro + 1
Pero no te asustes... t no tienes que hacer ningn clculo... de eso se encarga el Visual Basic.
Para acceder a los datos de los ficheros abiertos como Random, vienen como anillo al dedo, (si es que el
anillo te encaja bien), los tipos definidos por el usuario, aunque cualquier cadena servira para esta tarea.
Antes de empezar a manejar ficheros de acceso aleatorio, es importante planear lo que vamos a
almacenar en ellos; siempre se debe planear, pero en esta ocasin es un poco ms importante, ms que
nada porque, como ya he dicho, tenemos la obligacin de saber la longitud de los datos, (al menos de
cada uno de los registros), a almacenar. Ya que esa longitud, (la de cada registro), debemos especificarla
a la hora de abrir el fichero.
Un pequeo detalle antes de continuar, cuando abrimos un fichero secuencial para lectura (Input), el
Visual Basic o el sistema operativo, slo nos permite leer datos de ese fichero, es decir: no podemos leer
y escribir al mismo tiempo. Igualmente ocurre cuando lo abrimos para escritura (Output), slo que en
esta ocasin slo podemos escribir y no leer. Sin embargo, con los ficheros abiertos como aleatorios
(Random) o binarios (Binary), una vez que el fichero est abierto, podemos leer o escribir
indistintamente. Alguna ventaja teniamos que tener... no iban a ser todo "obligaciones".
Sigamos con lo nuestro...
Veamos cmo, por fin, usar estos ficheros:
Para verlo... nada mejor que con un ejemplo:
Primero definimos un tipo de datos, en este caso vamos a guardar el nombre, edad y la cuenta de email
de unos colegas, por tanto emplearemos un tipo definido con estos tres campos, veamos:
Private Type t_colegas
Nombre As String * 30
Edad
As Integer
email
As String * 50
End Type

Declaramos una variable de este "nuevo" tipo de datos, que ser la que usaremos para acceder al
fichero:
Dim unColega As t_colegas
Y abrimos el fichero:
Open "miscolegas.dat" For Random As nFic Len = Len(unColega)
El Len(unColega), le est indicando al VB que la longitud de cada registro es la que tenga ese tipo de
datos.
No siempre hay que hacerlo as, podramos asignar a una variable esa longitud y usarla para abrir el
fichero:
lenColega = Len(unColega)
Open "miscolegas.dat" For Random As nFic Len = lenColega
Lo que quiero dejar claro es que al Visual Basic no le importa con qu variable accedemos al fichero,
sino que longitud tendr esa variable, o si lo prefieres, cual ser la longitud de cada registro.
Por tanto, si sabemos que nuestro tipo de datos, (o lo que es lo mismo: cada registro), tiene 82 bytes de
longitud, podramos usar un string con esa longitud para acceder al fichero en cuentin y...
Toc, toc! Guille!!!
S?
No crees que te ests precipitando?
Yo? Por qu?
Porque ests hablando de acceder as o asao a los datos y an no has explicado cmo leer o
escribir esos datos...
Pues... s... es cierto... je...
Si no fuera por el otro Guille... en fin...
Esto..., cuando quieras leer el contenido de un registro en particular del fichero abierto, usa esta
instruccin:
Get #canal, num_registro, variable_de_datos
Para escribir usa esta otra:
Put #canal, num_registro, variable_de_datos
Es decir GET para leer y PUT para escribir, en esto los ingleses lo tienen ms fcil, ya que al menos a
ellos esas dos palabras tienen algo de sentido...
Despus de cualquiera de estas instrucciones se indica el nmero de fichero (#canal), seguido por el
nmero de registro al que queremos acceder, (num_registro), y por ltimo la variable,
(variable_de_datos), que usamos para leer, (GET), los datos del disco o almacenarlos en l (PUT)
Un detalle que tienes que tener siempre presente al definir un tipo de datos para acceder a los ficheros
aleatorios: asegurate de que todas las cadenas contenidas en ese tipo, sean de longitud fija; lo mismo si
dentro del tipo usas arrays, estos deben ser de ndices constantes, es decir que estn definidos al crear
el tipo.
Todas estas "precauciones" se consiguen con datos "estticos", es decir que permanecen sin cambios, al
menos en lo que a tamao se refiere. Los "dinmicos" son los que pueden cambiar "dinmicamente" de
tamao.
Aclaremos estos puntos antes de continuar.
Una variable declarada de esta forma:
Dim cadenaEstatica As String * 50
Siempre tendr 50 caracteres, incluso si hacemos esta asignacin:
cadenaEstatica = ""
Con esto no eliminamos las 50 celdas de memoria, sino que la rellenamos de espacios...
Prueba con este cdigo:
Crea un nuevo proyecto y aade esto en el Form_Load:

Private Sub Form_Load()


Dim cadenaEstatica As String * 50
Show
cadenaEstatica = "Hola"
Print cadenaEstatica & "Pepe"
cadenaEstatica = ""
Print cadenaEstatica & "Pepe"
Print
Print "Longitud de la cadena:"; Len(cadenaEstatica)
Print "Asc(cadenaEstatica) ="; Asc(cadenaEstatica)
End Sub
El resultado sera este:

Es decir que una cadena esttica (o de longitud fija), siempre tendr el nmero de caracteres que le
indicamos al declararla.
Sin embargo una cadena dinmica slo tendr los caracteres que le asignemos.
Prueba este cdigo:
Private Sub Form_Load()
Dim cadenaDinamica As String
Show
cadenaDinamica = "Hola"
Print cadenaDinamica & "Pepe"
cadenaDinamica = ""
Print cadenaDinamica & "Pepe"
Print
Print "Longitud de la cadena:"; Len(cadenaDinamica)
Print "Asc(cadenaDinamica) ="; Asc(cadenaDinamica)
End Sub
Habrs obtenido algo parecido a esto:

Osea "Illegal Function Call", este error lo da al intentar conseguir el cdigo ASCII de la cadena... pero
como la cadena est vaca... pues no hay nada que obtener, por tanto: Error al canto!!!
Aparte del error, te puedes fijar que "HolaPepe" sale junto y que la longitud de la variable es cero.
Cuando asignamos una cadena vaca a un string dinmico, lo dejamos "seco", es decir sin nada en el
interior...
Lo mismo ocurre con los arrays, ya sean de caracteres o numricos.
Los estticos siempre conservan el nmero de elementos, incluso cuando se eliminan, (al menos eso es
lo que parece), con Erase. Aunque esto ya lo vimos, no est de ms recordarlo: Al "eliminar"
con Erase un array dinmico, lo eliminamos de la memoria, pero en los estticos, simplemente ponemos
el contenido a cero, (o a cadenas vacias si son de cadenas dinmicas).
Pruebalo:
Dim arrayEstaticoInteger(1 To 10) As Integer
Dim arrayEstaticoString(1 To 5) As String
Dim arrayDinamicoInteger() As Integer
Dim arrayDinamicoString() As String
Cuando se declaran los arrays con el nmero de elementos que va a contener, siempre con constantes,
estos arrays son estticos, porque siempre contendrn ese nmero de elementos.
Sin embargo los dinmicos, se declaran sin decirles cuantos elementos van a contener y despus se
usa Redim o Redim Preserve para cambiar el nmero de elementos.
Veamos un ejemplo de un tipo definido con un array esttico:
Private Type t_colegas2
Nombre
As String * 30
Edad
As Integer
email(1 To 3)
As String * 50
End Type
Aqu hemos definido un "campo" email con un array de tres elementos.
Recuerda que aunque los tipos definidos permitan tanto cadenas de longitud variable como arrays
dinmicos, si ese tipo se va a usar para acceder a datos de un fichero aleatorio, su longitud siempre tiene
que ser fija y coincidir con la longitud que se indic a la hora de abrir ese fichero... si no tienes esta
"precaucin"... no acceders con "fiabilidad" a los datos contenidos en ese fichero... despus no digas
que no te advert...
De todas formas, vamos a comprobarlo...
Escribe este cdigo en un form:
'Este cdigo en las declaraciones del form
Option Explicit

Private Type t_colegas


Nombre As String * 30
Edad
As Integer
email
As String * 50
End Type
Dim unColega As t_colegas
Private Type t_colegaDinamico
Nombre As String
Edad
As Integer
email
As String
End Type
Dim unColegaDinamico As t_colegaDinamico
Private Sub Form_Load()
Dim nFic As Integer
nFic = FreeFile
Open "miscolegas.dat" For Random As nFic Len = Len(unColega)
'Asignamos los datos
With unColega
.Nombre = "Pepe"
.Edad = 22
.email = "pepe22@mundo.net"
End With
Put #nFic, 1, unColega
'ahora lo hacemos con el colega dinmico
With unColegaDinamico
.Nombre = unColega.Nombre
.Edad = unColega.Edad
.email = unColega.email
End With
'Aqu dar error:
Put #nFic, 2, unColegaDinamico
Close
End Sub
Ejecuta el programa y te encontrars con un "bonito" error nmero: 59 Bad Record Length o La longitud
de registro es incorrecta, si usas la versin castellana del Visual Basic. Lo que nos quiere decir este error
es que no puedes grabar datos de una longitud diferente a la especificada a la hora de abrir el fichero.
Pero... por qu? si, aparentemente, la longitud es la misma...
Pues eso, que slo es en apariencia... si en la ventana "Inmediato" escribes esto, saldrs de dudas:
Print len(uncolega); len(uncolegadinamico)
El resultado ser este:
82 10
En el primer caso, el del coleguilla normal, lalongitud es la esperada: 82
Pero en nuestro amigo dinmico, la longitud es 10, independientemente de que "en teora" tenga
almacenados esos 82 caracteres del "esttico". Lo que ocurre es que al ser dinmico, el contenido de las
variables de caracteres se almacenan en otro sitio y lo nico que hay en esas variables es un "puntero" a
la direccin de memoria en la que estn los datos almacenados... al menos ahora sabemos que una
variable de cadena de caracteres tiene una longitud de 4 bytes... creo que eso ya lo vimos en la entrega
nmero dos o tres... dnde hablamos de lo que ocupa cada variable... los enteros (Integer) ocupan 2
bytes, independientemente de cmo est declarada la variable... lo mismo ocurre con los otros datos
numricos.
Como te deca, si sabemos que la longitud del registro es de 82 caracteres, podemos definir una cadena
de esa longitud y usarla para acceder a los datos.
Probemos esto otro:

Dim unaCadena As String * 82


'...

unaCadena = "Prueba de una cadena"


Put #nFic, 2, unaCadena

'...

Ahora si que funcionar.


Pero si esa variable est definida como String normal, no funcionar...
Resumiendo: para acceder a los registros de un fichero abierto como Random, las variables usadas
deben tener definida la longitud igual que el tamao especificado a la hora de abrirlo.
Un poco de complicacin: Vamos a ver un ejemplo, "ilustrativo" ms que prctico.
Ya he comentado que con una cadena de longitud fija podemos acceder a un registro. Ahora
comprobars lo "cmodo" que es usar los tipos definidos. Pero este ejemplo lo pongo para que sepas
cmo se almacenan los datos numricos en una cadena que se va a usar para guardar datos en un
fichero de acceso aleatorio.
Hemos "comprobado" que un Integer se almacena en dos bytes... por tanto lo que se guarda en el disco
es precisamente eso: dos bytes. Cuando se usa un tipo definido, no te tienes que preocupar de cmo se
almacena, simplemente asignas el valor a la variable numrica y del resto se ocupa el VB.
Viendo el ejemplo anterior, es fcil almacenar un entero, si usamos un tipo definido, pero cmo lo
haremos si la variable en la que se almacenar los datos es una cadena de longitud fija?
Para ello debemos "desglosar" los datos en distintas partes:
Para el Nombre usaremos los primeros 30 bytes de la cadena, para la edad los dos siguientes, es decir:
bytes 31 y 32, para el email desde la posicin 33 hasta la 82, osea desde la 33 con 50 bytes de longitud.
Si escribes esto:
Dim
Dim
Dim
Dim

unaCadena As String * 82
elNombre As String * 30
laEdad As String * 2
elEmail As String * 50

Dim nFic As Integer


Dim unaCadena As String * 82
Show
nFic = FreeFile
Open "miscolegas.dat" For Random As nFic Len = Len(unColega)
elNombre = "Pepe de 23 aos"
laEdad = 23
elEmail = "Pepe23@mundo.net"
unaCadena = elNombre & laEdad & elEmail
Put #nFic, 2, unaCadena
Close nFic
No conseguirs el resultado esperado... en lugar de 23 aos, tendr: 13106 !!! Dudo mucho que llegue
a conseguir esa edad... ni an siendo un gnomo...
Si queremos guardar un nmero debemos convertirlo antes... el problema es que "NO HAY FUNCIONES
DE CONVERSIN"
Antes si que las haba... cuando digo antes, me refiero al Basic del MS-DOS.
Para cada tipo de dato numrico existan un par de funciones, una para convertir el nmero en una
cadena y el otro para convertir la cadena en un nmero...
Y no me estoy refiriendo a las funciones que convierten los nmeros en letras y las cadenas en
nmeros... aunque pueda parecerte una contradiccin... no es lo mismo convertir un nmero en una
cadena normal que en una cadena para almacenar en el disco como si de un nmero se tratase...

A saber, STR o CSTR convienten un nmero en una cadena, es decir que si el nmero es 23, lo
convierten en "23" en el caso de CSTR y en " 23" si se usa STR, fjate en el espacio que hay antes del 2
en el segundo caso.
Pero cuando se debe convertir un nmero en una cadena de 2 bytes... la cosa cambia...
Y no te confundas... no pienses que si usas CSTR lo tienes solucionado... porque en el ejemplo este de
"23" est claro... pero y si el nmero es 1998? Tendriamos una cadena de 4 caracteres...
Como te deca, en los tiempos del MS-DOS, existan las funciones MKI$ y CVI para convertir los
nmeros enteros; MKL$ y CVL para los enteros largos, MKS$ y CVS para los "singles" y MKD$ y CVD
para los Double. No busques estas funciones... porque no estn...
Aunque podemos fabricarnoslas... pero, como no es plan de "romperse" el coco con una chorradilla de
estas... slo vamos a usar el ejemplo de los nmeros enteros.
Cmo se usaran?
En el ejemplo anterior hariamos esto:
elNombre = "Pepe de 23 aos"
laEdad = Mki(23)
elEmail = "Pepe23@mundo.net"
unaCadena = elNombre & laEdad & elEmail
Put #nFic, 2, unaCadena
La funcin se hara as:
Private
Dim
Dim
Dim

Function Mki(ByVal unInteger As Integer) As String


sLoByte As String
sHiByte As String
iChar As Integer

iChar = unInteger \ 256


sHiByte = Chr$(iChar)
iChar = unInteger Mod 256
sLoByte = Chr$(iChar)
'Devolvemos el valor
Mki = sLoByte & sHiByte
End Function
Que complicacin verdad?
Pues como estas... muchas ms... pero eso antes, en el MS-DOS... desde que hay "mogolln" de
espacio de almacenamiento... he perdido de vista muchas de estas cosas de "manejo" de nmeros a
"bajo nivel"...
Pero antes haba que ahorrar cuantos bytes se pudieran...
La cuestin es que se divide el nmero en dos partes, la alta que se consigue dividiendo el entero entre
256 y la baja, que es el resto que queda... despus de haberlo dividido por 256... que de eso es de lo que
se encarga el MOD...
Despus se convierten esos valores en dos bytes usando el CHR$... se unen... y sin necesidad de
agitarlo... conseguimos el "batido" que queremos... por tanto, lo asignamos al valor que devolver la
funcin... (recuerda que una funcin devuelve un valor cuando se asigna ese valor a su nombre...)
Bien... un lio... verdad?
Pues ahora ms lios...
Cmo se asigna esto al revs? Es decir: Cmo se convierte una cadena de 2 bytes en un entero?
Con los tipos definidos no hay que hacer nada... ya sabes, que hace la conversin automticamente.
Pero si usamos una cadena de longitud fija... ya es otro cantar...
Vamos a ver la declaracin de la funcin "equivalente" al CVI del viejo Basic del MS-DOS:
Private Function Cvi(ByVal unaCadena As String) As Integer
Dim sLoByte As String
Dim sHiByte As String
sLoByte = Left$(unaCadena, 1)

sHiByte = Right$(unaCadena, 1)
'Devolvemos el valor
Cvi = Asc(sLoByte) + Asc(sHiByte) * 256
End Function
No voy a entrar en detalles, as que paso a un ejemplo "completo" para ver estos resultados.
Si vas a comprobar cmo "trabajan" alguna de estas funciones usando "puntos de interrupcin", es decir
que quieres que el VB se detenga en una lnea determinada, (para ello debers posicionarte en la lnea,
que no debe ser un comentario, y pulsar F9, al llegar a esa lnea el Visual se detiene), debers cambiar
la propiedad Autoredraw del form y ponerla a TRUE, de esta forma el contenido del Form (el que se
imprime dentro del Form_Load), se mantiene...
'Esto escribelo en el Form_Load
Dim nFic As Integer
Dim unaCadena As String * 82
Dim laEdad23 As Integer
Show
laEdad23 = 23
nFic = FreeFile
Open "miscolegas.dat" For Random As nFic Len = Len(unColega)
'Asignamos los datos
With unColega
.Nombre = "Pepe"
.Edad = 22
.email = "pepe22@mundo.net"
End With
Put #nFic, 1, unColega

Dim elNombre As String * 30


Dim laEdad As String * 2
Dim elEmail As String * 50
elNombre = "Pepe de 23 aos"
laEdad = Mki(laEdad23)
elEmail = "Pepe23@mundo.net"
unaCadena = elNombre & laEdad & elEmail
Put #nFic, 2, unaCadena
Get #nFic, 1, unColega
With unColega
Print
Print "Colega 1:"
Print .Nombre
Print .Edad
Print .email
End With
'Si se lee as, no hay problemas
Get #nFic, 2, unColega
With unColega
Print
Print "Colega 2:"
Print .Nombre
Print .Edad
Print .email
End With
'De esta manera est la cosa ms complicada...
Get #nFic, 2, unaCadena

Print
Print
Print
Print
Print

"Colega 2:"
Mid$(unaCadena, 1, 30)
Cvi(Mid$(unaCadena, 31, 2))
Mid$(unaCadena, 33, 50)

Observa que aunque el segundo dato se haya guardado usando una cadena de longitud fija,
(unaCadena), se puede leer tanto con un tipo definido, si es de la misma longitud, claro, como con la
cadena de longitud fija.
El problema es que tenemos que "desglosar" el contenido de esa cadena... Recuerda que te coment
que cada uno de los "campos" del registro ocupa un espacio determinado... osea que tienen una longitud
fija... por eso hay que usar el Mid$, para tomar cada uno de los "trozos" de esa cadena.
El Mid$ funciona de la siguiente forma:
Mid$ (cadena, posicin_de_inicio, numero_de_caracteres)
Lo que significa que devolver el nmero de caracteres indicados
por numero_de_caracteres empezando por la posicin: posicin_de_inicio. En caso de que no se
especifique el nmero de caracteres, devolver toda la cadena desde la posicin indicada hasta el final
de la misma.
Y ya que estamos con estas funciones... voy a explcarte las dos usadas en la funcin CVI:
Left$ y Right$
El Left$ toma de una cadena los caracteres que se le indiquen, empezando por la izquierda.
Right$ hace lo mismo, pero empieza a contar desde la derecha.
Unos ejemplos:
Left$("Hola Mundo", 4) devolver "Hola", es decir los 4 primeros caracteres.
Right$("Hola Mundo", 4) delvolver "undo", porque son los cuatro caracteres que hay a la derecha...
El Left$ se puede sustituir por Mid$ de la siguiente forma:
Mid$("Hola Mundo", 1, 4) es decir: empezando por el primer caracter, dame cuatro...
Sin embargo esto otro:
Mid$("Hola Mundo", 4) nos dar: "a Mundo", o lo que es lo mismo: desde la posicin cuarta, todo lo
que haya en la cadena.
Y si quieres imprimir cada uno de los caracteres de una cadena, prueba esto:
Dim i As Integer
Dim unaCadena As String
unaCadena = "Hola Mundo"
For i = 1 To Len(unaCadena)
Print Mid$(unaCadena, i, 1)
Next
Lo que se hace aqu es un bucle para cada uno de los caracteres de la cadena, esto se sabe con LEN,
que devuelve la longitud de una cadena y con el Mid$, vamos tomando todos los caracteres de uno en
uno. Ya que le decimos que nos muestre el caracter que est en la posicin i... slo muestra uno, porque
esa es la cantidad que le indicamos que nos devuelva...
UF! Creo que algunas veces se me va la olla... y se me olvidan cosas que... creyendo que he
explicado... las uso...
En fin... la cuestin es que ahora sabes unas instrucciones nuevas...
Y ya que estamos...
Veamos cmo se puede usar tambin MID$, lo que ocurre es que esta "funcin" tambin es una
"instruccin", al igual que ocurra con INPUT, segn se use delante o detrs del signo igual, se convierte
en funcin o en instruccin.
Ya sabes que una funcin devuelve un valor y se puede usar en una expresin, pero una instruccin
"hace" algo y no devuelve ningn valor ni se puede usar en una expresin.

En el ejemplo de guardar los registros, se usaron tres variables para almacenar los datos en el fichero:
Dim elNombre As String * 30
Dim laEdad As String * 2
Dim elEmail As String * 50
elNombre = "Pepe de 23 aos"
laEdad = Mki(laEdad23)
elEmail = "Pepe23@mundo.net"
unaCadena = elNombre & laEdad & elEmail
Put #nFic, 2, unaCadena
Pues esto mismo se puede hacer de esta otra forma:
Mid$(unaCadena, 1, 30) = "Prueba de una cadena"
Mid$(unaCadena, 31, 2) = Mki(laEdad23)
Mid$(unaCadena, 33, 50) = "pepe23@mundo.net"
Put #nFic, 2, unaCadena
Es decir, al igual que la funcin con el mismo nombre, la instruccin MID$ sustituye en "unaCadena" los
caracteres indicados por el inicio y la longitud por los que estn despus del signo igual...
Creo que me he pasado... bueno, esto al final viene bien... ya que as tenemos otra entrega "medio"
preparada... ya que de la que tena prevista de 7 pginas "manuscritas" slo he usado 2 y poco ms...
Para completar esta "extraa" entrega... extraa por "no prevista"... vamos a "rematarla" con unos
ejercicios, que en este caso sern de manejo de cadenas con las funciones que acabamos de ver...
Los ejercicios:
1- Haz que se muestren los caracteres de una cadena al revs.
Por ejemplo, si la cadena es "Hola Mundo", se deber imprimir: "odnuM aloH"
Que es til si queremos hacer carteles para que se vean al derecho al mirar por el retrovisor del coche...
(por decir algo)
2- Usando esta misma cadena, es decir "Hola Mundo", dividela en las dos palabras.
Se supone que deber servirte para cualquier frase, as que no hagas nada "fijo".
Lo que tienes que hacer es devolver en una cadena todos los caracteres hasta el primer espacio y el
resto en otra cadena.
Para esto, si quieres, puedes usar el Left$ y el Mid$... al menos para la primera palabra.
Y ya est... no te voy a complicar ms la vida... que ya vendrn complicaciones posteriores.
Pulsando en este link tienes las soluciones.

Para terminar, slo pedirte disculpas por haberme/haberte "liado"... pero... eso es lo que hay... 8-)

Y como no es plan de perder la costumbre de pedirte que hagas un comentario de la entrega que acaba
de terminar... aqu tienes el link para que me hagas saber que te ha parecido...

Curso Bsico de Programacin


en Visual Basic

Entrega Diecisiete: 16/Abr/98


por Guillermo "guille" Som
Si quieres linkar con otras entregas, desde el ndice lo puedes hacer

A estas alturas ya estars acostumbrado a mis "desvarios", eso demuestra que soy de lo menos
ordenado de lo que se pueda ser, pero... ese es un problemilla que llevo conmigo desde chiquitillo, as
que...
La cuestin es que parece ser que no voy a terminar con esto del acceso a los ficheros... y eso que
tengo ganas de terminar con ello para poder pasar a otra cosa, pero... se me resiste el tema...
Realmente no es que se me resista, es que por el camino van surgiendo nuevas cosillas que es bueno
que sepas y como este curso no est enfocado para que lo aprueben en ningn plan nacional de
estudios... pues eso...
Lo que si que me interesa saber es que no te pierdes con tantos desvarios... es decir, que sigues la
lnea... aunque eres libre de poder desviarte y salirte por la tangente para mirar los manuales y la ayuda
del Visual Basic, que aunque no te lo creas, tambin sirve para aprender... ahora, lo que pasa es que hay
que saber comprenderla... y de eso creo que es de lo que de una forma u otra me estoy encargando yo...
si no lo consigo, malo y si lo consigo... mejor para todos.
Siguiendo con esos desvarios, vamos a empezar esta entrega con el manejo de las cadenas, que,
aunque ya vimos un poco de ella en la entrega anterior, no estar de ms saber algo ms. Ten en cuenta
que la mayora de las veces vamos a manipular cadenas... y no es plan de que nos pillen "atados" sin
saber que hacer... (chiste malo, lo reconozco...)
Seguramente no me voy a enrollar demasiado en este tema, digo "seguramente" porque no s en que
acabar esta entrega... as que paciencia y disfruta y aprende con lo que se diga en ella.
Ahora vamos al tema.
Ya hemos visto, cmo tomar caracteres de una cadena desde el principio (LEFT), desde el final (RIGHT)
y desde cualquier punto (MID); tambin podemos saber cuantos caracteres tiene una cadena (LEN) e
incluso convertir un nmero en cadena (CSTR) o una cadena en nmero (VAL).
Tienes que recordar que el VB tiene como tipo de variable por defecto el Variant, por tanto estas
funciones realmente devuelven un tipo Variant, dentro de este tipo hay una serie de subtipos, que
realmente son los tipos que vimos al principio de este curso, es decir Integer, Long, String, etc. A que
viene este nuevo lio Guille? A que es conveniente que lo sepas, nada ms, pero, al menos por ahora no
te preocupes por ello, el VB se encarga de hacer sus conversiones, aunque nosotros podemos obligarle
a que lo haga, para ello debermos usar esas dunciones aadindole al final el signo dlar ($), ya sabes
que ese signo es el que se emplea para indicar que una variable es de cadena. Por tanto LEFT$, MID$ y
RIGHT$ devolvern siempre una cadena, mientras que LEFT, MID y RIGHT lo que devuelven es un
Variant de subtipo String... un lio... pero ya te digo que no debes preocuparte.
Hay un montn de funciones para esto del manejo y conversin de las cadenas, en esta entrega
veremos algunas de ellas, las que usaremos ms a menudo. Si eres de espritu inquieto, (por decir algo),
puedes echar mano de la ayuda del Visual Basic y buscar las distintas funciones e instrucciones que
manejan o manipulan las cadenas... la verdad que te puedes entretener bastante con ellas... aunque no
te fies de todo lo que veas y te diga la ayuda si no lo compruebas por ti mismo... que al menos uno de los
ejemplos est equivocado, pero me imagino que se deber a la traduccin... en fin... por no fiarte, no te
fies ni de lo que yo te diga, siempre comprueba las cosas, as saldrs de dudas... y si no sales de dudas,
pues... peor "pa t"
Creo que voy a complicarte un poco ms la vida, pero no te espantes, no va a ser en vano.
Adems de los tipos de datos que hemos vistos hasta ahora, hay otro que sirve para esto de las
cadenas, o casi, ya que se podra usar para manejar cada uno de los bytes de una cadena, fijate que he
dicho "bytes" y no caracteres, ya que si trabajas en un entorno de 32 bits, cada caracter de una cadena
se compone de dos bytes, si ests usando el VB de 16 bits slo hay un byte por cada uno de los
caracteres. El tipo en cuestin es BYTE y en ese tipo slo se puede almacenar un valor que va desde 0
a 255, es decir un byte, la lgica algunas veces es aplastante...
As que, si le echas un vistazo a la ayuda, te encontrars con algunas funciones que tienen al final una

letra B, eso significa que devuelve valores tipo Byte, as por ejemplo LENB, devolver el nmero de bytes
que tiene una cadena.
Prueba esto, vers que si lo usas con el VB de 16 bits te devuelve una cosa distinta a lo que hara en 32
bits:
Print Len("Hola Mundo")
Print LenB("Hola Mundo")
Lo que se mostrar, (recuerda de ponerle un show, si escribes este cdigo en el evento Show del form),
ser 10 y 20 si usas el VB de 32 bits, (recuerda que el VB5 slo es de 32 bits), pero en 16 bits (VB3
VB4-16), mostrar en ambos casos 10.
Vamos a practicar algunas cosillas con esto de los Bytes (o con datos de tipo Byte).
Ya sabes que puedes crear una array de cualquier tipo de datos, incluso de tipos definidos, as que
tambin podemos crear arrays del tipo Byte, pero este tipo de arrays tienen una particularidad.
Una cadena (variable de tipo string), realmente es un array del tipo Byte, esto nos permite manejar las
cadenas de caracteres como si fuesen arrays de bytes o mejor an usar los arrays del tipo byte, como si
fuesen cadenas.
Vamos a comprobarlo, pon estas lneas de cdigo en el evento Load de un form:
Show 'para que se muestre
Dim aByte() As Byte
aByte = "Hola Mundo"
Print aByte
Como comprobars se muestra Hola Mundo... igual que si lo hubieses asignado a una cadena de
caracteres.
En el VB4-16 te habr dado un error, para evitar ese error y que se muestre el contenido, puedes
asignarlo a una cadena e imprimir esa cadena, tambin puedes asignarlo a un Label y se mostrar el
contenido de ese array como si fuese una cadena.
Esto mismo, por supuesto tambin es aplicable al Visual Basic de 32 bits.
Aclaracin para los que trabajeis con 16 bits:
Para no complicar mucho las cosas, si ests usando 16 bits, comprueba lo que aqu se diga
y saca tus propias conclusiones.
A pesar de que an hay sistemas funcionando de 16 bits y gente que por tanto programa
para esos sistemas, creo que el enfoque adecuado de este curso debera concentrarse en
los sistemas de 32 bits, de todas formas, la mayora de las cosas "realmente" vlidas
servirn tanto para 16 como para 32 bits.
Pero voy an ms lejos, dentro de poco, no s realmente en cuantas entregas, pero el
enfoque se ir concentrando en el Visual Basic 5 y posteriores, (cuando los haya), ya que en
el VB5 se han introducido cosas realmente interesantes para la programacin enfocada a
objetos, (que pronto empezaremos a tocar), que aunque la mayora de esas cosas sean
vlidas para el VB4, en algn momento dejar de serlo y slo sern aplicables al VB5 y
posteriores...
Quiero dejar esto claro, para que despus no haya sorpresas... de todas formas, recalco que
esto es un curso bsico y como tal, servir para prcticamente cualquier versin de VB,
aunque mi "despiste" seguramente me llevar a tocar cosas slo aplicables en el VB5...
aunque eso ser seguramente en la segunda parte de este curso... que la habr, de eso
puedes tener casi un 100% de certeza.
Pero si pruebas esto:
Print Len(aByte)
El Visual Basic te dir que "nanai de la china", osease que no puedes saber cuantos caracteres tiene un
array de bytes...
Al menos usando Len... ni an usando LenB, as que si quieres lo compruebas, pero te dar el mismo

error.
Ahora bien, para saber los elementos que contiene un array, vimos que existen dos funciones: LBOUND
y UBOUND, la primera para saber el valor del primer elemento y la ltima para saber el ltimo elemento
del array. Por tanto podemos usar estas dos funciones para averiguar la longitud de esa cadena:
Print UBound(aByte)
Esto nos dar el nmero mximo de bytes de este array... s, muestra 19 (en 32 bits), en el entorno de 16
bits nos informar de que el elemento mayor de esta matriz es de 9; ya sabes que para 32 bits cada
caracter son dos bytes, por tanto 10 carecteres son 20 bytes. El porqu de que muestre uno menos es
porque empieza a contar por CERO, es decir que el elemento inferior de este array ser cero, lo
podemos comprobar con esto otro:
Print LBound(aByte)
Tanto en VB de 16 cmo de 32 bits mostrar cero.
Si te preguntas que pasara si se aadiera a las declaraciones generales del Form la instruccin: Option
Base 1, puedes comprobarlo, pero no cambiar los resultados mostrados, los arrays de Byte siempre
empiezan por cero, independiente del valor que indiquemos en el Option Base.
Esto es una afrimacin a medias, me explico, si a un array de bytes le asignas el contenido de una
cadena, el elemento inferior siempre ser CERO, pero puedes dimensionar una matriz de este tipo de la
misma forma que lo haras con cualquier otra de cualquier otro tipo de datos. Lo que ocurre es que
deberas tener la precaucin de que el nmero de elementos fuese par si lo que pretendes es que
contenga "algo parecido" a una cadena.
Vamos a seguir probando un poco ms, escribe este cdigo:
Dim aByte() As Byte
aByte = "Hola"
Dim i&
Print aByte
For i = LBound(aByte) To UBound(aByte)
Print aByte(i);
Next
Print
En el VB de 16 bits, te mostrar esto: 72 111 108 97, sin embargo en 32 bits el resultado sera este otro:
72 0 111 0 108 0 97 0 (si, ya se que he dicho que no iba a decir nada de los 16 bits, pero...)
Con esto, se demuestra, ms o menos, eso de que cada caracter de 32 bits ocupa dos bytes, el primero
es el normal y el segundo es el extendido...
Para "rematar" esto de los arrays de bytes, una ltima prueba, si usas el VB4-16 debers modificarlo un
poco, ya que slo tienes un byte por cada caracter y realmente es menos "instructivo" que si ests
usando 32 bits.
'Se supone que tienes estas declaraciones de las variables i y a:
'Dim a$, i&
'Los valores deben ser pares
ReDim aByte(-10 To 19)
Dim j%
j = 65
For i = LBound(aByte) To UBound(aByte) Step 2
aByte(i) = j
aByte(i + 1) = 0
j = j + 1
Next
Print aByte
Print LBound(aByte), UBound(aByte)
a = aByte
Print a

Aqu hemos usado un array de bytes con ndices que van de -10 a 19, recuerda que de -10 a -1 van 10 y
de 0 a 19 van 20, por tanto sern 30 los bytes que tiene este array, es decir 15 caracteres, que van
desde A (65) hasta O (letra o mayscula, 79), por eso se imprimen estos quince caracteres:
ABCDEFGHIJKLMNO.
Para terminar con estas pruebas, escribe esto a continuacin de lo anterior:
Print LeftB(a, 6)
Print RightB(a, 6)
Print MidB(a, 5, 6)
Esto ser lo que habr mostrado (en 32 bits): ABC, MNO y CDE
Fijate que el MidB empieza por un nmero impar, si lo hicieras por uno par, el VB te mostrara una serie
de interrogaciones... porque no sabe que es lo que quieres hacer con eso... ms o menos...
Si te preguntas que es lo que ocurrira si en lugar de MidB(a, 5, 6) escribieras esto otro: MidB(a, 0, 6), te
encontraras con un error del Visual Basic, ya que el argumento desde, debe ser un valor 1 hasta la
longitud de la cadena.
Bien, ya sabes algo ms, el resto que veamos tratar de las funciones de cadenas normales y corrientes,
cualquier otra prueba con bytes la haces "por libre", cosa que te recomiendo para que te vayas
acostumbrando a ellas, pero no te compliques demasiado, ya que no son tan frecuentes como debieran y
siempre tendrs a mano la ayuda para poder "recordar" que estn ah.

Ms funciones de manejo de cadenas, por favor.


Convertir nmeros a cadenas:
Cuando quieras convertir un nmero en una cadena, adems de usar la "conversin automtica" que
hace el propio VB, puedes usar cualquiera de estas dos funciones: CStr y Str$
La diferencia "visible" entre estas dos funciones es, que la primera te devuelve slo el nmero, sin
espacios, mientras que la segunda, en caso de que sea un nmero positivo, devolver el nmero pero
con un espacio delante:
Dim a$, i%
i = 10
a = CStr(i)
Print "i=" & a
a = Str$(i)
Print "i=" & a
Como vers, en el primer caso se mostrar: i= 10, en el segundo: i=10, es decir que Str$ le aade el
espacio que tiene los nmeros positivos. Si el valor de i fuese -10 mostrara lo mismo en ambos casos.

Cambiar a maysculas / minsculas:


Para hacer esto, usaremos las funciones: LCase y UCase, la primera convierte la cadena a minsculas y
la segunda a maysculas:
a = "Un niito clido"
Print LCase(a)
Print UCase(a)
Aunque sea una chorradilla de frase, es para que compruebes que los caracteres acentuados y la ee
tambin se convierten.
Como en los nmeros no tiene sentido esto de la conversin, permanecen iguales.

Quitar los espacios del principio y del final:


Las funciones usadas para hacer esto, son tres: LTrim$, RTrim$ y Trim$
La primera quita los espacios del principio, la segunda los espacios en blanco del final y la tercera los
quita tanto del principio como del final.
Esta ltima funcin es lo mismo que si hicieramos esto: Ltrim$(RTrim$(unaCadena)), que es lo que haca
yo antes de que el Visual Basic incluyese esta funcin...
Vamos a ver un ejemplo:
a = "
Un ejemplo "
Print "<" & LTrim$(a) & ">"
Print "<" & RTrim$(a) & ">"
Print "<" & Trim$(a) & ">"
El resultado ser el siguiente: <Un ejemplo >, < Un ejemplo>, <Un ejemplo>
Es decir: se comprueba que actan como se esperaba...

Averiguar el cdigo de los caracteres:


Ya sabes que cada "letra" que puede tener una cadena de caracteres est representada por un cdigo,
as la A es el cdigo 65, la Z es el 90, la a es el 92 y la z es el 132. El cdigo del espacio es 32.
Para averiguar los cdigos de los caracteres y para asignar a una cadena cualquier cdigo, convertido en
el correspondiente caracter, se usan las funciones Chr$ y Asc.
La primera devuelve el caracter correspondiente al nmero que se le pasa como parmetro.
La segunda hace la operacin inversa, nos dice cual es el cdigo del caracter que se le ha indicado.
Veamos un ejemplo:
Print Asc("Z")
Print Chr$(90)
El primero nos dir que 90 es el cdigo de la Z maysculas y en el segundo caso, nos confirma que el
caracter representado por 90 ser la Z.
Si en ASC se le pasa una cadena con ms de una caracter, slo nos devuelve el valor del primero:
Print Asc("Hola")
Imprimir 72, es decir el valor de la H mayscula.

Llenar una cadena con una cantidad de caracteres:


Para esto, podemos usar un bucle y en cada iteracin del mismo incrementar el contenido de una
cadena o bien podemos usar dos de las funciones que el Visual Basic pone a nuestra
disposicin: Space$ y String$
La primera devuelve la cantidad de espacios que se le indique, si queremos 10 espacios haremos esto: a
= Space$(10)
A la segunda se le pasan dos parmetros, el primero indicando la cantidad de caracteres que queremos
y el segundo el cdigo de ese caracter: a = String$(10, 65) nos dar diez letras A maysculas.
Tambin podemos pasarle en el segundo parmetro una cadena, por tanto el ejemplo anterior se podra
escribir as:
a = String$(10, "A")
Si la cadena que le pasamos tiene ms de un caracter, nos devuelve slo el primer caracter de esa
cadena:
a = String$(10, "Pepe")
Es decir slo 10 letras P.

Comparar el contenido de dos cadenas:


Ya sabes que las cadenas se pueden comparar igual que se hacen con los nmeros: usando el signo
igual.

If "Hola" = "hola" Then


Es un ejemplo "chorra", pero se puede hacer.
Esta comparacin debera devolver FALSE, ya que la H inicial en una de las cadenas est en
maysculas y en la otra en minscula. Si no le hemos indicado nada al VB, nos dir que son diferentes,
pero podemos indicarle al Visual que al comparar las cadenas, ignore las diferencias entre las
maysculas y minsculas. Para ello tendremos que agregar en la parte general del mdulo, donde est
el Option Explicit, la siguiente instruccin:
Option Compare Text
De esta forma, las comparaciones realizadas siempre sern independiente de que sean maysculas o
minsculas, incluso si estn mezcladas las maysculas con las minsculas.
Por defecto el Visual Basic hace lo que se llama una comparacin binaria, es decir que comprueba el
cdigo de cada uno de los caracteres que componen las cadenas; tambin se le puede indicar esto para
que todas la comparaciones realizadas sean siempre en modo "binario", aunque no hace falta indicarlo,
ya que es el valor por defecto, pero si quieres hacerlo, para saber que ests haciendo las comparaciones
de esa forma, aade esta lnea:
Option Compare Binary
Las comparaciones tambin se pueden efectuar para saber cual es mayor o menor, el VB se guiar por
el cdigo de cada caracter comparado, debers tener en cuenta que los nmeros estn antes que las
letras, por tanto "1234" sera menor que "ABCD" y "VWXYZ" ser mayor que "DEFGH"
Pero adems de efectuar las comparaciones de esta forma, existe una funcin que sirve precisamente
para eso: StrComp
Esta funcin permite que las comparaciones se hagan de distinta forma:
Usando el valor por defecto, es decir el indicado en Option Compare,
usando siempre comparacin binaria, (distingue entre maysculas y minsculas)
y usando siempre comparacin "textual", (no hace distincin entre maysculas y minsculas)
Los parmetros que usa esta funcin son los siguientes: cadena1, cadena2 y opcionalmente el tipo de
comparacin a realizar.
Si este ltimo parmetro no se especifica, se efectuar la comparacin segn se indique en Option
Compare.
En otro caso, los valores pueden ser: 0 (comparacin binaria) 1 (comparacin textual).
Existe otro valor que es usado para las bases de datos de Access, pero que nunca lo he llegado a
probar... slo lo he visto cuando he leido la ayuda.
Los valores que devolver esta funcin sern:
0 si las dos cadenas son iguales,
-1 si la primera cadena es menor que la segunda
1 si la primera cadena es mayor que la segunda.
Debes tener en cuenta que "HOLA" es menor que "hola", si la comparacin es binaria, lo mismo con
"Hola", ya que la H mayscula tiene un cdigo menor que la h minscula.
Veamos un ejemplo:
Dim b$
a = "Hola"
b = "hola"
Print "Usando el Option Compare: "; StrComp(a, b)
Print "Usando comparacin textual: "; StrComp(a, b, vbTextCompare)
Print "Usando comparacin binaria: "; StrComp(a, b, vbBinaryCompare)
Los valores de las constantes vbTextCompare y vbBinaryCompare ya estn definidos por el VB y son 1 y
0 respectivamente.

Asignar valores e incrementar el contenido de una cadena:


Muchas de las cosillas que estamos viendo en esta entrega, ya se han usado en otras entregas, pero as
tendrs una referencia ms a mano... adems de servirte de recordatorio, por si lo has olvidado.
La concatenacin consiste en aadir a una cadena el contenido de otras cadenas o caracteres.

Como sabrs si quieres incrementar el valor de una variable numrica, haces esto: Num = Num + 1
El basic interpretar primero la expresin, o lo que haya despus del signo igual y el resultado lo
asignar a la variable que est a la izquierda del signo igual.
Lo mismo hace con las cadenas de caracteres, lo que ocurre es que slo permite la suma. Aunque desde
hace tiempo que Microsoft no recomienda esta forma de concatenar las cadenas, ya que el Visual Basic
puede "malintepretarlo" y recomienda que se use el signo & (ampersando, creo que se llama). Usando
ese signo, el VB sabe exactamente lo que debe hacer.
Por tanto si haces esto:
a = "Hola"
b = "mundo"
a = a & " " & b
Print a
Te mostrar Hola mundo, es decir ha guardado en "a" lo que ya haba adems de un espacio y el
contenido de "b"
Este tipo de concatenacin tambin pudes hacerlo en los controles Label y Text o en cualquiera que
disponga de alguna propiedad en la que puedas guardar una cadena.
Por ejemplo el Caption de un label (que es la propiedad por defecto y por tanto se puede omitir).
Si tienes un Label2 en el form, podras hacer esto:
Label2 = "Hola"
Label2 = Label2 & "

" & b

Y se mostrar en ese label lo mismo que antes se imprimi. Esto mismo se puede hacer indicando que
se asigna a la propiedad Caption de esa etiqueta:
Label2.Caption = "Hola"
Label2.Caption = Label2.Caption & "

" & b

El resultado sera el mismo.

Averiguar la posicin de una cadena dentro de otra:


Para esto usaremos la funcin Instr, esta funcin espera dos parmetros como mnimo, aunque permite
cuatro:
Instr( [posInicio,] Cadena1, Cadena2[, tipo_comparacin])
Las dos cadenas, son las que usar para devolver la posicin de la segunda cadena dentro de la
primera.
Si hacemos esto: Print Instr("Hola mundo", "mundo") nos mostrar un SEIS, ya que "mundo" est en
la posicin sexta, al menos ah es dnde empieza.
Si se especifica posInicio, empezar a comprobar a partir de esa posicin inclusive, por tanto:
Print Instr("Hola mundo", "o") imprimir 2
Print Instr( 6, "Hola mundo", "o") imprimir 10, ya que busca una letra "o" a partir de la posicin 6.
El ltimo parmetro: tipo_comparacin es para realizar comparaciones binarias o de texto, como ya
hemos visto anteriormente, si este parmetro tiene la misma funcin que en StrComp. Es decir si no se
especifica, la comparacin se hace segn el Option Compare y si se indica, se hace segn lo indicado.
Si especificas este parmetro, debers indicar tambin la posicin de inicio, sino el VB te dir que los
tipos de datos no coinciden.
Un ejemplo:
Print
Print
Print
Print
Print

InStr("Hola mundo", "o")


InStr(6, "Hola mundo", "o")
InStr("Hola mundo", "O")
InStr(1, "Hola mundo", "O", vbBinaryCompare)
InStr(1, "Hola mundo", "O", vbTextCompare)

Dependiendo de que tengamos Option Compare Text el tercer caso imprimir un cero (si no tenemos la
comparacin textual) o un 2 si tenemos esa opcin de comparacin

En los dems casos, siempre devolver el mismo resultado.


Pero no te confundas, devuelven lo mismo, porque sabemos que debe devolverlo, ya que se especifica
como segunda cadena una constante que representa a una "o" minscula y en la primera cadena
tenemos dos de esa letra, otro gallo cantara si tanto la primera como la segunda cadena fuesen
variables y no sabemos lo que va a contener.
Cuando sea imprescindible saber la posicin de una cadena dentro de otra, teniendo en cuenta el que
haya que distinguir o no entre las maysculas y minsculas, es recomendable que uses el tipo de
comparacin que quieres realizar.
Si no lo haces, al menos recuerda o comprueba que tipo de comparacin se realizarn por defecto en
ese mdulo.
Bien, creo que ya tienes a tu disposicin casi todas las funciones de manejo de cadenas que puedas
necesitar.
Ahora toca que practiques un poco con ellas para que le vayas cogiendo el "tranquillo" y te las aprendas.
Una cosa que quiero aclarar es que no pretendo hacer con este curso un "sustituto" de la ayuda o los
manuales del Visual Basic, por eso te recomiendo siempre que las instrucciones con las que te
encuentres en algunos de los ejemplos, las busques en la ayuda o los manuales, lo mismo que para
saber "manejarte" en el entorno de Visual Basic. S que esto ya lo he dicho antes, o al menos debera
haberlo dicho, pero lo hago de nuevo para que no esperes un "diccionario" de todas las instrucciones
que tiene el Visual Basic. Lo que pretendo siempre es que te enteres de cmo se usan esas
instrucciones e incluso cuando usar una en lugar de otra... en fin... si ves que alguna que otra vez se me
va la "olla", me lo dices e intentar solucionar ese despiste.
Ejercicios?
Te podra poner muchos... pero slo voy a ponerte uno y con ese tendrs "pa rato"
Escribe una funcin que devuelva la posicin de una cadena dentro de otra, pero comprobando esa
posicin por el final.
Es decir que Instr("Hola Mundo","o") devolvera 2, pero con nuestra funcin devolvera 10.
Podramos llamarla RInstr y se usara as: RInstr("Hola mundo","o")
Haz una segunda versin en la cual se le pase como primer parmetro la posicin por la que se
empezar a comprobar, de esta forma: RInstr2(6,"Hola mundo","o") nos dar un valor 2
En las soluciones veremos cmo podemos indicar parmetros opcionales en nuestros procedimientos y
crearemos una nica funcin que se use igual que Instr, es decir pasndo como primer parmetro
opcional la posicin de inicio de la bsqueda.

Y siguiendo la "sana" costumbre, te pido tu opinin sobre esta entrega.

Curso Bsico de Programacin


en Visual Basic
Soluciones de la entrega Diecisiete.
Fecha: 16/Abr/98

Empezaremos viendo la parte fcil del ejercicio, es decir la que nos muestra la posicin cuando la
funcin espera slo dos parmetros, el primero ser la cadena en la que hay que encontrar lo que haya
en la segunda cadena.
Private Function RInstr1(ByVal s1 As String, ByVal s2 As String) As Long
Dim i As Long
Dim sTmp As String
RInstr1 = 0

For i = Len(s1) To 1 Step -1


sTmp = Mid$(s1, i, Len(s2))
If sTmp = s2 Then
RInstr1 = i
Exit For
End If
Next
End Function
Este tiene poco que explicar.
Se hace un bucle desde la ltima posicin de la primera cadena Len(s1) hasta el principio, ya que lo que
necesitamos es encontrar la posicin de s2 empezando a "mirar" desde el final.
A continuacin guardamos en sTmp un trozo de cadena que va desde la posicin actual y que contiene
tantos caracteres como tenga la segunda cadena, si te fijas, el bucle se podra hacer tambin de esta
forma:
For i = Len(s1) - Len(s2) + 1 To 1 Step -1
Ya que no nos sirve comparar el ltimo caracter con la cadena s2 cuando esta ltima tiene ms de un
caracter, por ejemplo.
Esto es inapreciable en cadenas cortas, pero en otras ms largas, acortar el tiempo del bucle.
Para el segundo caso, hay que saber que los procedimientos (sub y function) permiten parmetros
opcionales, estos se indican con la palabra Optional delante de los parmetros que vayan a ser
opcionales.
La nica pega es que cuando un parmetro es opcional los que le siguen tambin tienen que ser
opcionales.
Entonces cmo indicar que el parmetro opcional sea el primero?
Pues... ms o menos fcil... aunque con truco.
Cuando un parmetro es opcional, se puede usar la funcin IsMissing para comprobar si se ha
especificado o no ese parmetro.
Esto es cierto siempre que el parmetro opcional sea de tipo Variant sin un valor por defecto. En el VB4
todos los parmetros opcinales deben ser Variant y sin valores por defecto, pero en VB5 (y posteriores)
los parmetros opcionales pueden ser del tipo que queramos, adems de poder tener un valor por
defecto, es decir, si no se especifica, se le da un valor "predeterminado".
Ahora vamos a usar slo los parmetros sin valores predeterminados, pero ms adelante seguramente lo
usaremos.
Sabiendo que con IsMissing podemos averiguar si se ha especificado o no el parmetro en opcional,
haremos lo siguiente:
Si se especifican los tres parmetros, el primero ser la posicin por la que se empezar a comprobar.
Si no se especifica el ltimo parmetro, engaaremos al Visual Basic, dicindole que los dos parmetros
introducidos son la primera y la segunda cadena...
Ya ves que slo es echarle un poco de "cabeza" al asunto...
Vamos a ver la declaracin de esta funcin:
Private Function RInstr(ByVal v1 As Variant, ByVal v2 As Variant, Optional
ByVal v3 As Variant) As Long
Dim i As Long
Dim sTmp As String
Dim s1 As String
Dim s2 As String
Dim posIni As Long
If IsMissing(v3) Then
'Si no se especifican los tres parmetros
s1 = CStr(v1)
'La primera cadena
s2 = CStr(v2)
'la segunda cadena
posIni = Len(s1)
'el ltimo caracter de la cadena
Else
posIni = CLng(v1)
'la posicin por la que empezar
s1 = CStr(v2)
'la primera cadena (segundo parmetro)
s2 = CStr(v3)
'la segunda cadena (tercer parmetro)
End If
'Valor inicial de la bsqueda, si no se encuentra, es cero

RInstr = 0
'Siempre se empieza a buscar por el final
For i = posIni - Len(s2) + 1 To 1 Step -1
'Tomar el nmero de caracteres que tenga la segunda cadena
sTmp = Mid$(s1, i, Len(s2))
'Si son iguales...
If sTmp = s2 Then
'esa es la posicin
RInstr = i
Exit For
End If
Next
End Function
Ahora quedara hacer una funcin que comtemple las mismas opciones que tiene el Instr normal, es
decir que se pueda especificar un cuarto parmetro que nos indique si la comparacin se hace de una
forma u otra.
Que te parece esto como un ejercicio nuevo?
Saba que contestara de forma afirmativa... je, je...
Pues intntalo... y si quieres ver la solucin, selecciona el contenido de la caja negra esa que hay al final
y vers...

A ver si ya terminamos en la prxima entrega el acceso aleatorio a los ficheros

Curso Bsico de Programacin


en Visual Basic
Entrega Dieciocho: 26/Abr/98
por Guillermo "guille" Som
Si quieres linkar con otras entregas, desde el ndice lo puedes hacer

Ya es hora de seguir con los ficheros de acceso aleatorio, despus del alto en el camino para ver cmo
se manejan las cadenas de caracteres en Visual Basic, an no hemos visto todas las funciones, pero si
las ms comunes. No te preocupes... no voy a continuar en esta entrega con esas funciones... ya le
llegarn el turno...
Por fin! Habrs exclamado... y con razn... pero son cosas que debes saber... y como de lo que se trata
es de saber ms y/o mejor, pues... nunca estn de ms...
No recuerdo exactamente en que punto me qued en las explicaciones sobre el acceso aleatorio de la
entrega diecisis, as que... si ves que me repito, pues... salud! y a seguir adelante...
Una cosa que hay que tener superclarsimo en esto del acceso aleatorio, es que debemos usar tipos
definidos para acceder a los datos del fichero... para que complicarnos con funciones conversoras de
datos, si el Visual lo hace de forma automtica por nosotros? Por tanto, te aconsejo que "siempre" uses
variables definidas, ya que no hay un motivo vlido para no usarlas.
En los siguientes ejemplos, vamos a usar el tipo definido que usamos en la entrega diecisis, el del
colega...
En este primer caso, vamos a guardar en un registro determinado el contenido de tres cajas de textos,
cada una de ellas para cada uno de los campos del tipo definido:

Private
Dim
Dim
Dim

Sub cmdGuardar_Click()
unColega As t_colega
nFic As Long
numColega As Long

nFic = FreeFile
Open "colegas.dat" For Random As nFic Len = Len(unColega)
'Sacar un valor aleatorio
numColega = Rnd * 25 + 1
Label1(3) = "nmero de colega: " & CStr(numColega)
With unColega
.Nombre = Text1
.Edad = Val(Text2)
.email = Text3
End With
'Guardar los datos en el disco
Put #nFic, numColega, unColega
Close nFic
End Sub
Aqu vemos los pasos que normalmente se realizan con cualquier tipo de fichero...
--Se asigna a una variable un nmero de fichero libre (ya sabes: el canal por el cual VB se comunicar
con el disco)
--Se abre el fichero en cuestin, recuerda que las extensiones que uses son a tu antojo, no hay
necesidad de usar un tipo de extensin especfica, salvo que hagas un programa que "entienda" los
datos contenidos en ese tipo de extensin y puedas abrir los ficheros con slo hacer doble click... pero
esto es un tema para ms adelante...
--Se asigna a la variable el dato a guardar y
--Se guarda...
Este ejemplo no sera prctico, ya que puede que salga el mismo nmero ms de una vez y se perderan
los datos anteriores.
Porque debes saber que, cuando se guarda informacin en un registro determinado, ste funciona de la
misma forma que las variables... o casi, es decir: cuando se guarda un nuevo valor, el que hubiera antes
"desaparece".
Una cosa que debes saber, aunque me imagino que lo habrs comprobado al ejecutar el programa, y si
no ha sido as, no te preocupes... si te sirve de consuelo, tarde unos mesesillos en "detectar" esto que te
voy a explicar ahora...
Puedes acceder a cualquier registro de un fichero aleatorio, incluso si antes no has guardado nada. De la
misma forma, puedes guardar informacin en el registro 7 aunque antes no hayas guardado en ninguno
de los 6 anteriores.
El problema?
Que si lees informacin de un registro en el que no has guardado informacin anteriomente... puedes
encontrarte con "basura", y de hecho la encontrars...
Por qu?
Porque accedes a una parte del disco que, posiblemente tena guardada alguna otra informacin...
aprovecho esto, para decirte que, cuando borras un fichero del disco, este fichero no se borra, al menos
no se borra la informacin que contena.
Cmo solucionar este problemilla?
Hay varios mtodos, el que yo normalmente usaba, ahora casi no trabajo con ficheros de acceso
aleatorio, era guardar informacin "vaca" en unos cuantos registros y cuando esos estaban ocupados,
guardaba otro puado y as.
Algunas veces, si saba que el fichero iba a tener un nmero limitado de registros, los grababa todos con
datos vacos, es decir cadenas con slo espacios y nmeros con valor cero.
En otras ocasiones tena un campo del registro al que le asignaba un valor, si al leer el registro, tena ese
valor "predeterminado", quera decir que ya contena informacin vlida, si no era as, pona los campos
con valores "vacios" y as evitaba la basura.

Si quieres comprobarlo... as de paso me sirve para que veas un ejemplo de cmo acceder a los datos
del disco y mostrarlo en unas cajas de texto.
Private
Dim
Dim
Dim

Sub cmdLeer_Click()
unColega As t_colega
nFic As Long
numColega As Long

nFic = FreeFile
Open "colegas.dat" For Random As nFic Len = Len(unColega)
'Sacar un valor aleatorio
numColega = Rnd * 25 + 1
Label1(3) = "nmero de colega: " & CStr(numColega)
'leer ese registro
Get #nFic, numColega, unColega
With unColega
Text1 = .Nombre
Text2 = .Edad
Text3 = .email
End With
Close nFic
End Sub
Si has probado el ejemplo de guardar, para poder conseguir datos con contenido "basura", debers
probar algunas veces ms que las que hayas probado antes... por qu? porque estamos usando
nmeros aleatorios y al no existir un "Randomize", la secuencia de nmeros aleatorios siempre es la
misma cada vez que ejecutas el programa... lo recuerdas?
Bien, aparte del asuntillo este de la "basura", no tiene ningn misterio esto del acceso aleatorio... pero
an no hemos terminado, no queda mucho para que te toque "trabajar", pero todava tienes un respiro...
si a que te explique ms cosas se puede llamar respiro...
En el tercer ejemplo que vamos a ver, se van a mostrar todos los colegas que tenemos guardados en el
fichero. Se supone que los datos los hemos guardado de forma ordenada, no como en los ejemplos
anteriores, ya que no tiene ningn motivo guardar a los colegas aleatoriamente... no sea que cojan
complejo de bola de bingo...
Ya te he comentado que la longitud de todos los registros de un fichero aleatorio tienen que ser iguales...
y ahora lo podrs comprobar... que algunas veces no hay que fiarse de todo lo que yo diga...
El nmero de registros es el resultado de dividir la longitud del fichero por la longitud de cada registro...
numRegistros = Lof(nFic) \ Len(unColega)
Fjate que uso \ para dividir. Las divisiones realizadas con este signo dan como resultado nmeros
enteros, mientras que el habitual / realiza una divisin de coma flotante... es decir que puede tener
decimales.
Como un registro no puede estar formado por "nosecuantos caracteres y pico", en este caso es
recomendable el uso de la divisin de nmeros enteros, entre otras cosas porque tambin es ms
rpida...
Por tanto este cdigo nos informara del nmero de registros y hara un bucle entre todos los registros
que tiene el fichero.
'
nFic = FreeFile
Open "colegas.dat" For Random As nFic Len = Len(unColega)
numRegistros = Lof(nFic) \ Len(unColega)
For i = 1 To numRegistros
Get #nFic, i, unColega
'Mostrar el contenido del registro
'...

Next
Close nFic
Podemos sustituir el Get #nFic, i, unColega por esto otro: Get #nFic, , unColega.
Cuando no se indica el nmero de registro, tanto en Get como en Put, Visual Basic usa el registro actual.
Cada vez que se accede a un registro determinado, el Basic lo "marca" como registro actual, de esta
forma sabe cual debe ser el siguiente registro al que debe acceder si no se le indica ninguno.
Si hacemos esto: Get #nFic, 15, unColega, al hacer esto otro: Put #nFic, , unColega, se estar
guardando en el nmero 16.
Es decir, el VB mantiene un "puntero" al siguiente registro. El bucle anterior podra haber quedado as:
For i = 1 To numRegistros
Get #nFic, , unColega
'Mostrar el contenido del registro
'...
Next
De todas formas, siempre suelo especificar el nmero de registro al que quiero acceder, as me parece
que estoy ms seguro de dnde se leer o escribir el registro.
Uno de los problemas que tiene este tipo de ficheros es que estamos "atados" a la longitud del registro.
Que ocurre si nos d el "punto" de quitar, aadir o cambiar la longitud de alguno de los campos?
Pues que lo tenemos ms bien chungo... estaremos metidos en un pequeo lio...
Una vez que hemos definido el tamao del registro, y tenemos datos en el fichero, cualquier cambio que
hagamos, dar como resultado algo no esperado...
Pero, todo tiene arreglo... aunque en este caso, nos lo tendremos que "currar" nosotros. Tendremos que
fabricarnos alguna rutina que se encargue de esta conversin.
Y ese podra ser el ejercicio de esta entrega:
Realizar una pequea utilidad que convierta un fichero de acceso aleatorio con registros de una longitud
conocida, en otro con registros de otra longitud o con campos de longitud diferente al original.
Y digo "longitud conocida", porque si no sabemos la longitud de cada registro, incluso de cada campo de
ese registro, poco podremos hacer...
Un detalle importante es que para acceder a los ficheros abiertos como "random", slo podemos hacerlo
con variables de longitud fija, ya sean tipos definidos o cadenas.
Se podra pensar que haciendo esto:
Dim unaCadena As String
'Asignamos 83 espacios a esta cadena
unaCadena = Space$(83)
nFic = FreeFile
Open "colegas.dat" For Random As nFic Len = Len(unaCadena)
'...
Get #nFic, 1, unaCadena
Pues no!
Ya que la variable unaCadena no tiene longitud fija y el Visual Basic necesita que lo sea.
Otra cosa es que hagamos esto otro:
'Esta cadena siempre tendr este nmero de caracteres
Dim unaCadena As String * 83
nFic = FreeFile
Open "colegas.dat" For Random As nFic Len = Len(unaCadena)
'...
Get #nFic, 1, unaCadena
Ahora si que funcionara bien la cosa, ya que el VB tiene la informacin que necesita...
La verdad es que hecho de menos una instruccin que tena el Basic del MS-DOS y era que podas
definir una serie de variables para acceder a los registros, incluso podas declarar una array... y cada uno

de los elementos del array con la longitud de cada uno de los campos... Pero eso ya no est, as que...
hay que usar los tipos definidos que al fin y al cabo es la mejor opcin para este tipo de ficheros.
Para el ejercicio, se supone que tenemos un fichero con registros declarados de esta forma:
Private Type t_Colega
Nombre As String * 30
Edad
As Integer
email As String * 50
End Type
Y lo queremos convertir en registros que tengan esta otra:
Private Type t_Colega
Nombre As String * 30
Edad
As Integer
email As String * 50
URL
As String * 128
End Type
Por supesto, queremos que los registros que haya sigan conservando los datos que tuviesen... sino,
que clase de rutina conversora sera?
Acuerdate de lo que digo en muchas ocasiones, no pienses en complicarte la vida, siempre procura ir a
lo simple, ya que en la mayora de las ocasiones ese es el camino correcto...
Cuando veamos la siguiente entrega, o al menos cuando veamos los ficheros de acceso binario, (mi
intencin es que sea en la prxima entrega, pero ya sabes...), crearemos otra utilidad de conversin ms
flexible que esta, es decir, una rutina que convierta un fichero a un formato que pueda ser definido por el
usuario en tiempo de ejecucin.
Aunque no sea lo habitual, y normalmente una entrega termina cuando te pongo los ejercicios, vamos a
ver un ejemplo completo para introducir y mostrar datos en un fichero de acceso aleatorio.
Cmo?
Que quieres hacerlo t?
Pues vale, me parece estupendo...
Desde luego, es que tengo unos alumnos que no me merezco... 8-)
No te quejes... y no digas que t no has dicho nada... yo he oido voces que me decan: queremos
hacerlo nosotros!
Y eso es lo que hay...
Para esta aplicacin vamos a usar tres cajas de texto en los que introduciremos los valores a guardar en
cada campo, con sus correspondientes labels para indicarnos los nombres de esos campos.
Existir otro label/textbox para indicarnos el nmero del registro actual, es decir en el que se
almacenarn los datos o del que se leern esos datos.
Un par de botones para Guardar y Leer...
Te resulta familiar?
Pues as es... algo parecido a lo que ya vimos en la entrega nmero once cuando se usaron arrays de
tipos definidos...
El aspecto del "programilla" sera algo as:

No he aadido nada para mostrar todos los registros... pero ya tendremos tiempo de hacerlo.
Bueno, pues hasta aqu hemos llegado...
Las soluciones de la entrega 18 estn en este link.

Y a pesar de parecer un poco pesado, realmente me gustara recibir tu opinin sobre esta entrega.

Curso Bsico de Programacin


en Visual Basic
Soluciones de la entrega Dieciocho.
Fecha: 26/Abr/98

Vamos a ver las soluciones a los ejercicios de la entrega dieciocho:


El primero era crear una utilidad para convertir un fichero de un tipo a otro. Una solucin sera esta:
Private Type t_Colega
Nombre As String * 30
Edad As Integer
email As String * 50
End Type
Private Type t_Colega2
Nombre As String * 30
Edad As Integer
email As String * 50
URL As String * 128
End Type
Private
Dim
Dim
Dim
Dim

Sub cmdConvertir_Click()
unColega As t_Colega, unColega2 As t_Colega2
nFic As Long, nFic2 As Long
numColegas As Long
i As Long

'abrir el fichero original


nFic = FreeFile
Open "colegas.dat" For Random As nFic Len = Len(unColega)

'abrir el fichero de destino


nFic2 = FreeFile
Open "colegas2.dat" For Random As nFic2 Len = Len(unColega2)
numColegas = LOF(nFic) \ Len(unColega)
For i = 1 To numColegas
'leer el registro
Get #nFic, i, unColega
'Asignar los nombres del nuevo tipo
With unColega
unColega2.Nombre = .Nombre
unColega2.Edad = .Edad
unColega2.email = .email
unColega2.URL = ""
End With
'Guardar el nuevo registro
Put #nFic2, i, unColega2
Next
Close nFic2
Close nFic
'Si quieres eliminar el fichero anterior y cambiarle el nombre
'hazlo despus de cerrar los ficheros
End Sub
Este es el listado completo del segundo ejercicio:
'-----------------------------------------------------------------'Ejercicio de la entrega 18
(26/Abr/98)
'
'Guillermo 'guille' Som, 1998
'-----------------------------------------------------------------Option Explicit
'Tipo para usar en el fichero
Private Type t_Colega
Nombre As String * 30
Edad As Integer
email As String * 50
End Type
'Esta variable se usar para acceder a los datos
Dim m_unColega As t_Colega
'Nmero de registros del fichero
Dim m_numColegas As Long
'Nmero del colega actual, usado cuando se edita, etc.
Dim m_elColega As Long
'Esta variable guardar el fichero a usar
Dim m_sFicColegas As String
'Esta se usar como FLAG para saber si hemos cambiado
'el registro actual
Dim m_Modificado As Boolean
Private Sub cmdGuardar_Click()
Dim nFic As Long
'Slo si el nmero del colega es el indicado en Text4
'de esta forma slo se guardar cuando se pulse en
'Nuevo o en Leer
If m_elColega = Val(Text4) Then

nFic = FreeFile
Open m_sFicColegas For Random As nFic Len = Len(m_unColega)
With m_unColega
.Nombre = Text1
.Edad = Val(Text2)
.email = Text3
End With
'Guardar los datos en el disco
Put #nFic, m_elColega, m_unColega
Close nFic
'Ajustar el nmero de colegas
m_numColegas = CuantosColegas()
m_Modificado = False
'Posicionar el cursor en el nmero de registro
Text4.SetFocus
End If
End Sub
Private Sub cmdLeer_Click()
Dim nFic As Long
'No se comprueba si se ha modificado el registro actual
'esto habra que tenerlo en cuenta... lo he dejado preparado
'con la variable m_Modificado
'Te dejo que hagas las comparaciones pertinentes...
'...
'Slo leer si no se est aadiendo uno nuevo
If m_elColega <= m_numColegas Then
m_elColega = Val(Text4)
'Pero que no se lea un valor "no vlido"
If m_elColega > 0 And m_elColega <= m_numColegas Then
nFic = FreeFile
Open m_sFicColegas For Random As nFic Len = Len(m_unColega)
'leer ese registro
Get #nFic, m_elColega, m_unColega
'quitarle los espacios "extras", ya que al ser
'de longitud fija, los espacios en blanco tambin
'se mostrarn en la caja de texto
'Para comprobarlo, quita el Trim$ y vers lo que
'ocurre cuando el nombre tiene menos caracteres...
With m_unColega
Text1 = Trim$(.Nombre)
Text2 = .Edad
Text3 = Trim$(.email)
End With
Close nFic
m_Modificado = False
Text1.SetFocus
Else

'si el nmero no es vlido...


Text4.SetFocus
m_elColega = 0
End If
End If

End Sub
Private Sub cmdNuevo_Click()
'Comprobar si se ha modificado?
'...
'Aadir un nuevo colega,
'slo si no se est introduciendo uno nuevo
If m_elColega <> m_numColegas + 1 Then
m_elColega = m_numColegas + 1
Text4 = m_elColega
'Limpiar el contenido de las cajas de texto
Text1 = ""
Text2 = ""
Text3 = ""
'Limpiar tambin la variable el registro actual,
'aunque realmente no es necesario...
With m_unColega
.Nombre = ""
.Edad = 0
.email = ""
End With
m_Modificado = False
'Posicionar el cursor en el campo del nombre
Text1.SetFocus
End If
End Sub
Private Sub Form_Load()
'asignamos el path del fichero de colegas:
m_sFicColegas = App.Path & "\Colegas.dat"
'Esta asignacin fallar si el path es el directorio raiz
'por tanto se debera comprobar de esta forma:
If Right$(App.Path, 1) = "\" Then
m_sFicColegas = App.Path & "Colegas.dat"
Else
m_sFicColegas = App.Path & "\Colegas.dat"
End If
'Tambin de esta otra forma... algo menos "clara"
m_sFicColegas = App.Path & _
IIf(Right$(App.Path, 1) = "\", "", "\") & _
"Colegas.dat"
'Inicialmente leer el nmero de registros
'lo pongo en una funcin para usarlo cuando se necesite,
'sin tener que repetir el proceso, aunque corto, pero...
m_numColegas = CuantosColegas()
'Borrar
Text1 =
Text2 =
Text3 =
Text4 =

el contenido de los TextBox


""
""
""
""

'Para empezar no se ha modificado


m_Modificado = False
End Sub
Private Function CuantosColegas() As Long
'Esta funcin se encarga de informarnos del nmero de registros

'que tiene el fichero


'Usarlo slo cuando queremos saber esta informacin y
'no necesitamos mantener el fichero abierto
'si no existe el fichero, se producir un error
On Local Error Resume Next
CuantosColegas = FileLen(m_sFicColegas) \ Len(m_unColega)
If Err Then
CuantosColegas = 0
End If
Label1(4) = "Nmero de colegas:" & CuantosColegas
Err = 0
End Function
Private Sub Form_Unload(Cancel As Integer)
'Por si se qued o estaba el fichero abierto...
Close
Set Form1 = Nothing
End Sub
Private Sub Text1_Change()
'Si en lugar de usar tres TextBox distintos se usara un array
'sera ms cmodo, ya que slo se pondr esta asignacin
'en un slo evento Change.
'
m_Modificado = True
End Sub
Private Sub Text2_Change()
m_Modificado = True
End Sub
Private Sub Text3_Change()
m_Modificado = True
End Sub
A ver si la prxima entrega no se hace de rogar demasiado, que ya estamos casi a punto de acabar con
esto del acceso a los ficheros

Curso Bsico de Programacin


en Visual Basic
Entrega Diecinueve: 24/Jun/98
por Guillermo "guille" Som
Si quieres linkar con otras entregas, desde el ndice lo puedes hacer

S que va a sonar a excusa barata y esas cosas, pero si te dijera que el "manuscrito" lo tengo terminado
desde el 26 de mayo...
Ahora ya no es por aquello del porttil, an no lo tengo, parece ser que no hay "almas" tan bondadosas
por esos mundos de Internet... pero bueno...
Estaba pensando yo que lo mismo con un programilla de esos a los que les hablas y escriben de forma
automtica... la verdad es que he estado probando con el SDK que tiene Microsoft, pero ese no me

termina de valer, salvo que las entregas las escriba en yankinglish... pero no es plan... en fin, tendr que
seguir buscando las teclas y despus de pulsar una tecla mirar para el papel...
Bueno, menos rollo, a ver si soy capaz de terminarlo pronto, para irme a ponerme como un salmonete,
que hoy es da de playa, adems de que es fiesta local y esas cosas pa que los catetillos podamos ir a
darnos un remojn a la playa, con una buena torta de San Juan...
Me acuerdo yo que antes... vale, vale!, no hace falta que grites..., lo dejo, pero que sepas que te pierdes
lo que iba a decir...

Para terminar con los tipos de acceso a ficheros, vamos a ver la forma ms potente y a la vez la ms
complicada... o casi.
Con el acceso binario podemos acceder a cualquier punto del fichero y, lo ms importante, leer o guardar
la cantidad de caracteres que queramos.
Antes de entrar en detalles, veamos cmo indicarle al VB que vamos a usar este tipo de acceso.
Como siempre, esto se har al abrir el fichero:
Open Nombre_Fichero For Binary As Numero_Fichero
Cuando abrimos un fichero en modo binario, al igual que suceda en el modo aleatorio (random), se tiene
acceso tanto de lectura como de escritura. Tambin se usan las instrucciones GET y PUT para leer o
escribir la informacin, pero a diferencia del acceso aleatorio, no estamos obligados a usar una variable
de longitud fija, (adems de longitud previamente especificada a la hora de abrir el fichero), si esto fuese
as, no habra diferencia con el acceso aleatorio... as que esta entrega casi ni existira...
Cmo leemos datos de un fichero de acceso binario?
Ya te he comentado que se usa GET para leer datos, la cuestin est en cmo indicarle al Visual Basic la
cantidad de caracteres a leer...
Pues hagamos la pregunta: Cmo le idicamos al VB la cantidad de caracteres a leer?
Vamos a verlo con un ejemplo:
A$ = Space$(10)
Get nFic, , A$
Esto leer 10 caracteres.
Osea, se leern tantos caracteres como "capacidad" tenga la variable usada. Si slo quisieramos leer
slo un caracter, esta variable tendra una longitud de un caracter... (algunas veces alucino con mi lgica
tan contundente, en fin...)
La ventaja es obvia: no es necesario estar atados a un nmero fijo de caracteres, simplemente
asignndole una cantidad de caracteres a la variable usada, es suficiente.
El problema puede surgir a la hora de determinar la posicin desde la que leeremos esos caracteres.
Ves, nada es perfecto, y si no controlamos el tema, pues, tendremos algn que otro quebradero de
cabeza.
La posicin tendremos que indicarla nosotros mismos, aunque tambin podemos dejar que sea el propio
Visual el que se encargue de este tema, todo depender de lo que queramos hacer.
Ya vimos en el acceso aleatorio que el clculo de la posicin de cada registro podiamos dejarlo de forma
automtica, es decir que sea el propio VB el que "decida" la posicin. Realmente el VB no decide nada,
ya que es una caracterstica de GET y PUT, si no se le indica la posicin, usa la "predeterminada" y esa
posicin se ajusta automticamente cada vez que se lee o escribe informacin, el clculo se hace
tomando la ltima posicin y aadindole la longitud del dato. En el caso de los ficheros aleatorios esa
posicin es "ficticia" (o relativa), ya que el VB convierte la posicin real dentro del fichero en nmero de
registros... Pero ahora no estamos con el acceso aleatorio, sino con el binario y con este tipo de acceso,
trabajamos con posiciones "reales", es decir que si hacemos esto:
Get nFic, 3, A$
Leeremos caracteres desde la posicin tres del fichero, el nmero de caracteres leidos estar indicado
por la longitud de la variable A$
Como ya coment antes, la ventaja es que no estamos obligados a leer un nmero determinado de
caracteres y el inconveniente es que hay que saber lo que estamos haciendo y se puede conbertir en un
inconveniente si no lo usamos de la forma adecuada.

Pero, vamos a demostrar esto que acabo de decir.


Crea un nuevo proyecto, asignale a la propiedad AutoRedraw del form el valor TRUE, de esta forma no
habr problemas a la hora de imprimir, (y ver lo impreso), en el formulario. Esto del Autoredraw es til
cuando nuestro form quede oculto por otra ventana, nunca perder lo que hayamos imprimido en l.
Aade un commandbutton y escribe el siguiente cdigo:
Private
Dim
Dim
Dim

Sub Command1_Click()
nFic As Integer
sFic As String
sCadena As String

'sCadena tiene 20 caracteres


sCadena = "Prueba de una cadena"
sFic = "binarios_19.dat"
nFic = FreeFile
Open sFic For Binary As nFic
Put nFic, , sCadena
Close nFic
'leer los datos guardados
nFic = FreeFile
Open sFic For Binary As nFic
Get nFic, , sCadena
Print sCadena
Close nFic
End Sub
Ejecuta la aplicacin (pulsando F5), pulsa en el Command1, y vers que todo funciona bien.
Ahora aade lo siguiente antes del Get nFic, , sCadena:
sCadena = Space$(5)
Y ejecuta de nuevo el programa.
Como vers slo se han leido los cinco primeros caracteres de lo que se guard anteriormente. Es decir
slo mostrar Prueb, porque la cadena usada para leer tiene esa cantidad de caracteres.
Este es un detalle que debers recordar, as que apntatelo.
La ventaja es que podemos guardar y leer distintos tipos de datos mezclados.
Por ejemplo, si sabemos que tenemos un tipo definido y despus una cadena de caracteres, podemos
mezclarlo. Pero es importante que a la hora de leer los datos, leamos la cantidad "justa" de caracteres, y
en el orden correcto.
Vamos a ver esto que acabo de decir.
Borra el cdigo anterior o crea un nuevo proyecto y aade un command y el siguiente cdigo:
'Esto en la parte General del form
Option Explicit
Private Type t_colega
Nombre As String * 30
Edad As Integer
End Type
Private
Dim
Dim
Dim
Dim

Sub Command1_Click()
nFic As Integer
sFic As String
sCadena As String
unColega As t_colega

unColega.Nombre = "Guille"
unColega.Edad = 40
'sCadena tiene 20 caracteres
sCadena = "Prueba de una cadena"
sFic = "binarios_19.dat"
nFic = FreeFile

Open sFic For Binary As nFic


Put nFic, , unColega
Put nFic, , sCadena
Close nFic
'leer los datos guardados
nFic = FreeFile
Open sFic For Binary As nFic
Get nFic, , unColega
Get nFic, , sCadena
'mostramos los datos leidos
Print unColega.Nombre, unColega.Edad
Print sCadena
Close nFic
End Sub
Si inviertes el orden de las variables a la hora de leer, pues causas un pequeo desastre, ya que no lees
lo que esperas leer. Osea que no uses esto del acceso binario "al voleo", sino pensndolo bien.
Entonces, cuando es conveniente usar el acceso binario?
Siempre que queramos acceder a un fichero del que estimemos que puede que no sea del tipo ASCII, es
decir un fichero que pueda contener cualquier clase de caracteres. Normalmente los ficheros ASCII, (o
los usados habitualmente para acceso secuencial), terminan cuando se encuentra un cdigo EOF
(caracter ASCII nmero 26) o cuando ya no hay ms caracteres en el fichero; sin embargo con el acceso
binario slo se "acaban" cuando no quedan ms caracteres que leer del fichero.
Por supuesto que si un fichero se ha guardado usando un tipo de acceso, puede abrirse usando otro tipo
de acceso, aunque estos casos no son recomendables, salvo que sepamos lo que hacemos...
Veamos un nuevo ejemplo. Ya sabes, borra el cdigo usado anteriormente o crea un nuevo proyecto.
Private
Dim
Dim
Dim

Sub Command1_Click()
nFic As Integer
sFic As String
sCadena As String

sFic = "binarios_19.dat"
nFic = FreeFile
Open sFic For Binary As nFic
Put nFic, , "Prueba de una cadena"
Put nFic, , vbCrLf
'Se guarda una segunda cadena
Put nFic, , "Segunda cadena"
Put nFic, , vbCrLf
Close nFic
'leer como secuencial
nFic = FreeFile
Open sFic For Input As nFic
Do While Not EOF(nFic)
Line Input #nFic, sCadena
Print sCadena
Loop
Close nFic
End Sub
Como habrs comprobado, se ha leido todo lo que haba en el fichero, incluso cosas que haba de
pruebas anteriores.
Ahora engaemos al VB y hagamos que piense que un fichero se ha acabado antes de que se acabe de
forma "real".
Sustituye el cdigo del Command1 por este otro:
Private
Dim
Dim
Dim
Dim

Sub Command1_Click()
nFic As Integer
sFic As String
sCadena As String
sEOF As String * 1

sEOF = Chr$(26)
sFic = "binarios_19.dat"
nFic = FreeFile
Open sFic For Binary As nFic
Put nFic, , "Prueba de una cadena"
Put nFic, , vbCrLf
'Aadimos un cdigo de fin de fichero
Put nFic, , sEOF
'Se guarda una segunda cadena
Put nFic, , "Segunda cadena"
Put nFic, , vbCrLf
Close nFic
'leer como secuencial
nFic = FreeFile
Open sFic For Input As nFic
Do While Not EOF(nFic)
Line Input #nFic, sCadena
Print sCadena
Loop
Close nFic
End Sub
Ahora slo se ha mostrado lo guardado antes del cdigo almacenado en la variable sEOF.
Pero el fichero contina teniendo lo que antes tena. Lo que ocurre es que cuando se abre un fichero
secuencial y el VB se encuentra con el cdigo 26, piensa que se debe haber terminado el fichero en
cuestin.
Ahora vamos a leerlo como binario... Por supuesto, sabiendo lo que se ha guardado y cmo se ha
guardado.

Private
Dim
Dim
Dim
Dim
Dim

Sub Command1_Click()
nFic As Integer
sFic As String
sCadena As String
sEOF As String * 1
sCRLF As String * 2

sEOF = Chr$(26)
sCRLF = vbCrLf
'sCadena tiene 20 caracteres
sCadena = "Prueba de una cadena"
sFic = "binarios_19.dat"
nFic = FreeFile
Open sFic For Binary As nFic
Put nFic, , sCadena
Put nFic, , sCRLF
Put nFic, , sEOF
'Se guarda una cadena de 15 caracteres
Put nFic, , "Segunda cadena"
Put nFic, , sCRLF
Close nFic
'leer los datos guardados
nFic = FreeFile
Open sFic For Binary As nFic
'Se leen slo 5 caracteres de los 20 guardados
sCadena = Space$(5)
Get nFic, , sCadena
Print sCadena
sCadena = Space$(15)
'Leemos los caracteres que quedaron pendientes,

'ya que sCadena slo ley 5 de los 20 caraceteres que tena


Get nFic, , sCadena
'tambin leemos los caracteres "extras" que se guardaron
Get nFic, , sCRLF
Get nFic, , sEOF
Print sCadena
Get nFic, , sCadena
Print sCadena
Close nFic
End Sub
Bien, ahora ya hemos conseguido leer todo, pero fjate en el detalle de que hemos tendo que leer los
cdigos "extras" que se guardaron, es decir el retorno de carro y el de fin de fichero. Si no lo hubieramos
hecho... pruebalo y lo compruebas...
Habrs observado una lnea de ms y un caracter extrao antes de "Segunda cade"... creo que no hace
falta que te explique el porqu... verdad?
Normalmente con el acceso binario podemos leer todos los caracteres que haya en un fichero. Se suele
usar cuando no sabemos la estructura de ese fichero y tenemos alguna forma de "interpretar" lo que
leemos, aunque esto ltimo no se aprende en ningn curso y no hay regla fija. En la mayora de las
ocasiones que uso el acceso binario, es cuando quiero leer informacin de un fichero para buscar algo
en concreto. Ese fichero puede ser un ejecutable, una DLL o cualquier otro tipo de fichero. Si de
antemano se que es un fichero secuencial, seguramente no lo leera como binario, ya que el tiempo de
acceso y lectura de un fichero secuencial es menor que uno abierto como binario. Osea que se lee antes
uno abierto con For Input que con For Binary.
Esta diferencia en el tiempo de acceso es apreciable sobre todo cuando se manejan muchos ficheros...
Hablando de leer todo el contenido de un fichero, ya sabes que existe un funcin llamada Input$, a la que
se le indica el nmero del fichero abierto y la cantidad de caracteres que queremos leer y nos lo devuelve
para que podamos asignarlo a una variable de cadena. El fichero que hemos creado con el ltimo
ejemplo no es realmente un fichero ASCII, ya que contiene caracteres binarios, es decir, caracteres que
no estn en el rago ASCII del 32 al 255 (en algunos casos hasta el cdigo 127).
Veamos la reaccin del VB ante un caso "no deseado", es decir leer lo que no debemos leer:
'Se supone que has probado los ejemplos anteriores y que existe el fichero
indicado
Private Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim sCadena As String
sFic = "binarios_19.dat"
nFic = FreeFile
'
Open sFic For Input As nFic
sCadena = Input$(LOF(nFic), nFic)
Close nFic
Print sCadena
End Sub
Aqu lo que se pretenda era leer el fichero de una vez. Pero como se ha abierto el fichero como
secuencial, el VB ha detectado que se la leido un cdigo de fin de fichero, precisamente antes de que se
acbe el fichero y nos avisa con un magnfico mensaje de error.
Esto se soluciona, bien abriendo el fichero secuencial, pero usando EOF(nFic) para comprobar si hemos
alcanzado el final del fichero o bien abriendo el fichero en modo binario y usando la funcin Input$.
Private
Dim
Dim
Dim

Sub Command1_Click()
nFic As Integer
sFic As String
sCadena As String

sFic = "binarios_19.dat"
nFic = FreeFile
'

Open sFic For Binary As nFic


sCadena = Input$(LOF(nFic), nFic)
Close nFic
Print sCadena
End Sub
Ahora puedes observar que se lee TODO lo que hay en el fichero, ya que al abrirlo en modo binario, no
se tiene en cuenta ningn caracter especial y se lee hasta dnde se le indique.
Creo que es suficiente por hoy.
Hay ms cosas, en cuanto al acceso a los ficheros, pero no vamos a alargar esta entrega, que puede ser
que te empaches con tantas cosas y no es bueno.

Los ejercicios
Recuerdas uno de los ejercicios de la entrega 18?
Consista en cambiar el formato de un fichero de acceso aleatorio en otro con los campos en otro formato
(longitud de los campos). Pues bien, con el acceso aleatorio slo era posible si conociamos de antemano
el tamao del registro nuevo (y, por supuesto, la longitud de cada campo). Ahora con lo que sabes del
acceso binario y unas cuantas miles de lneas de cdigo, podrs hacerlo para convertir cualquier fichero
a un nuevo formato y as poder usarlo de forma genrica.
Es decir, tenemos un fichero con una serie de campos y queremos cambiar la estructura de ese fichero y,
por supuesto, traspasar la informacin existente al nuevo formato. El usuario de esta utilidad, tendr que
saber la estructura del fichero de origen y tambin saber la nueva estructura a la que quiere convertir el
susodicho fichero de datos.
Para no complicar demasiado la cosa, vamos a usar slo 10 campos, pero se podran permitir ms...
El aspecto del form en tiempo de diseo sera el siguiente:
No te preocupes por los "campos" que faltan en el destino, enseguida te explico cmo hacer que
aparezcan, al menos a la hora de ejecutar el programa.
Esto te servir para otras veces en las que necesites crear controles en tiempo de ejecucin y
posicionarlos adecuadamente, o casi...
Veamos el aspecto del form y despus veremos el cdigo usado para "crear" esos controles:

El cdigo:
Private Sub Form_Load()
Dim i As Integer
'Crear los controles de destino
'(empezamos por UNO porque el control CERO ya est creado)
For i = 1 To 9
'Cargarlos en memoria
Load lblDest(i)
Load txtDestTam(i)
'Asignarles la posicin y hacerlos visible
With txtDestTam(i)
.Visible = True
.Top = txtDestTam(i - 1).Top + .Height + 45
lblDest(i).Top = .Top - 15
lblDest(i).Visible = True
lblDest(i) = "Campo " & i + 1 & ":"
End With
Next
'Borrar el contenido de los TextBoxes
For i = 0 To 9
txtTam(i).Text = ""
txtDestTam(i).Text = ""
Next
End Sub
La cuestin est en que al pulsar en el botn de convertir el fichero, antes se hayan asignado los valores
correspondientes.
La informacin que hay que pasarle a la aplicacin de cada campo, es la siguiente: tamao de cada
campo.
Lo que hay que saber es el tamao de los nmeros al guardarlo en disco, para ello echale un vistazo a la
ayuda del VB y te dir lo que ocupa cada tipo, aunque creo que en alguna de las primeras entragas ya lo
vimos.
Para muestra, un botn: Los Integers ocupan dos bytes, los Longs cuatro bytes, etc.
La cuestin es que se asignen los valores de forma correcta, sino, la cosa puede no funcionar.
Y con esto y un bizcocho... hasta otra entrega, que no creo que sea maana a las ocho...
Este es el link a la solucin de esta entrega, recuerda no hacer trampas e intentarlo primero.
(De todas formas, el link no te llevar a ningn sitio, ya que an no la he puesto... je, je...)
Nota 25/Jun/98: Ya est operativo el link de la solucin al ejercicio.

Y continuando con la sana costumbre de recibir tus preciados, y la mayora de las veces aduladores,
comentarios, cosa que agradezco y que dicho sea de paso, es la nica razn por la que sigo con el curso
bsico... pues eso, aqui te dejo el link para que me escribas lo que te ha parecido esta entrega

Curso Bsico de Programacin


en Visual Basic
Soluciones de la entrega Diecinueve.
Fecha: 25/Jun/98

Ahora s que est la solucin de la entrega 19, la verdad es que si no lo has conseguido, no debes
preocuparte demasiado, no era tan "simple" como podra parecer, ya que se necesita de un poco de
"tablas" y manejo en esto de la programacin, as que si ests dispuesto a ser sincero, por favor enviame
un mensaje diciendo si lo conseguiste o no, esto me ayudar a saber si tengo que poner cosas ms
sencillas o dedicarme a ensear otras cosillas, no s..., por ejemplo porqu cuando todo est oscuro no
se ve nada... je.
Para volver a la entrega 19, pulsa en este link.
Este es el listado completo de la solucin que YO he encontrado al ejercicio, por supuesto no tiene
porqu ser igual a la tuya, si quieres puedes mandarme una copia del resultado que has encontrado... no
te garantizo nada, pero lo mismo hasta te comento sobre l... Venga, nimo! que lo difcil an no ha
empezado... ;-)
Esta es una foto del programa en ejecucin y el listado del mismo:

'-----------------------------------------------------------------'Ejercicio para la entrega 19


(24/Jun/98)
'(solucin)
'
'Guillermo 'guille' Som, 1998
'-----------------------------------------------------------------Option Explicit
Private Sub Form_Load()
Dim i As Integer
'Para probar uso el fichero de colegas.dat
'el tamao de cada campo era: 30, 2, 50
'Private Type t_Colega
'
Nombre As String * 30
'
Edad As Integer
'
email As String * 50
'End Type
'
txtOrigen = "colegas.dat"
'Crear los controles de destino

'(empezamos por UNO porque el control CERO ya est creado)


For i = 1 To 9
'Cargarlos en memoria
Load lblDest(i)
Load txtDestTam(i)
'Asignarles la posicin y hacerlos visible
With txtDestTam(i)
.Visible = True
.Top = txtDestTam(i - 1).Top + .Height + 45
lblDest(i).Top = .Top - 15
lblDest(i).Visible = True
lblDest(i) = "Campo " & i + 1 & ":"
'Ajustar el TabIndex,
'(se supone que ya estaban por orden)
lblDest(i).TabIndex = txtDestTam(i - 1).TabIndex + 1
.TabIndex = lblDest(i).TabIndex + 1
End With
Next
'Borrar el contenido de los TextBoxes
For i = 0 To 9
txtTam(i).Text = ""
txtDestTam(i).Text = ""
Next
End Sub
Private Sub cmdConvertir_Click()
'Variables para los nombres y nmeros de ficheros
Dim nFic As Long, nFic2 As Long
Dim sFic As String, sFic2 As String
'Estos arrays controlarn los tamaos de cada campo
Dim aOrigen() As Long
Dim aDestino() As Long
'Nmero de campos en cada fichero
Dim nOrigen As Integer
Dim nDestino As Integer
'Tamaos de los registros
Dim tOrigen As Integer
Dim tDestino As Integer
'Las cadenas que contendrn los datos
Dim sOrigen As String
Dim sDestino As String
'Nmero de registros del fichero de origen
Dim numReg As Integer
Dim tamFic As Long
'Para usos generales
Dim i As Long, j As Long
Dim posReg As Long
Dim sTmp As String
'Antes de hacer nada, comprobamos que exista el fichero
'de origen
sFic = Trim$(txtOrigen)
If Len(Dir$(sFic)) = 0 Then
MsgBox "ATENCIN! No existe el fichero de origen."
txtOrigen.SetFocus
Exit Sub
End If
'Asignamos el nombre del fichero de destino
sFic2 = Trim$(txtDestino)
'Se asignarn los tamaos de cada registro, se dejar
'de comprobar cuando el contenido del textbox sea cero.
'Si se usara un TextBox con el nmero de campos, la cosa
'sera ms fcil de controlar, pero...

'
'Empezamos por el origen
For i = 0 To 9
If Val(txtTam(i)) = 0 Then
'ya no hay nada ms que comprobar
Exit For
Else
nOrigen = nOrigen + 1
ReDim Preserve aOrigen(nOrigen)
'asignamos el tamao del campo nOrigen
aOrigen(nOrigen) = Val(txtTam(i))
'ajustamos el tamao total del registro
tOrigen = tOrigen + aOrigen(nOrigen)
End If
Next
'Ahora comprobamos el destino
For i = 0 To 9
If Val(txtDestTam(i)) = 0 Then
'ya no hay nada ms que comprobar
Exit For
Else
nDestino = nDestino + 1
ReDim Preserve aDestino(nDestino)
'asignamos el tamao del campo nDestino
aDestino(nDestino) = Val(txtDestTam(i))
'ajustamos el tamao total del registro
tDestino = tDestino + aDestino(nDestino)
End If
Next
'
'Ya tenemos la informacin suficiente,
'
'Por si da error al acceder a los ficheros
On Local Error GoTo ErrorConvertir

'Abrimos los ficheros en modo binario


nFic = FreeFile
Open sFic For Binary As nFic
'Averiguar el nmero de registros de este fichero
tamFic = LOF(nFic)
numReg = tamFic \ tOrigen
'Comprobar que el tamao especificado concuerda con el fichero
'Si el nmero de registros multiplicado por el tamao de cada
'registro es diferente al tamao del fichero...
If numReg * tOrigen <> tamFic Then
MsgBox "Los tamaos especificados en los campos de origen" & vbCrLf &

"no concuerdan con el tamao del fichero.", vbCritical,


"Convertir ficheros"
Close
txtTam(0).SetFocus
Exit Sub
End If
'Abrimos el fichero de destino
nFic2 = FreeFile
Open sFic2 For Binary As nFic2
'
'Preparamos la cadena que contendr los datos de origen
'esta no cambiar de tamao
sOrigen = Space$(tOrigen)
'Hacemos un bucle para todos los registros de origen
For j = 1 To numReg
Get nFic, , sOrigen
'La cadena de destino se formar con el tamao de
'los campos de origen ms el tamao de los nuevos campos,
'si el nmero de campos de destino es diferente,
'simplemente se rellenar la cadena con espacios

sDestino = ""
'
'Esta variable contendr la posicin dentro del registro
'del campo que se est procesando
posReg = 1
For i = 1 To nOrigen
'Tomamos el contenido del campo actual
sTmp = Mid$(sOrigen, posReg, aOrigen(i))
'Asignamos este campo y lo rellenamos de espacios
sTmp = Left$(sTmp & Space$(aDestino(i)), aDestino(i))
sDestino = sDestino & sTmp
'ajustamos el tamao de la posicin dentro del registro
'de origen
posReg = posReg + aOrigen(i)
Next
'Ahora hay que rellenar la cadena de destino con espacios
'suficientes hasta completar el nmero de caracteres
'que se han especificado.
'
'El TRUCO est en aadirle a la cadena de destino la
'cantidad de caracteres totales y slo quedarnos
'con esa cantidad, de esta forma nos aseguramos que
'tendremos la cantidad que necesitamos tener...
'
sDestino = Left$(sDestino & Space$(tDestino), tDestino)
'Lo guardamos
Put nFic2, , sDestino

Next
'Se acab de convertir, cerramos los ficheros
Close
'Guardamos la informacin de los formatos usados:
'
'Uso un formato standard INI para que se pueda leer de forma
'fcil, incluso usando el ejemplo de la entrega 20
'
nFic = FreeFile
Open "Convertir.ini" For Output As nFic
'Datos de origen:
Print #nFic, "[Datos de Origen]"
Print #nFic, "Fichero=" & sFic
Print #nFic, "Nmero de campos=" & nOrigen
For i = 1 To nOrigen
Print #nFic, "Tamao Campo" & CStr(i) & "=" & aOrigen(i)
Next
Print #nFic, ""
'Datos de destino:
Print #nFic, "[Datos de Destino]"
Print #nFic, "Fichero=" & sFic2
Print #nFic, "Nmero de campos=" & nDestino
For i = 1 To nDestino
Print #nFic, "Tamao Campo" & CStr(i) & "=" & aDestino(i)
Next
Close
'Avisamos de que todo acab bien
MsgBox "Se ha convertido el fichero de forma satisfactoria," & vbCrLf & _
"La informacin de los datos convertidos est en: Convertir.ini", _
vbInformation, "Convertir ficheros."
SalirConvertir:
Close
Exit Sub
ErrorConvertir:
MsgBox "Se ha producido el siguiente error:" & vbCrLf & _
Err.Number & " " & Err.Description, vbCritical, "Convertir ficheros"
Resume SalirConvertir
End Sub
El contenido del fichero "Convertir.ini" de la prueba que he hecho, sera el siguiente:

[Datos de Origen]
Fichero=colegas.dat
Nmero de campos=3
Tamao Campo1=30
Tamao Campo2=2
Tamao Campo3=50
[Datos de Destino]
Fichero=colegas2.dat
Nmero de campos=4
Tamao Campo1=40
Tamao Campo2=2
Tamao Campo3=50
Tamao Campo4=128

Curso Bsico de Programacin


en Visual Basic
Entrega Veinte: 24/Jun/98
por Guillermo "guille" Som
Si quieres linkar con otras entregas, desde el ndice lo puedes hacer

Para compensar un poco el que hayan pasado casi dos meses entre la entrega 18 y la 19, te doy esta
del tirn... no es por nada, es que ya la tena lista y realmente tena que ir junto con la diecinueve, lo que
pasa es que no quise que la entrega anterior fuese demasiado larga y as te lo tomas con ms ganas...
espero.

Ya hemos visto las distintas formas de acceder a los ficheros, ahora vamos a ver una instruccin que
puede sernos til cuando decidamos "movernos" dentro del fichero.
Me explico: cuando se trat el acceso secuencial, coment que la informacin haba que leerla de forma
secuencial, es decir un dato despus de otro, bueno, pues esto es cierto slo a medias. No empieces a
pegar saltos de alegra, porque tampoco es para tanto. El tema est en que si lees la informacin de
forma "seguida", entonces si que es as, pero, si te entra hipo, puedes acceder a cualquier parte del
fichero. Cmo? Pues con la siguiente instruccin que te voy a presentar ahora...
A ver, instruccin ven, que te voy a presentar... venga, no te de vergenza, estamos en confianza... (es
que dice que no le gusta su nombre), aqu est...
oras, ores, damas y caballeros, les presento a: SEEK
Esta instruccin (que tambin es una funcin) se usa, en modo instruccin, para posicionarnos en
cualquier parte del fichero abierto, tanto para leer como para escribir.
Si se usa como funcin, nos devuelve la posicin actual, es decir en la que nos encontramos, del fichero.
Veamos cmo usarla:
Seek #numFic, posicin y tambin variable = Seek(#numFic)
El valor devuelto es de tipo Long.
Dependiendo del modo en el que est abierto el fichero habr que "interpretar" el valor de distinta forma:
Para los ficheros de tipo secuencial y binario, nos da la posicin en bytes (o caracteres).
Para los ficheros abiertos como aleatorios (random), nos da la posicin en nmero de registros.

Cuando lo usamos en modo instruccin, lo que hace es posicionar el puntero dentro del fichero, de modo
que lo siguiente que se lea o se escriba se har en la posicin indicada. Ni que decir tiene que el valor de
la posicin debe ser un valor legal. Es decir, no podemos posicionarnos en la posicin CERO ni en una
posicin NEGATIVA, ya que no es "legal".
El uso de esta funcin/instruccin es til cuando necesitemos avanzar o retroceder dentro del fichero.
Y como el movimiento se demustra andando, vamos a ver un ejemplo.
Vamos a crear una pequea utilidad que leer datos de un fichero, buscando claves especiales.
Imaginate que quieres acceder a un fichero al estilo de los ficheros INI, en ese tipo de ficheros existen
una serie de secciones que estn "enmarcadas" entre corchetes y a continuacin vienen una serie de
datos (claves) con una especie de asignaciones que representan los valores de esas claves.
Veamos un ejemplo de un fichero de este tipo:
[elGuille]
nombre=guille
email=guille@costasol.net
La seccin se llama "elGuille" y los dos campos son "nombre" y "email"
Realmente para acceder a este tipo de ficheros no necesitaramos usar Seek, ya que podemos acceder
secuencialmente, pero vamos a ver cmo podemos "posicionarnos" en una seccin en concreto,
despus de haber leido el contenido y haber tomado "buena nota" de las posiciones.
La utilidad de ejemplo, nos va a mostrar todas las secciones disponibles y despus podremos acceder
rpidamente a una posicin en concreto.
Veamos el aspecto del formulario y el cdigo correspondiente:

'Esta fecha no est mal, es que ya lo tena "manuscrito" desde entonces...


'Ejemplos del curso bsico, ejemplo de Seek
(26/May/98)
'
Option Explicit
Private Type tSecciones
Nombre As String
Posicion As Long
End Type
Private aSecciones() As tSecciones
Private nSecciones As Integer
Private sFic As String
Private nFic As Integer
Private Sub Form_Load()
'deshabilitar el botn de leer contenidos
cmdLeerContenido.Enabled = False
Text1 = ""

List1.Clear
'Creamos el fichero de ejemplo
sFic = "basico_20.ini"
nFic = FreeFile
Open sFic For Output As nFic
Print #nFic, "[elProfe]"
Print #nFic, "Nombre=Guillermo"
Print #nFic, "email=guille@costasol.net"
Print #nFic, ""
Print #nFic, "[Alumnos]"
Print #nFic, "Cantidad=2"
Print #nFic, "Nombre_01=Pepito"
Print #nFic, "email_01=pepito@servidor.com"
Print #nFic, "Nombre_02=Juanita"
Print #nFic, "email_02=juani@servidora.net"
Print #nFic, ""
Print #nFic, "[Fecha]"
Print #nFic, "Fichero creado el da=26/May/1998"
Print #nFic, "Fichero actualizado el da=" & Format$(Now, "dd/mmm/yyyy")
Close
End Sub
Private Sub cmdLeerContenido_Click()
'Leemos el contenido de la seccin seleccionada en el list
Dim sCadena As String
Dim nItem As Long
nItem = List1.ListIndex
If nItem >= 0 Then
'borramos el contenido del Text1
Text1 = ""
nFic = FreeFile
Open sFic For Input As nFic
'posicionamos el fichero en el sitio que nos interesa
Seek nFic, aSecciones(nItem + 1).Posicion
'ahora leemos el contenido del fichero hasta encontrar [
'o hasta que se acabe el fichero
Do While Not EOF(nFic)
Line Input #nFic, sCadena
If Left$(sCadena, 1) = "[" Then
'nada ms que leer
Exit Do
Else
Text1 = Text1 & sCadena & vbCrLf
End If
Loop
Close nFic
End If
End Sub
Private Sub cmdLeerSecciones_Click()
Dim sCadena As String
Dim Posicion As Long
'Borramos el contenido del ListBox
List1.Clear
'Leemos las secciones disponibles
nFic = FreeFile
Open sFic For Input As nFic
Do While Not EOF(nFic)
Line Input #nFic, sCadena
'guardamos la posicin actual, justo despus de leer,

'de esta forma nos indicar la posicin a partir de la


'cual leeremos el contenido...
Posicion = Seek(nFic)
'Si es una seccin
If Left$(sCadena, 1) = "[" Then
'incrementamos el nmero de secciones
nSecciones = nSecciones + 1
'redimensionamos el array
ReDim Preserve aSecciones(nSecciones)
'asignamos los valores al array
With aSecciones(nSecciones)
.Nombre = sCadena
.Posicion = Posicion
End With
'aadimos esta seccin a la lista
List1.AddItem sCadena
End If

Loop
Close nFic

If nSecciones Then
'MsgBox "Se han hallado " & nSecciones & " secciones"
'seleccionamos el primer item del listbox
List1.ListIndex = 0
'habilitamos el botn
cmdLeerContenido.Enabled = True
Else
MsgBox "No hay secciones en el fichero: " & sFic
End If
End Sub
Private Sub List1_DblClick()
'Tambin podemos ver el contenido de una seccin
'haciendo doble-click
cmdLeerContenido_Click
End Sub
Te explico un poco cmo funciona todo esto. Ya que de lo que se trata no es slo de ver cdigo sino de
explicarlo, verdad?
En primer lugar declaramos las variables que se van a usar.
Una de estas variables es un tipo definido que contendr el nombre de la seccin y la posicin dentro del
fichero.
Creamos un array dinmico (es decir redimensionable) de este nuevo tipo de datos, en l guardaremos
cada una de las secciones halladas en el fichero procesado. Tambin dimensionamos una variable que
contendr el nmero de secciones halladas, aunque slo se usa mientras se lee la informacin del
fichero, por tanto no es necesario que est declarada en la parte general de las declaraciones del
formulario.
Recuerda que las variables declaradas en la parte general de un formulario, estn disponibles en todo el
formulario.
En el Form_Load, que es el punto de entrada de nuestra utilidad, adems de asignar el nombre del
fichero y guardar un contenido de ejemplo, borramos el contenido del Text1 y el List1, adems
deshabilitamos el botn de leer el contenido de una seccin, para que no se use hasta que no haya
datos.
Al pulsar en el botn que lee las secciones, primero borramos lo que hubiese antes en el array de
secciones y asignamos cero a la variable que contiene el nmero de secciones.
Despus de abrir el fichero, en modo secuencial, vamos leyendo lnea por lnea, en cuanto nos
encontramos con una lnea que empieza por corchete [, quiere decir que hemos encontrado una seccin,
por tanto, incrementamos la variable que lleva la cuenta de las secciones halladas, redimensionamos el
array usando Preserve para no perder la informacin antes almacenada, y asignamos la informacin del
nombre y la posicin que hemos obtenido con Seek.
Fjate que la lectura de la posicin se hace despus de haber leido la seccin del fichero, esto es as,

porque lo que necesitamos saber es la posicin que viene a continuacin de la seccin, ya que despus
de la seccin es cuando vienen las claves. (En ralidad, se asigna siempre despus de leer una lnea,
pero a nosotros slo nos interesa su valor cuando hemos encontrado una seccin).
Seguimos leyendo hasta encontrar el final del fichero.
Por qu se ha usado el acceso secuencial?
Por la sencilla razn de que este tipo de fichero suele ser de tipo ASCII, es decir que no contiene
caracteres "raros" y que normalmente se editan en programas del tipo NotePad. De hecho el Windows
tiene asociado al bloc de notas (Notepad) para abrir los ficheros que contengan la extensin INI.
Adems de que al no saberse la longitud de los datos que contiene, pero que si sabemos que cada lnea
termina con un retorno de carro (o cambio de lnea), es ms cmodo usar el Line Input # para leer toda la
lnea; el modo binario no nos sera de utilidad, salvo que leyesemos el fichero caracter por caracter, cosa
que ralentizara el proceso.
Para acceder a una seccin en concreto, cosa que ocurre al pulsar en el botn cmdLeerContenido,
simplemente abrimos el fichero, posicionamos el "puntero" en el sitio adecuado y leemos lo que haya en
el fichero hasta que encontremos otra seccin, (que empezar por un corchete), o hasta que lleguemos
al final del fichero.
Tambin he puesto cdigo para que al hacer doble-click en un elemento del List1, se lea el contenido de
la seccin correspondiente, para ello lo nico que se hace es llamar al evento Click del botn
cmdLeerContenido.

Y hasta aqu ha llegado esta entrega, (que realmente formaba parte de la entrega 19), ahora vamos a ver
un par de ejercicios para que te vayas soltando en esto de la programacin con el Visual Basic.
El primer ejercicio realmente no usa Seek pero si algo parecido a la utilidad esta de leer el contenido de
los ficheros del tipo INI, y consiste en crear un array con el contenido de todas las secciones y todas las
claves y valores de cada seccin. De forma que el fichero slo se lea una vez y cuando se quiera mostrar
el contenido de una seccin se use el contenido del array.
La verdad es que no es nada fcil, pero tampoco pienses que es tan complicado como para no poder
resolverlo, al menos deberas intentarlo y no coger el camino fcil de ver la solucin, entre otras cosas,
porque lo que se pretende con estos ejercicios es que cojas "soltura" en la programacin y si adems de
soltarte te quedas con las "buenas" costumbres, pues mejor.
A que buenas costumbres me refiero?
A usar Option Explicit en todos los mdulos, para de esta forma declarar las variables antes de usarlas y
a "indentar" el cdigo para que te sea ms fcil seguirlo...
Despus del sermn vamos a ver la pista que te doy:
La pista es que puedes usar estos tipos definidos para crear el array de claves y su contenido, y el array
para almacenar cada seccin y las claves de cada una de ellas.
'
Private Type tContenidos
Clave As String
Contenido As String
End Type
Private Type tSecciones
Nombre As String
NumClaves As Integer
Contenidos() As tContenidos
End Type
Private aSecciones() As tSecciones
Como sabes cada clave tiene este formato: Clave=Contenido. Esto te lo digo para que la clave vaya por
un lado y el contenido por otro, aunque sea algo ms complicado que almacenar simplemente la clave y
el contenido, a la larga te ayudar a manipular mejor las cadenas de caracteres y tambin le darn
mayor utilidad al cdigo que se cree con este ejercicio.
Como segundo ejercicio, haz lo mismo, pero en lugar de almacenar en el array cada clave y su
contenido, usa Seek para "recordar" la posicin de cada una de las claves de cada seccin para despus
poder acceder a esa parte del fichero para leer lo que nos interesa.

Este segundo ejercicio es un poco ms complicadillo, ya que necesitar usar de forma correcta Seek,
tanto en modo funcin como en modo instruccin.
Este es el tipo de datos que tendrs que usar:
'
Private Type tSecciones
Nombre As String
NumClaves As Integer
Contenidos() As Long
End Type
Private aSecciones() As tSecciones
Fjate que aqu slo guardamos en Contenidos la posicin de cada clave dentro del fichero.
Suerte y no desesperes si no lo consigues, no me gustara perder a todos mis alumnos de golpe... creo
que no lo soportara.
Las soluciones de los dos ejercicios estn en este link.

Y ya slo queda que hagas tu comentario sobre esta entrega


Soluciones de la entrega Veinte.
Fecha: 24/Jun/98

Estas son las soluciones de los ejercicios de la entrega veinte, si quieres ver el contenido de la susodicha
entrega, pulsa en este link y te llevar a la entrega 20.
El primero:
'
'Ejemplos del curso bsico, ejemplo de Seek
'
'Solucin a los ejercicios de la entrega 20
'
Option Explicit

(26/May/98)

Private Type tContenidos


Clave As String
Contenido As String
End Type
Private Type tSecciones
Nombre As String
NumClaves As Integer
Contenidos() As tContenidos
End Type
Private aSecciones() As tSecciones
Private nSecciones As Integer
Private sFic As String
Private Sub cmdLeerContenido_Click()
'Leemos el contenido de la seccin seleccionada en el list
Dim sCadena As String
Dim nItem As Long
Dim i As Integer
nItem = List1.ListIndex
If nItem >= 0 Then

'borramos el contenido del Text1


Text1 = ""
With aSecciones(nItem + 1)
For i = 1 To .NumClaves
sCadena = .Contenidos(i).Clave & "=" &
.Contenidos(i).Contenido
Text1 = Text1 & sCadena & vbCrLf
Next
End With
End If
End Sub
Private
Dim
Dim
Dim
Dim
Dim

Sub cmdLeerSecciones_Click()
nFic As Integer
sCadena As String
Posicion As Long
nClaves As Integer
i As Integer

'Borramos el contenido del ListBox


List1.Clear
'Leemos las secciones disponibles
nFic = FreeFile
Open sFic For Input As nFic
Do While Not EOF(nFic)
Line Input #nFic, sCadena
'Si es una seccin
If Left$(sCadena, 1) = "[" Then
nClaves = 0
'incrementamos el nmero de secciones
nSecciones = nSecciones + 1
'redimensionamos el array
ReDim Preserve aSecciones(nSecciones)
'asignamos los valores al array
aSecciones(nSecciones).Nombre = sCadena
'aadimos esta seccin a la lista
List1.AddItem sCadena
'ahora leemos el contenido del fichero hasta encontrar [
Do While Not EOF(nFic)
Line Input #nFic, sCadena
If Left$(sCadena, 1) = "[" Then
'nada ms que leer
'restablecemos la posicin anterior
Seek nFic, Posicion
Exit Do
Else
Posicion = Seek(nFic)
'Posicin del signo igual
i = InStr(sCadena, "=")
If i Then
nClaves = nClaves + 1
ReDim Preserve
aSecciones(nSecciones).Contenidos(nClaves)
With aSecciones(nSecciones)
.NumClaves = nClaves
'La clave estar antes del signo igual
.Contenidos(nClaves).Clave = Trim$(Left$(sCadena,
i - 1))
'el contenido de la clave despus del signo
.Contenidos(nClaves).Contenido = Mid$(sCadena, i +
1)
End With
End If
End If
Loop
End If
Loop

Close nFic
If nSecciones Then
'seleccionamos el primer item del listbox
List1.ListIndex = 0
'habilitamos el botn
cmdLeerContenido.Enabled = True
Else
MsgBox "No hay secciones en el fichero: " & sFic
End If
End Sub
Private Sub Form_Load()
Dim nFic As Integer
'deshabilitar el botn de leer contenidos
cmdLeerContenido.Enabled = False
Text1 = ""
List1.Clear
'Creamos el fichero de ejemplo
sFic = "basico_20.ini"
nFic = FreeFile
Open sFic For Output As nFic
Print #nFic, "[elProfe]"
Print #nFic, "Nombre=Guillermo"
Print #nFic, "email=guille@costasol.net"
Print #nFic, ""
Print #nFic, "[Alumnos]"
Print #nFic, "Cantidad=2"
Print #nFic, "Nombre_01=Pepito"
Print #nFic, "email_01=pepito@servidor.com"
Print #nFic, "Nombre_02=Juanita"
Print #nFic, "email_02=juani@servidora.net"
Print #nFic, ""
Print #nFic, "[Fecha]"
Print #nFic, "Fichero creado el da=26/May/1998"
Close
cmdLeerSecciones_Click
End Sub
Private Sub List1_DblClick()
cmdLeerContenido_Click
End Sub
El segundo:
'
'Ejemplos del curso bsico, ejemplo de Seek
'
'Solucin a los ejercicios de la entrega 20
'
Option Explicit
Private Type tSecciones
Nombre As String
NumClaves As Integer
Contenidos() As Long
End Type
Private aSecciones() As tSecciones
Private nSecciones As Integer
Private sFic As String

(26/May/98)

Private Sub cmdLeerContenido_Click()


'Leemos el contenido de la seccin seleccionada en el list
Dim nFic As Integer
Dim sCadena As String
Dim nItem As Long
Dim i As Integer
nItem = List1.ListIndex
If nItem >= 0 Then
nFic = FreeFile
Open sFic For Input As nFic
'borramos el contenido del Text1
Text1 = ""
With aSecciones(nItem + 1)
For i = 1 To .NumClaves
'Nos posicionamos en el sitio que nos interesa
Seek nFic, aSecciones(nItem + 1).Contenidos(i)
Line Input #nFic, sCadena
Text1 = Text1 & sCadena & vbCrLf
Next
End With
Close nFic
End If
End Sub
Private
Dim
Dim
Dim
Dim
Dim

Sub cmdLeerSecciones_Click()
nFic As Integer
sCadena As String
Posicion As Long
nClaves As Integer
i As Integer

'Borramos el contenido del ListBox


List1.Clear
'Leemos las secciones disponibles
nFic = FreeFile
Open sFic For Input As nFic
Do While Not EOF(nFic)
Line Input #nFic, sCadena
'Si es una seccin
If Left$(sCadena, 1) = "[" Then
nClaves = 0
'incrementamos el nmero de secciones
nSecciones = nSecciones + 1
'redimensionamos el array
ReDim Preserve aSecciones(nSecciones)
'asignamos los valores al array
aSecciones(nSecciones).Nombre = sCadena
'aadimos esta seccin a la lista
List1.AddItem sCadena
'ahora leemos el contenido del fichero hasta encontrar [
Do While Not EOF(nFic)
'En las claves nos interesa saber la posicin
'antes de empezar a leerlas
Posicion = Seek(nFic)
Line Input #nFic, sCadena
If Left$(sCadena, 1) = "[" Then
'nada ms que leer
'restablecemos la posicin anterior
Seek nFic, Posicion
Exit Do
Else
i = InStr(sCadena, "=")
'Si es una clave tendr el signo igual
If i Then
nClaves = nClaves + 1

ReDim Preserve
aSecciones(nSecciones).Contenidos(nClaves)
With aSecciones(nSecciones)
.NumClaves = nClaves
.Contenidos(nClaves) = Posicion
End With
End If
End If
Loop
End If
Loop
Close nFic
If nSecciones Then
'seleccionamos el primer item del listbox
List1.ListIndex = 0
'habilitamos el botn
cmdLeerContenido.Enabled = True
Else
MsgBox "No hay secciones en el fichero: " & sFic
End If
End Sub
Private Sub Form_Load()
Dim nFic As Integer
'deshabilitar el botn de leer contenidos
cmdLeerContenido.Enabled = False
Text1 = ""
List1.Clear
'Creamos el fichero de ejemplo
sFic = "basico_20.ini"
nFic = FreeFile
Open sFic For Output As nFic
Print #nFic, "[elProfe]"
Print #nFic, "Nombre=Guillermo"
Print #nFic, "email=guille@costasol.net"
Print #nFic, ""
Print #nFic, "[Alumnos]"
Print #nFic, "Cantidad=2"
Print #nFic, "Nombre_01=Pepito"
Print #nFic, "email_01=pepito@servidor.com"
Print #nFic, "Nombre_02=Juanita"
Print #nFic, "email_02=juani@servidora.net"
Print #nFic, ""
Print #nFic, "[Fecha]"
Print #nFic, "Fichero creado el da=26/May/1998"
Close
cmdLeerSecciones_Click
End Sub
Private Sub List1_DblClick()
cmdLeerContenido_Click
End Sub

Curso Bsico de Programacin


en Visual Basic
Entrega Veintiuna: 13/Jul/98
por Guillermo "guille" Som

Si quieres linkar con otras entregas, desde el ndice lo puedes hacer

Con lo que hemos visto hasta ahora tendrs, o al menos deberas tener, una buena base sobre el
lenguaje BASIC (o Visual Basic), pero saber un montn de instrucciones no es suficiente. Por suerte, no
slo hemos visto un "diccionario" del VB.
Si has empezado casi de cero, seguramente no te habr costado adaptarte a la programacin en
Windows, pero si por el contrario arrastras "conocimientos" de cualquier otro lenguaje que funcionaba
bajo MS-DOS, puede que esa adaptacin te cueste ms, sobre todo si el lenguaje con el que trabajabas
era el BASIC.
Un problema de los que descendemos, por aquello de la herencia, del MS-DOS, es que "pretendemos"
aprovechar lo que ya tenamos hecho y queremos adaptar al Visual Basic nuestros programas: UN
ERROR!
S, como lo oyes, intentar adaptar todo un programa DOS a Windows es una tarea muy dura y a la larga
poco efectiva, te lo digo por propia experiencia; otra cosa es adaptar ciertas rutinas, esto es ms fcil,
sobre todo si no interacta con el usuario.
El decir todo esto es para que desistas en "ventanizar" una aplicacin BASIC-DOS, seguramente, salvo
que la tuvieras bastante bien estructurada con procedimientos y funciones, te costar ms adaptarla que
hacerla de nuevo.
No voy a explicar cmo adaptar un listado MS-DOS al Windows, sera una prdida de tiempo, sobre todo
si a t no te interesa, lo que si vamos a "volver" a ver es cmo controlar una aplicacin de Windows, (sino
volver a ver, al menos profundizar en el tema).
Porque hay ocasiones en las que nosotros debemos tomar el control, por ejemplo cuando el usuario
tiene que rellenar un campo y no debe pasar a otro hasta que lo haya hecho de forma correcta.
En una ocasin anterior ya vimos que los programas realizados en Visual Basic, y por extensin todos
los programas que tengan que trabajar en Windows, se basan en los eventos. Si entendemos bien para
que sirven los eventos, seguramente nos ser ms fcil "controlar" el funcionamiento del programa.
As que, en esta y en las prximas entregas, vamos a darle un repaso a los eventos ms usuales.
Tambin veremos con detalle, unos cuantos controles, los ms habituales, de forma que su uso y
aplicacin sean "casi naturales" y al final acabes usndolos como si los conocieras de toda la vida.

Un poco de definicin.
Te recuerdo que un evento es una especie de aviso que manda el control de que algo ha ocurrido o est
ocurriendo.
Esto de los eventos es la "esencia" de la programacin Windows. No estamos atados a una
programacin secuencial (o lineal), como se haca en MS-DOS. Con ese tipo de programacin, nosotros
decidamos lo que iba a ocurrir a continuacin, y si no decidamos, al menos podamos prever lo que
poda suceder.
Pero la programacin en Windows es otra historia; el Windows nos "avisa" de que algo est ocurriendo,
bueno, realmente Windows no nos avisa de nada, (a ver si piensas que te va a mandar un mensaje por
mail), son los controles mediante sus eventos los que hacen sonar la campana para que sepamos que el
usuario est haciendo algo, como mover el ratn, presionar una tecla, etc.

Para muestra...
...un botn y un label y un textbox y un...
Empecemos por el Label que es ms simple.

Las etiquetas (Label) se usan para mostrar informacin, normalmente este tipo de control no necesita
intervencin por parte del usuario.
Normalmente se suele usar de estas dos formas:
Como etiqueta informativa que acompaa a otro control y que nos indica la informacin que ese
control nos da o nos pide, segn sea el caso.
Por ejemplo, si queremos que el usuario introduzca un nombre, usaremos un textbox para que escriba
en l, pero tambin pondremos una etiqueta indicndole que es lo que se espera que escriba.
Como panel o lnea informativa, indicndole algn tipo de informacin al usuario.
Es habitual que en la parte inferior de un form se aada una etiqueta que "informe" de lo que se debe
hacer o lo que el programa est haciendo.
Tambin se usan las etiquetas para informar de las opciones que ha seleccionado o del proceso que la
aplicacin ha realizado o est a punto de realizar.
Resumiendo, cada vez que tengas que informar al usuario, usa etiquetas para ello. Siempre que esa
"informacin" no requiera de su intervencin.
Las cajas de texto (TextBox) son los controles, por excelencia, para la introduccin de informacin por
parte del usuario.
Cada vez que el usuario deba escribir lo que nuestra aplicacin necesite, se usar un textbox.
Los botones (CommandButton) son los que indicarn, normalmente, al programa que el usuario ha
finalizado de introducir la informacin que se necesita y que debe procesarla o si el usuario cambia de
opinin y no quiere hacer lo que se peda.
Es, por tanto, habitual que se usen dos botones para conseguir esto, uno para "aceptar" y otro para
"cancelar".
Tambin es habitual que se use para pasar a otra pantalla de informacin.
Los ListBox y ComboBox se suelen usar para mostrarle al usuario una "lista" de posibilidades de las
que debe escoger una o varias, (para esto ltimo es ms habitual el listbox).
Aunque el ComboBox se puede usar tambin para la introduccin de informacin, no es lo habitual, en la
mayora de los casos es preferible usar el TextBox, aunque tambin veremos los casos en los que nos
viene mejor usar el Combo.
Los CheckBox se usan cuando el usuario necesite indicar si se usa o no una opcin determinada, esta
opcin debe ser tan "autosuficiente" y slo se necesitar saber si la quiere usar o no.
Por ejemplo, si necesitamos que el usuario indique si una vez procesado los datos queremos que se
imprima o no.
El uso de los OptionButtons es para las ocasiones en las que necesitemos indicar al usuario que
escoja entre unas cuantas y elija slo una.
Hay ocasiones en las que en lugar de un checkbox, se usan dos optionbuttons; para el mismo caso de
imprimir o no, para que indique el sexo, etc.
Por supuesto que hay ms controles, pero al menos estos son los que se usarn ms habitualmente,
aunque para que la "relacin" sea ms completa, veremos tambin otros dos controles que se suelen
usar para "contener" y agrupar a los dems controles:
Los PictureBox y Frames, stos se usan para poner controles dentro, sobre todo el Frame.
La primera recomendacin para hacer esto, adems de tenerlos "fsicamente" separados del resto,
tambin es ms fcil moverlos a otro sitio cuando estamos diseando la aplicacin o el "interface" de
cara al usuario.
En otras ocasiones necesitaremos estos contenedores para agrupar los OptionButtons, cuando veamos
en profundidad los controles, lo entenders.
Como ltimamente no dispongo de mucho tiempo y adems me gusta "chincharos" un poco, dejo aqu
esta entrega, as que, permanece pendiente y mientras tanto repasate el manual y la ayuda, de esta
forma te ser ms fcil adaptarte.

En esta ocasin no te voy a pedir ningn comentario sobre la entrega, ya que tampoco es mucho lo que
ha dado de s, pero no quiero que pasen "meses" entre entrega y entrega, as que... aunque poco, algo

es algo.
De todas formas, en la prxima entrega veremos ya algunos de los eventos ms habituales.
Este tipo de entregas son un poco "aburridas", ya que hay que empezar a manejar un poco los
conceptos antes de pasar a los ejemplos, por tanto te pido un poco de consideracin para conmigo y
aguantes hasta que venga lo realmente interesante: los programillas de ejemplo y esas cosas.

Curso Bsico de Programacin


en Visual Basic
Entrega Veintidos: 4/Sep/98
por Guillermo "guille" Som
Si quieres linkar con las otras entregas, desde el ndice lo puedes hacer

Ya habrs notado a lo largo de todas estas entregas, que de planificacin, "nasti de plasti", osease nada
de nada... Y es que las cosas van surgiendo y mezclndose y al final... hasta casi se entiende lo que
digo... y eso que es difcil, sobre todo cuando entre una entrega y la siguiente casi han pasado dos
meses... pero, como digo, suerte para los que empiezan cuando ya hay un montn de entregas, al
menos se las leen del tirn... porque en ms de una ocasin me han escrito, sin nimo de ser
demasiados criticones, supongo, que si el que empezara el curso en abril del ao pasado, tuviese que
esperar a que lo terminase... lo tena claro... y es cierto, pero confo que los que empezasteis de los
primeros, ya hayais aprendido a leer el manual y la ayuda del Visual Basic, y hasta os hayais atrevido
con algunos de los muchos libros que hay sobre este lenguaje... que si bien, al principio os podran
parecer difciles de entender, al menos ahora podais entenderlos, aunque sea un poco...
Como deca al principio, o al menos intentaba decir, el curso no lo tengo planificado y las cosas van
surgiendo... la verdad es que ahora que leo los apuntes que tena, fechados el 9 de julio, no se a que
viene todo este rollo, as que mejor lo dejo y seguimos con el tema este de los eventos y los controles
que podemos usar con el Visual Basic.
Ya sabes, (y si no lo sabias, te lo cuento yo ahora), que los controles suelen estar incluidos en un
formulario, tambin pueden estar en controles diseados por nosotros y en otros tipos de
"contenedores", (de basura habr pensado alguno, sobre todo cuando se pone manos a la obra y no sale
lo que quiere... no te desesperes, ya tendrs tiempo de pillar buenos cabreos...), pero para simplificar,
vamos a pensar que estn puestos en un formulario.
Esta aclaracin viene a cuento para lo que te voy a contar ahora.
Insisto, esto lo tengo manuscrito desde hace dos meses y la verdad es que o recuerdo en que estaba
pensando cuando lo escrib, porque nada de lo que viene a continuacin tiene que ver con el hecho de
que un control est en un formulario u otro contenedor, pero al menos podrs "intuir" que los controles no
tienen porqu estar siempre "puestos" en un formulario.
Cuando se produce un evento en un formulario, producido por el propio Form o por cualquier control
contenido en l, se deja de procesar el cdigo que se estaba ejecutando y se pasa a procesar el cdigo
contenido en el evento.
Es importante que tengas muy presente esto que acabo de decir, ya que es la causa de efectos no
deseados.
Por supuesto, si el evento que se produce no tiene cdigo asociado, no pasa nada.
Aclaremos esto un poco; si te has fijado en la ventana de cdigo, cuando seleccionas un control de la
ventana izquierda, incluso el propio formulario, en la ventana de la derecha te muestra los eventos
disponibles, es decir los eventos que Visual Basic podr interceptar, normalmente no son todos los que
se generan, pero s son los que el propio lenguaje nos permite interceptar y por tanto en cualquiera de
ellos podemos aadir nuestro cdigo para hacer algo cuando dicho evento se produzca.
Pero esto no quiere decir que tengamos que escribir cdigo en todos ellos, sino slo en los que nos
interesen, pero el hecho de no escribir cdigo en un evento, no quiere decir que no se producir. Por

ejemplo, si no escribes cdigo en el evento LOAD de un form, no impedir que el form se cargue, se
cargar, independientemente de que queramos interceptar ese hecho o no.
Sigamos con lo que pasa cuando se est ejecutando una parte del cdigo y se produce un evento.
Por ejemplo, si mientras se procesa el cdigo de un evento, vuelve a producirse ese mismo evento, se
vuelve a procesar el cdigo desde el principio y una vez terminado este segundo evento, se contina por
dnde se interrumpi el anterior.
Esta es una de las gracias de Windows y todo el tema de los eventos.
No te preocupes si no te enteras que pronto veremos ejemplos.
Aunque en muchas ocasiones esto no ocurre mientras nosotros no lo permitamos, hay veces en las que
no podemos "predecir" que es lo que ocurrir, salvo que comprendamos perfectamente cmo funcionan
los controles y sepamos cmo y cuando se producen algunos eventos; tambin puede intervenir la suerte
de darnos cuenta de que... "si hago esto con este control, puede ocurrir este o aquel evento"
Y esto que os digo es tan cierto como que nadie me ha regalado an un porttil... je, je.
Vamos a ver un pequeo ejemplo para que salgas de dudas.
Crea un nuevo proyecto, cambia la propiedad Autoredraw del form para que sea True, de esta forma, si
lo redimensionas podrs ver lo que se ha imprimido en el.
Escribe el siguiente cdigo en el evento Click del form:
Private Sub Form_Click()
Dim i As Long
Dim j As Long
Print
For i = 1 To 10
Print i;
For j = 1 To 2000
DoEvents
Next
Next
Print
End Sub
Ejecuta el programa, cuando hagas click en el formulario, vers que se imprimen los nmeros del 1 al 10,
van un poco lento, para que puedas hacer lo que te dir ahora, mientras se estn imprimiendo los
nmeros, vuelve a hacer click en el form, hazlo ms o menos rpido, si tus reflejos no te funcionan como
quisieras, cambia el valor 2000 del bucle j con otro mayor, as se irn imprimiendo los nmeros de forma
ms lenta.
Habrs notado que cuando an no se ha terminado de imprimir los primeros diez nmeros, (si has
pulsado antes de que se terminen de imprimir, claro), se empiezan a imprimir en la siguiente lnea desde
1 y cuando dejes de hacer click, irn terminando los bucles... supongamos que has pulsado tres veces, el
resultado podra ser este:
12345678
123456
1 2 3 4 5 6 7 8 9 10
7 8 9 10
9 10
El primer bucle se interrumpi en 8, se inici el segundo, que se interrumpi en 6, se inici el tercero y
continu hasta finalizar, despus continu el segundo, (el que se qued en 6), y termina, una vez que
termin el segundo, se continua con el primero que se qued en 8 y por eso se imprimen el 9 y 10.
Como notars, no se han perdido los valores... y el Visual record por dnde se qued... esto es debido
a que todas las variables de un procedimiento son locales a este procedimiento, sea un evento o no,
(realmente los eventos son SUBs que son llamados por Windows), y se guardan antes de volver a entrar
en el procedimiento y una vez que el procedimiento acaba, se desechan... la memoria que se usa para
guardar temporalmente los valores de las variables de un procedimiento se llama STACK (o pila del
programa), hay que tener en cuenta que esta "pila" no es infinita y puede llegar a llenarse... sobre todo
cuando las cosas no se hacen bien. A este tipo de variables locales, tambin se les llama variables
automticas, por el hecho de que una vez que no se necesitan son automticamente borradas... cosa
que no ocurre cuando las variables se declaran a nivel de mdulo o se declaran "estticas", ms
adelante veremos ms sobre esto.

Lo que este pequeo ejemplo demuestra es lo que te he explicado antes, que se puede "reentrar" en un
evento (y por extensin a cualquier procedimiento); si esto mismo se hiciera por cdigo, no porque el
usuario interviene con su ratn, tendramos lo que se llama un procedimiento "recursivo", es decir que se
llama a s mismo... tendremos ocasin de ver algn ejemplo.
El evento ms dado a este tipo de "recursividad" es el evento Click. Este evento se produce cada vez
que pulsamos con el ratn sobre un control, incluso sobre un formulario, como hemos visto en este
ejemplo.
Este evento (Click), est presente en la mayora de los controles, prcticamente en todos.
La verdad es que poder "seguir" esto, imaginndose cmo lo hace el VB, es un poco difcil... vamos a ver
otro caso, ms usual y que seguramente ser ms fcil de entender...
Supongamos que tenemos un cdigo que procesa una serie de cosas y ese proceso puede llegar a ser
largo. Si ese cdigo lo tenemos en el evento Click de un botn, con idea de que se procese cada vez que
se pulsa en el botn, (cosa super-habitual), si no hacemos nada especial, mientras se est procesando el
cdigo, el form completo se quedar "congelado", una vez que haya terminado el proceso, se continuar
"aceptando" nuevos eventos, normalmente se quedarn pendientes de procesar y se ejecutarn a
continuacin de terminar el proceso largo...
Por eso en ocasiones es conveniente usar, como en el ejemplo anterior, la instruccin DoEvents. Con
esta instruccin permitimos que Windows notifique "en seguida" de que ha ocurrido otro evento y nos da
la posibilidad de procesarlo en ese momento.
Eso o al menos indicar al usuario de que tenga paciencia y espere a que se termine de hacer lo que se
estaba haciendo, ya que si no lo hacemos puede pensar que el programa se ha quedado "colgado".
Vamos a modificar el cdigo anterior del Form_Click para ver esto que estoy diciendo.
Sustituyelo por este otro:
Private Sub Form_Click()
Dim i As Long
Dim j As Long
For i = 1 To 10
Print i;
For j = 1 To 2000000 'dos millones
Next
Next
Print
End Sub
Ejecuta el programa y haz click, vers que no pasa nada, haz click de nuevo y esta vez si que ocurre,
hasta puede que el form se quede en blanco y al rato volver a la normalidad con las dos ristras de
nmeros impresos... o ms si no has tenido paciencia suficiente...
Una forma de solventar esa espera... es hacer que se muestre un mensaje pidindonos que
esperemos... pero eso no evitar que volvamos a hacer click en el form... incluso el mensaje no se
mostrar hasta que se haya terminado de hacer lo que se estaba haciendo... para que el mensaje se vea
enseguida, se pueden hacer dos cosas:
Una: usar un DoEvents justo despus de imprimir el mensaje
Dos: usar Refresh para que se "pinte" el control, en este caso el formulario.
...

Print "Un momento por favor..."


Refresh
For i = 1 To 10

...
En ambos casos tendramos el mensaje mostrado en la pantalla, vale, pero si vuelves a hacer click... se
volver a procesar todo el cdigo, etc... Aunque en esta ocasin, hasta que no finalice, no contina el
siguiente.
Cmo podemos evitar la re-entrada en un evento cuando an no ha terminado?
Usando lo que se llama un FLAG (o bandera), es decir una variable que nos indique que ya se est
procesando el cdigo y de esta forma poder evitar que se repita si an no ha terminado.
Como ya te he contado antes, las variables locales son automticas y se desechan una vez finalizado el

procedimiento, al ser automticas no "recuerdan" el valor que tenan antes, salvo en las ocasiones que el
VB las guarda en el Stack, pero no son recordadas en las diferentes ocasiones en las que entran en el
procedimiento.
Recuerdas que te coment lo de las variables estticas?
Pues este tipo de variables son las que podemos usar para prevenir estos casos. Las variables estticas
se declaran de igual forma que las variables normales, salvo que en lugar de usar Dim, se usa Static.
Una vez declarada una variable esttica, deja de ser automtica y VB no guarda una copia cada vez que
se entra en el procedimiento, sino que usa la misma cada vez que se procese el cdigo de ese evento.
Por tanto cada vez que se "cuela" el cdigo en un evento (o procedimiento), podemos saber si ya hemos
estado antes, sin terminarlo o no... para ello habra que hacer esto:
Private Sub Form_Click()
Dim i As Long
Dim j As Long
Static bFlag As Boolean
'Si no estamos en el evento
If bFlag = False Then
'conectamos la bandera
bFlag = True
Print "Un momento por favor..."
Refresh
For i = 1 To 10
Print i;
For j = 1 To 1000000
Next
'Debemos permitir que se procesen los mensajes
DoEvents
Next
Print
'Desconectamos la bandera
bFlag = False
End If
End Sub
Aqu hay dos detalles a tener en cuenta, el primero es el uso de la variable esttica, el otro es el
DoEvents, sin ste, el uso de la variable esttica no servira para nada, ya que al no permitir a Windows
que notifique los eventos, estos se quedan guardados en espera a que teminen los que haba
pendientes, y para que no se queden guardados, usamos el DoEvents.
Prueba a pulsar varias veces en el formulario mientras se muestran los nmeros, vers que no se
vuelven a mostrar.
Te explico un poco cmo funciona esto:
La primera vez que se entre en el evento, el valor de bFlag valdr False, esto siempre es as con las
variables Booleanas, cuando se quiere averiguar el valor de una variable que no se ha usado, sta tiene
un valor "vacio", cero en las numricas, cadena vaca en las cadenas y False en el caso de las
booleanas.
Como vale False, se cumple la condicin, por tanto se asigna el valor True a esa variable y se contina
procesando el cdigo.
Cuando se llega al DoEvents, Windows procesa los mensajes que tuviese pendiente y si tiene que
enviarle uno a este formulario, lo har.
Suponiendo que hemos pulsado otra vez el ratn, al procesarse los mensajes pendientes, Windows
enva al form un nuevo evento Click. Entonces se entra de nuevo en este procedimiento, pero esta vez,
el valor de bFlag no es False, por tanto no se hace nada, ya que la condicin no se cumple y se sale del
evento.
Cuando se ha salido del evento, se contina por donde estaba antes y se sigue procesando el bucle, etc.
Una vez terminado el bucle i, se asigna de nuevo el valor False a bFlag, para as poder permitir que se
procese en otra ocasin el cdigo que hay.
Todo esto es posible gracias a que la variable bFlag es esttica y el valor almacenado se mantiene entre
las distintas llamadas, si no asignaramos el valor False al final, no podramos entrar ms en este evento,
ya que nunca se cumplira la condicin, as que hay que tener cuidado con las variables estticas, si el
uso que le queremos dar es parecido al que hemos visto.

Hay ocasiones en las que un evento se "reproduce" muy a pesar nuestro, ms que nada porque hay
veces en las que no es tan obvio.
Por ejemplo, cuando se selecciona un elemento de un ListBox, se produce un evento Click; y si en ese
evento Click, tenemos algn cdigo que seleccione elementos del control... podemos tener al Visual
Basic bastante atareado... entrando en un evento y desde ese evento entrando a otro y as durante un
rato... mientras tanto, nuestro pobre VB guardando las variables automticas en el Stack (pila), pero llega
un momento en el que la pila se llena... y en ese momento nos suelta un mensajillo de esos que nos
indican que ya est hasta la coronilla de nosotros y de nuestra mala forma de programar... y se para...
Igual que yo me voy a parar aqu, porque ya est bastante bien de tanto Click y tanto Stack y todas esas
cosas...
Al final, la pelcula que te he contado no era exactamente lo que estaba en el guin, pero ms o menos lo
que te he explicado era lo que quera explicarte...
Para terminar, te dir que en algunos controles, al pulsar Intro se produce tambin un evento Click, por
ejemplo en los CommandButtons. Por supuesto para que se procese ese Intro, el control debe tener el
foco.
Bueno, lo dicho, dejemos aqu esta entrega que hay ms cosas que hacer.
A ver si la prxima no tarda tanto como esta y seguimos viendo... (espera que mire los apuntes, a ver
que es lo que hay preparado), ... en las notas del 12 de julio estn los eventos del ratn, en las del da
13, los del teclado... en fin, esto promete seguir pesadillo... pero que le vamos a hacer... todo sea para
que te enteres un poco de cmo va todo esto de los eventos...
Lo dicho en otras ocasiones: prtate bien y no hagas estropicios y si quieres mandarme un mensajillo
sobre el curso

Curso Bsico de Programacin


en Visual Basic
Entrega Veintitres: 4/Oct/98
por Guillermo "guille" Som
Si quieres linkar con las otras entregas, desde el ndice lo puedes hacer

Tengo muchas excusas que darte, para justificar este retraso, pero no voy a dartelas, ya que no har que
esta entrega se publicara antes...
La verdad es que esto de tanta "teora" me aburre un poco y no me motiva, pero se que es importante
que sepas todo esto de los eventos y dems cosillas, as que voy a intentar seguir, ya que en cuestin de
un par de entregas estaremos con otras cosas... no se que cosas, pero seguro que con otros temas... lo
importante es que sigas aprendiendo... pero no slo de lo que publico en el curso bsico, sino que si le
echas una visual a los manuales y a la ayuda... algo tendrs aprendido, espero que con todas las cosas
que llevo puestas hasta la fecha te haya servido para poder entender lo que en esos manuales y ayuda
se dice... y si no es as, no te preocupes, que algn da lo podrs entender...
Bien, vamos a ver algunos de los eventos que se producen con el ratn.
Como ya te coment en la entrega anterior, se puede saber los eventos que un control puede interceptar,
al menos los que el Visual Basic nos permite, son los que se muestran en la ventana de cdigo, en la
parte izquierda se selecciona el control o formulario y en la derecha estn los eventos que podemos
"codificar".
No todos los controles procesan los mismo eventos, pero en el caso de los eventos del ratn, casi la
mayora los interceptan... aunque no todos los que quisieramos, pero al menos algunos...

En estas imagenes podemos ver las listas de "objetos" disponibles en el formulario, en los que podemos
interceptar eventos y algunos de los eventos disponibles en el formulario.
En la lista
desplegable
de la
izquierda
estn los
controles que
estn
contenidos en
el formulario,
as como la
seccin
"General"
usada para
las
declaraciones
de variables y
procedimiento
s.
En la lista de
la derecha, se
muestran los
diferentes
eventos
disponibles
para el control
seleccionado
en la
izquierda, en
esta imagen
vemos
algunos de
los eventos
"interceptados
" por el VB
refente a los
formularios
normales.

Por ejemplo, podemos saber cuando se est moviendo el ratn por el control, (te recuerdo que los
formularios tambin tienen estos eventos), si se ha presionado un botn y hasta que botn se ha
presionado... Vamos a verlos con un poco ms de detalle:

Evento MouseDown.
Este evento se produce cuando pulsamos un botn del ratn. Con los parmetros que tiene este evento
podemos saber que botn se ha pulsado, la posicin dentro del control y si se est pulsando la tecla Shift
(Maysculas), Control o Alt.
Vamos a ver los parmetros y algunos de los valores disponibles.
Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Button

Indica el botn que se est pulsando, puede tener los siguientes valores:
1, se est pulsando el botn izquierdo,
2, se est pulsando el derecho,
4, se est pulsando el botn central.

Shift

X, Y

Slo se controla un botn a la vez.


Indica si se est pulsando algunas de las teclas de "cambio", Shift, Ctrl o Alt, el
valor devuelto corresponde con:
1, se est pulsando la tecla Shift (maysculas)
2, se est pulsando Control
4, se est pulsando Alt
Se permiten combinaciones de estos valores, es decir que si se pulsan varias de
esas teclas, los valores sern:
3, se estn pulsando Shift y Ctrl,
5, se estn pulsando Shift y Alt,
6, se estn pulsando Ctrl y Alt,
7, se estn pulsando las tres teclas.
Indica las coordenadas de la posicin del puntero del ratn dentro del control.
Es importante saber que estos valores son slo dentro del control en cuestin, no
referente al formulario o la pantalla.

El evento MouseDown se suele usar, entre otras cosas, para mostrar mens emergentes (PopUpMenus),
normalmente controlando que se haya pulsado el botn derecho, (cuando Button vale 2)

Evento MuseUp.
Este evento se produce cuando se suelta el botn, los parmetros son los mismos que para
MouseDown, pero en este caso lo que se detecta es cuando se "suelta" el botn pulsado.

Evento Click.
Este evento se produce cuando se hace "click" en un control... es una combinacin del MouseDown
seguido de un evento MouseUp... debes tener en cuenta que si ests genstionando los eventos
MouseDown, MouseUp y Click te encontrars con que se producen los tres eventos en ese orden, es
decir, primero se presiona, despus se suelta y por ltimo se produce el Click.

Evento DblClick.
Este como podrs imaginarte, se produce cuando se hace una doble pulsacin, doble click.
Si ests controlando estos cuatro eventos, adems de hacer tus propias comprobaciones, deberas
saber que normalmente se producen en este orden:
Primero el MouseDown, seguido de un MouseUp, a continuacin un Click seguido de un DblClick y por
ltimo un MouseUp.
Todo esto lo puedes comprobar con el siguiente cdigo:
'
'Pruebas para la entrega 23 del curso bsico
'
Option Explicit

(04/Oct/98)

Private Sub Form_Click()


Debug.Print "Se ha pulsado sobre el formulario (Click)"
End Sub
Private Sub Form_DblClick()
Debug.Print "Doble pulsacin en el formulario (DblClick)"
End Sub
Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y
As Single)
Debug.Print "Se ha pulsado el botn del ratn (MouseDown)"
End Sub
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y
As Single)

Debug.Print "Se ha soltado el botn del ratn (MouseUp)"


End Sub

Evento MouseMove.
Este evento se produce cada vez que movemos el ratn por un control o por el formulario.
Los parmetros de este procedimiento son los mismos que en los otros referentes al ratn:
Private Sub xxx_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Con este evento podemos saber cuando estamos dentro del control, sabiendo esto, podemos cambiar su
apariencia, etc.
El problema es que no sabemos cuando no estamos en el control, aunque si interceptamos la entrada en
otras partes del formulario, podremos saber que no estamos en el control en cuestin, ya que si estamos
en otro control... quiere decir que no estamos en este... Elemental querido Watson!
Si quieres ver un ejemplo para hacer "garabatos" en la pantalla... algunos lo llaman dibujar, en el cdigo
del evento MouseDown, selecciona la palabra MouseDown y pulsa F1, en el ejemplo que se muestra
est el programa para hacer esos garabaticos...

Y esto es todo por hoy... poco, pero mejor poco que nada... la prxima entrega ser sobre los eventos del
teclado... que podra haber puesto en esta, pero...
Y despus veremos algunos otros ms... lo que no se es si ser en la prxima o en la siguiente... ya
veremos.
Y para seguir con la norma... si quieres dejar un mensaje referente al curso bsico, puedes hacerlo, para
ello usa el siguiente link para que te resulte ms fcil y as controle que lo que me quieres decir es
referente al curso y no para hacer una consulta, ya que algunos aprovechan la ocasin para preguntar...
Este es el link para que me mandes tu comentario.

Curso Bsico de Programacin


en Visual Basic
Entrega Veinticuatro: 10/Oct/98
por Guillermo "guille" Som
Si quieres linkar con las otras entregas, desde el ndice lo puedes hacer

Son muchas las cosas que ocurren en una aplicacin mientras el usuario est trabajando, (o cualquiera
sabe lo que estar haciendo). Ya vimos algunos eventos relacionados con el ratn, pero tambin habr
muchos otros relacionados con el teclado, es decir, cada vez que el usuario pulse una tecla se
producirn varios eventos, que la tecla se mantiene pulsada, que la tecla se ha soltado... en resumen
que la tecla se ha pulsado. Tambin se puede saber cuando una serie de teclas se pulsan al mismo
tiempo, realmente cuando se pulsan algunas de las "especiales": Shift, Ctrl o Alt.
Bsicamente son tres los elementos que la prctica totalidad de los controles y formularios reconocen:
KeyDown, KeyUp y KeyPress, vamos a verlos por separado y con algo de detalle, adems de algn
ejemplo aclaratorio.

Evento KeyPress.
Este evento se produce cada vez que una tecla se pulsa, al menos una tecla normal... ya que las teclas
"especiales" no se consideran normales y no se suelen detectar en este evento, salvo que se use junto a
una tecla "normal".
Veamos que informacin acepta este evento como parmetro:
Private Sub Text1_KeyPress(KeyAscii As Integer)
El parmetro KeyAscii nos indicar el cdigo de la tecla pulsada, este cdigo nos lo da como valor
numrico, no como una cadena, es decir que si pulsamos la tecla A mayscula, valdr 65, ya que ese es
el valor ASCII de ese caracter, (realmente es un valor ANSI, pero...).
Para saber el valor de las teclas, puedes pulsar F2 en el IDE del Visual Basic y buscar las constantes de
KeyCode o en la ayuda busca la palabra KeyCode, de todas formas los valores Ascii se pueden saber o
usar con la funcin ASC, por tanto se puede hacer una comparacin de este tipo:
If KeyAscii = Asc("A") Then
'se ha pulsado la A mayscula
End If
En este evento se pueden detectar un montn de teclas, todas las alfanumricas y otros caracteres,
adems de la tecla INTRO (return), aunque tendrs problemas con la tecla TAB, ya que esta tecla tiene
un significado especial y no es tan fcil de detectar...
Normalmente se suele detectar la pulsacin de la tecla INTRO, entre otras cosas porque suele emitir un
pitido cada vez que se pulsa, al menos en las cajas de texto... para evitar ese "pitido", se puede hacer
esto:
If KeyAscii = vbKeyReturn Then
KeyAscii = 0
'Eliminamos el pitido
End If
Con esta asignacin, lo que hacemos es indicarle al VB que no se ha pulsado nada... o al menos decirle
que no tenga en cuenta que se ha pulsado esa tecla.
Otra de las cosas que se suele hacer cuando se pulsa INTRO es pasar al siguiente control, de la misma
forma que si hubiesemos pulsado la tecla TAB, esto se suele hacer ms a menudo de lo que parece,
sobre todo para usuarios que estn acostumbrados a usar programas de MS-DOS, para conseguirlo,
adems de tener "conectada" la propiedad TabStop de los controles, (si esta propiedad tiene el valor
FALSE no se puede usar TAB para cambiar de control), tendremos que decirle al Windows que lo que se
ha pulsado no ha sido el INTRO sino el TAB... es decir con algo como esto:
If KeyAscii = vbKeyReturn Then
KeyAscii = 0
'Eliminamos el pitido
'si queremos pasar al siguiente control
'tal como lo haramos pulsando la tecla TAB:
SendKeys "{TAB}"
End If
Es decir, usamos la instruccin SENDKEYS para que envie una tecla TAB...
Para ver que teclas podemos "enviar" con SendKeys, consulta la ayuda...
Por supuesto que se pueden hacer muchas otras cosas en este evento, pero eso depender de nuestra
aplicacin... y de nuestros gustos...

Eventos KeyDown y KeyUp.


Para tener un mayor control en las teclas pulsadas, se suelen comprobar en los eventos KeyDown y
KeyUp, la principal diferencia con el evento KeyPress es que en este caso no son cdigos ASCII, sino

cdigos de teclado...
Veamos los parmetros:
Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer)
KeyCode es el cdigo de la tecla, no el cdigo ASCII, aunque en la mayora de los casos coincide,
aunque no en todos.
Shift es para saber si se ha pulsado al mismo tiempo alguna de las teclas especiales: Shift
(maysculas), Ctrl o Alt.
El valor de las teclas KeyCode se puede ver en la ayuda o pulsando F2, como te indiqu antes, entre
otras teclas, adems de las normales, se pueden detectar las teclas de funcin (F1, F2, etc), las teclas
de bloqueo de maysculas, bloque numrico, etc.
Los valores del parmetro Shift son los mismos que en el evento del ratn, es decir: 1 para Shift, 2 para
Control, 4 para Alt y la combinacin de estos valores, psate por la entrega anterior para ver esos
valores.
Debes tener en cuenta que el evento KeyDown se produce cuando se presiona la tecla y KeyUp cuando
se suelta; segn que casos, puede ser interesante hacer las comprobaciones en uno u otro evento. Por
ejemplo, podras hacer algn tipo de efecto cuando se pulsa la tecla y otro diferente cuando se suelta...

Si quieres tener un control sobre las pulsaciones de las teclas, puedes querer comprobarlas de forma
genrica antes de que sean enviadas al control en el que se produce, hay una forma de hacerlo, para
que sea el formulario el que las reciba antes... Para ello debers asignar un valor TRUE a la
propiedad KeyPreview del formulario en cuestin. Ahora cada pulsacin de teclas sern procesadas
primero por los eventos Keyxxx del formulario y despus por esos eventos del control que tenga el foco.
Aunque si un botn tiene asignada a TRUE la propiedad Default, no se procesarn esas pulsaciones en
el formulario.
Vamos a ver un ejemplo para detectar la pulsacin de la tecla ESC y si esta se produce, mostrar un
cuadro de dilogo que preguntar si queremos terminar la aplicacin... no es algo comn hacer esto,
pero en algunas ocasiones puede ser interesante poder terminar una aplicacin al pulsar ESC, dnde
utilizar esta forma de "cerrar" un programa ser cuestin tuya. Esto tambin se consigue teniendo un
botn con la propiedad Cancel = TRUE, si ese botn se encarga de cerrar el programa, ya no tendrs
que hacer nada ms... pero vamos a suponer que no tenemos ese botn y queremos cerrarlo al pulsar
ESC.
Tambin veremos cmo pasar al siguiente control cuando pulsemos INTRO; aunque esto slo ser
posible si tenemos asignada a TRUE la propiedad TabStop de cada uno de los controles que estn en
ese formulario.
Para este ejemplo, vamos a crear un nuevo proyecto, automticamente se aade Form1. Ahora
insertaremos varios controles, que realmente no harn nada, pero as veremos cmo funciona todo esto.
Veamos aade 2 CommandButtons, 2 TextBoxes y un par de Labels.
Te voy a explicar es cmo suelo "manejar" los controles cuando los inserto en un formulario, que
tamaos suelo usar, que posicin, etc. Normalmente suelo usar unos tamaos "predefinidos" para los
controles:
Los Labels suelo darles una altura de 255, 285 315 a los TextBoxes y 375 405 a los
CommandButtons.
El ancho depender del contenido que vayan a tener, en los botones suelo dejarles el ancho por defecto:
1245
La separacin de los puntos del grid, los suelo tener definidos a 30x30 puntos. Es decir que si muevo los
controles o les cambio el tamao, suelo trabajar con valores de 30 puntos (twips?). Si quieres cambiar
el valor 120 que es el que tiene el VB por defecto, haz lo siguiente:
Selecciona el men Tools (Herramientas), te mostrar un cuadro de dilogo, selecciona la solapa
General, vers que hay una serie de opciones para manipular el "grid" que se muestra durante el diseo
de los formularios. Si no has cambiado nada, tendrs seleccionada las dos opciones que hay, en ingls
dice lo siguiente: (es que ahora tengo instalado el VB en ingls, as que si la traduccin que te doy no
coincide con lo que te muestra... intenta encontrarlas)
--Show Grid (Mostrar Grid o rejilla),

--Align controls to Grid (Ajustar los controles al grid)


Tambin hay dos cajas de texto para indicar la separacin de los puntos mostrados en el grid, estos son
los valores que tendrs que cambiar.
Aunque en las aplicaciones simples no hay que preocuparse por los recursos que usemos, no est de
ms acostumbrarse a aprovecharlos, as nos ser ms fcil acostumbrarnos. Una forma de ahorrar esos
recursos del sistema es usando arrays de controles, al menos siempre que sea posible. Por ejemplo los
labels son unos controles que nos permiten usar arrays sin demasiadas complicaciones, ya que
normalmente se suelen usar para poner ttulo a las cosas y poco ms. En los casos en que uso los labels
para mostrar informacin, puede que no use un array, pero por regla general uso arrays de labels.
Para crear un array de cualquier control, se puede hacer de la siguiente forma: (esta es la que yo uso,
porque entre otras cosas, me mantiene los tamaos que le asign)
Inserta un label, se crear Label1, seleccionalo, asigna el tamao que quieres que tenga, copialo,
(pulsando el botn dereho del ratn y seleccionando Copiar), ahora pulsa en cualquier parte del
formulario y selecciona pegar. Te preguntar si quieres crear un array de Label1 (o el nombre que le
hayas dado), dile que Si y ya lo tienes creado.
La diferencia entre dos labels, (o cualquier otro control), diferentes y dos que estn en un array es, entre
otras, estas:
Controles diferentes

Un Array de Controles

Nombre

Cada una tendr un nombre diferente:


Label1, Label2, etc.

Eventos

Cada control tendr su propio juego de


eventos.

Todas tienen el mismo nombre, pero se


debe usar un ndice para indicar a cual
nos referimos.
Label1(0), Label1(1), etc.
Todos los controles comparten el mismo
evento, pero ese evento incluir un nuevo
parmetro que ser el ndice dentro del
array del control que lo ha producido.

La ventaja de usar arrays es que slo tienes que incluir cdigo en un slo evento, ya que todos los
controles en ese array comparten el mismo "nombre". Pero an as, cada uno de los controles genera su
propio evento. Para poder distinguirlos hay que usar el ndice del array, as si el evento lo ha producido el
que tiene el ndice cero, el parmetro Index valdr cero.
Vamos a ver cmo se mostrara esos eventos en la ventana de cdigo:
Private Sub Label1_MouseMove(Index As Integer, Button As Integer, Shift As Integer, X As Single,
Y As Single)
Los parmetros son los mismos que si no estuviesen en un array, con la diferencia de que ahora se
incluye uno nuevo: Index.
Como te he comentado, ste parmetro es el que nos indicar el control que ha recibido el evento. Para
poder hacer cosas diferentes segn el control que sea, se puede usar una serie de If...Then o Select
Case...End Select, segn tus gustos.
Por ejemplo, en el evento Click de un array de Labels:
Private Sub Label1_Click(Index As Integer)
'Para saber en que etiqueta se ha hecho click:
Select Case Index
Case 0
'Se ha hecho Click en el label de ndice cero
Case 1
'Se ha hecho Click en el label de ndice uno
End Select
End Sub
Esto mismo es aplicable a los TextBox que tengan algn tipo de relacin, la ventaja, como puedes ver es
que comparten los mismos eventos, en algunos casos tendrs que saber el control que se est
procesando, pero en otros no, por ejemplo, si tienes un array de TextBoxes y quieres que se seleccione
todo el texto al recibir el foco, esto se consigue aadiendo el siguiente cdigo en el evento GotFocus:
Private Sub Text2_GotFocus()
'Seleccionar el texto que haya en el Text2
'Si usamos With, es ms cmodo codificar, ya que no hay
'que estar escribiendo el nombre del control.

With Text2
'Posicin incial de la seleccin: cero, el primer caracter
.SelStart = 0
'Seleccionar todo el texto:
'esto se averigua con la longitud del contenido de la
'propiedad Text
.SelLength = Len(.Text)
End With
End Sub
Si tuviesemos un array de Text1, hariamos lo mismo, pero simplemente cambiando el nombre del control
que ponemos despus del With:
Private Sub Text1_GotFocus(Index As Integer)
'Seleccionar el texto que haya en el Text1(Index)
'Si usamos With, es ms cmodo codificar, ya que no hay
'que estar escribiendo el nombre del control.
With Text1(Index)
'Posicin incial de la seleccin: cero, el primer caracter
.SelStart = 0
'Seleccionar todo el texto:
'esto se averigua con la longitud del contenido de la
'propiedad Text
.SelLength = Len(.Text)
End With
End Sub
Fjate que el cdigo usado es el mismo que para Text2. Si tuviesemos 20 cajas de texto, tendramos que
repetir este cdigo veinte veces, una vez para cada control, pero al tener un array slo habra que
ponerlo una vez.
Otra forma de no tener que repetir el cdigo un montn de veces, sera creando un procedimiento que
hiciera ese trabajo. Veamos el cdigo para ese procedimiento:
Antes de ver el cdigo, hay que saber que el procedimiento necesita saber el control en el que se debe
seleccionar, por tanto necesitar recibir como parmetro un textbox... veamos el cdigo y espero que
captes la forma de hacerlo:
Private Sub SeleccionarTexto(unTextBox As TextBox)
'Seleccionar el texto que haya en el TextBox
'Si usamos With, es ms cmodo codificar, ya que no hay
'que estar escribiendo el nombre del control.
With unTextBox
'Posicin incial de la seleccin: cero, el primer caracter
.SelStart = 0
'Seleccionar todo el texto:
'esto se averigua con la longitud del contenido de la
'propiedad Text
.SelLength = Len(.Text)
End With
End Sub
Como puedes comprobar el cdigo es el mismo que en los ejemplos anteriores, lo nico que se cambia
es el nombre del control que est despus del WITH. El tipo de datos que se recibe como parmetro es
del tipo TextBox, ya que ese ese el tipo de control que vamos a manipular, pero si se quisiera hacer ms
genrico y poder usarlo con cualquier control que tenga una propiedad Text, podemos cambiar el tipo de
parmetro para que valga para cualquier control:
Private Sub SeleccionarTexto(unTextBox As Contol)
De esta forma, lo mismo dar usar un RichTextBox, un ComboBox o un control que disponga de las
propiedades usadas.

Para usar este procedimiento, hariamos lo siguiente en el evento GotFocus de los controles en los que
queremos seleccionar al recibir el foco:
'Para el Text2:
Private Sub Text2_GotFocus()
'Llamamos al procedimiento, usando como parmetro
'el control Text2
SeleccionarTexto Text2
End Sub
'Para el array Text1:
Private Sub Text1_GotFocus(Index As Integer)
'Llamamos al procedimiento usando el Text1 correspondiente,
'en ese caso hay que indicar el ndice.
SeleccionarTexto Text1(Index)
End Sub
En el caso del Text1, que es un array, se pasa el TextBox que ha recibido el foco: por tanto hay que
indicarlo con el ndice.
Bueno, vamos al tema, que me estoy despistando un poco... aunque esto tena que contartelo algn da,
as que tampoco ha venido mal del todo... verdad?
Para que un formulario procese la pulsacin de las teclas antes que los controles, hay que asignar a la
propiedad KeyPreview el valor True. Haz click en el formulario, selecciona la ventana de propiedades,
(pulsa F4 si no est visible), busca la propiedad KeyPreview y selecciona True ya que por defecto el valor
es False.
Aade el siguiente cdigo al cdigo del formulario:
Private Sub Form_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyEscape Then 'Se ha pulsado ESC
'Descargamos el formulario
Unload Me
ElseIf KeyAscii = vbKeyReturn Then 'Se ha pulsado Intro
'Borramos la tecla pulsada para que no "pite"
KeyAscii = 0
'Enviamos una pulsacin TAB
SendKeys "{TAB}"
End If
End Sub
Nota: Lo de la pulsacin del Intro no funcionar con los botones ni con las cajas de texto que tengan un
valor True en la propiedad MultiLine, ya que el Intro se usa para cambiar de lnea.
El orden de tabulacin, es decir que control recibir el foco cuando se pulse la tecla TAB, estar indicado
por el valor de la propiedad TabIndex de cada uno de los controles. Ese valor se cambia de forma
automtica cuando se modifica el valor de otro control. Al principio tiene el valor segn los controles
aadidos, pero si quieres cambiarlo, puedes modificar ese valor, sabiendo que el primer control que
recibir el foco ser el que tenga el valor cero y despus los que tengan el 1, 2, etc.
Las etiquetas no reciben el foco, pero tienen esa propiedad, entre otras cosas, es interesante que la
tengan, ya que lo que hacen es pasar el foco al control que tenga el valor siguiente dentro del TabIndex.
Normalmente se le suele dar a una etiqueta el TabIndex anterior al textbox que tenga "asociado", o al
que le est dando el ttulo, en caso de que esa sea su "utilidad".
Pero no podemos darle el foco a una etiqueta.
Entonces que utilidad tiene que tenga la propiedad TabIndex?
Que podemos usar una tecla de acceso rpido y si pulsamos esa "tecla" el foco pasar al control
siguiente.
Vamos a verlo con un ejemplo.
En el formulario habamos aadido dos labels: Label1(0) y Label1(1)
Selecciona la primera y escribe lo siguiente en la propiedad Caption: &Nombre, comprobars que la N
est subrayada, pues esa es la tecla de acceso rpido, para poder acceder a una tecla de acceso rpido

tendrs que pulsar Alt+tecla, en este caso Alt+N.


Selecciona la otra etiqueta y asignale esto en el caption: &Edad. Para poder usar este acceso rpido
tendrs que pulsar Alt+E.
Ahora vamos a poner en orden los valores de TabIndex:
Supongamos que el formulario tiene este aspecto:

--Selecciona el botn Aceptar, pulsa F4 para mostrar la ventana de propiedades, busca TabIndex y
escribe 0, pulsa Intro.
--Selecciona el botn cancelar, en la ventana de propiedades seguir estando seleccionada la misma
propiedad, escribe de nuevo cero.
--Haz lo mismo con el resto de los controles: LblInfo, Text2, Edad, Text1, Nombre
Ahora el orden de los valores de TabIndex ser: Nombre, Text1, Edad, Text2, LblInfo, Cancelar y Aceptar.
Pulsa F5 para ejecutar el programa, el foco lo recibir primero el Text1, el cual se seleccionar. Si pulsas
la tecla TAB vers que el foco va cambiando a Text2, Cancelar y Aceptar, para volver a Text, etc.
Prueba pulsando Intro cuando ests en alguno de los TextBoxes y vers que se cambia el foco al
siguiente control.
Para terminar con las pruebas, pulsa Alt+N y vers que el control que recibe el foco es el Text1, despus
pulsa Alt+E y el que reciba el foco ser el Text2.

Bueno, creo que ya est bien por hoy, no sea que te acostumbre a esto de las entregas largas y no es
cuestin.
En la siguiente entrega veremos algunos eventos ms y con ello concluiremos esta tanda, para pasar a
ver algo sobre las propiedades de los controles y algunas otras cosillas... como adelanto, para tu
tranquilidad, te dir que ya tengo "manuscritas" tres entregas ms y algunos "esbozos" para otras
cuantas... as que no te lo tomes con demasiada calma que voy a seguir dndote la lata...

Curso Bsico de Programacin


en Visual Basic
Entrega Veinticuatro: 10/Oct/98
por Guillermo "guille" Som
Si quieres linkar con las otras entregas, desde el ndice lo puedes hacer

Son muchas las cosas que ocurren en una aplicacin mientras el usuario est trabajando, (o cualquiera
sabe lo que estar haciendo). Ya vimos algunos eventos relacionados con el ratn, pero tambin habr
muchos otros relacionados con el teclado, es decir, cada vez que el usuario pulse una tecla se
producirn varios eventos, que la tecla se mantiene pulsada, que la tecla se ha soltado... en resumen
que la tecla se ha pulsado. Tambin se puede saber cuando una serie de teclas se pulsan al mismo
tiempo, realmente cuando se pulsan algunas de las "especiales": Shift, Ctrl o Alt.
Bsicamente son tres los elementos que la prctica totalidad de los controles y formularios reconocen:
KeyDown, KeyUp y KeyPress, vamos a verlos por separado y con algo de detalle, adems de algn
ejemplo aclaratorio.

Evento KeyPress.
Este evento se produce cada vez que una tecla se pulsa, al menos una tecla normal... ya que las teclas
"especiales" no se consideran normales y no se suelen detectar en este evento, salvo que se use junto a
una tecla "normal".
Veamos que informacin acepta este evento como parmetro:
Private Sub Text1_KeyPress(KeyAscii As Integer)
El parmetro KeyAscii nos indicar el cdigo de la tecla pulsada, este cdigo nos lo da como valor
numrico, no como una cadena, es decir que si pulsamos la tecla A mayscula, valdr 65, ya que ese es
el valor ASCII de ese caracter, (realmente es un valor ANSI, pero...).
Para saber el valor de las teclas, puedes pulsar F2 en el IDE del Visual Basic y buscar las constantes de
KeyCode o en la ayuda busca la palabra KeyCode, de todas formas los valores Ascii se pueden saber o
usar con la funcin ASC, por tanto se puede hacer una comparacin de este tipo:
If KeyAscii = Asc("A") Then
'se ha pulsado la A mayscula
End If
En este evento se pueden detectar un montn de teclas, todas las alfanumricas y otros caracteres,
adems de la tecla INTRO (return), aunque tendrs problemas con la tecla TAB, ya que esta tecla tiene
un significado especial y no es tan fcil de detectar...
Normalmente se suele detectar la pulsacin de la tecla INTRO, entre otras cosas porque suele emitir un
pitido cada vez que se pulsa, al menos en las cajas de texto... para evitar ese "pitido", se puede hacer
esto:
If KeyAscii = vbKeyReturn Then
KeyAscii = 0
'Eliminamos el pitido
End If
Con esta asignacin, lo que hacemos es indicarle al VB que no se ha pulsado nada... o al menos decirle
que no tenga en cuenta que se ha pulsado esa tecla.
Otra de las cosas que se suele hacer cuando se pulsa INTRO es pasar al siguiente control, de la misma
forma que si hubiesemos pulsado la tecla TAB, esto se suele hacer ms a menudo de lo que parece,
sobre todo para usuarios que estn acostumbrados a usar programas de MS-DOS, para conseguirlo,
adems de tener "conectada" la propiedad TabStop de los controles, (si esta propiedad tiene el valor
FALSE no se puede usar TAB para cambiar de control), tendremos que decirle al Windows que lo que se
ha pulsado no ha sido el INTRO sino el TAB... es decir con algo como esto:
If KeyAscii = vbKeyReturn Then
KeyAscii = 0
'Eliminamos el pitido
'si queremos pasar al siguiente control
'tal como lo haramos pulsando la tecla TAB:
SendKeys "{TAB}"
End If

Es decir, usamos la instruccin SENDKEYS para que envie una tecla TAB...
Para ver que teclas podemos "enviar" con SendKeys, consulta la ayuda...
Por supuesto que se pueden hacer muchas otras cosas en este evento, pero eso depender de nuestra
aplicacin... y de nuestros gustos...

Eventos KeyDown y KeyUp.


Para tener un mayor control en las teclas pulsadas, se suelen comprobar en los eventos KeyDown y
KeyUp, la principal diferencia con el evento KeyPress es que en este caso no son cdigos ASCII, sino
cdigos de teclado...
Veamos los parmetros:
Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer)
KeyCode es el cdigo de la tecla, no el cdigo ASCII, aunque en la mayora de los casos coincide,
aunque no en todos.
Shift es para saber si se ha pulsado al mismo tiempo alguna de las teclas especiales: Shift
(maysculas), Ctrl o Alt.
El valor de las teclas KeyCode se puede ver en la ayuda o pulsando F2, como te indiqu antes, entre
otras teclas, adems de las normales, se pueden detectar las teclas de funcin (F1, F2, etc), las teclas
de bloqueo de maysculas, bloque numrico, etc.
Los valores del parmetro Shift son los mismos que en el evento del ratn, es decir: 1 para Shift, 2 para
Control, 4 para Alt y la combinacin de estos valores, psate por la entrega anterior para ver esos
valores.
Debes tener en cuenta que el evento KeyDown se produce cuando se presiona la tecla y KeyUp cuando
se suelta; segn que casos, puede ser interesante hacer las comprobaciones en uno u otro evento. Por
ejemplo, podras hacer algn tipo de efecto cuando se pulsa la tecla y otro diferente cuando se suelta...

Si quieres tener un control sobre las pulsaciones de las teclas, puedes querer comprobarlas de forma
genrica antes de que sean enviadas al control en el que se produce, hay una forma de hacerlo, para
que sea el formulario el que las reciba antes... Para ello debers asignar un valor TRUE a la
propiedad KeyPreview del formulario en cuestin. Ahora cada pulsacin de teclas sern procesadas
primero por los eventos Keyxxx del formulario y despus por esos eventos del control que tenga el foco.
Aunque si un botn tiene asignada a TRUE la propiedad Default, no se procesarn esas pulsaciones en
el formulario.
Vamos a ver un ejemplo para detectar la pulsacin de la tecla ESC y si esta se produce, mostrar un
cuadro de dilogo que preguntar si queremos terminar la aplicacin... no es algo comn hacer esto,
pero en algunas ocasiones puede ser interesante poder terminar una aplicacin al pulsar ESC, dnde
utilizar esta forma de "cerrar" un programa ser cuestin tuya. Esto tambin se consigue teniendo un
botn con la propiedad Cancel = TRUE, si ese botn se encarga de cerrar el programa, ya no tendrs
que hacer nada ms... pero vamos a suponer que no tenemos ese botn y queremos cerrarlo al pulsar
ESC.
Tambin veremos cmo pasar al siguiente control cuando pulsemos INTRO; aunque esto slo ser
posible si tenemos asignada a TRUE la propiedad TabStop de cada uno de los controles que estn en
ese formulario.
Para este ejemplo, vamos a crear un nuevo proyecto, automticamente se aade Form1. Ahora
insertaremos varios controles, que realmente no harn nada, pero as veremos cmo funciona todo esto.
Veamos aade 2 CommandButtons, 2 TextBoxes y un par de Labels.
Te voy a explicar es cmo suelo "manejar" los controles cuando los inserto en un formulario, que
tamaos suelo usar, que posicin, etc. Normalmente suelo usar unos tamaos "predefinidos" para los
controles:
Los Labels suelo darles una altura de 255, 285 315 a los TextBoxes y 375 405 a los

CommandButtons.
El ancho depender del contenido que vayan a tener, en los botones suelo dejarles el ancho por defecto:
1245
La separacin de los puntos del grid, los suelo tener definidos a 30x30 puntos. Es decir que si muevo los
controles o les cambio el tamao, suelo trabajar con valores de 30 puntos (twips?). Si quieres cambiar
el valor 120 que es el que tiene el VB por defecto, haz lo siguiente:
Selecciona el men Tools (Herramientas), te mostrar un cuadro de dilogo, selecciona la solapa
General, vers que hay una serie de opciones para manipular el "grid" que se muestra durante el diseo
de los formularios. Si no has cambiado nada, tendrs seleccionada las dos opciones que hay, en ingls
dice lo siguiente: (es que ahora tengo instalado el VB en ingls, as que si la traduccin que te doy no
coincide con lo que te muestra... intenta encontrarlas)
--Show Grid (Mostrar Grid o rejilla),
--Align controls to Grid (Ajustar los controles al grid)
Tambin hay dos cajas de texto para indicar la separacin de los puntos mostrados en el grid, estos son
los valores que tendrs que cambiar.
Aunque en las aplicaciones simples no hay que preocuparse por los recursos que usemos, no est de
ms acostumbrarse a aprovecharlos, as nos ser ms fcil acostumbrarnos. Una forma de ahorrar esos
recursos del sistema es usando arrays de controles, al menos siempre que sea posible. Por ejemplo los
labels son unos controles que nos permiten usar arrays sin demasiadas complicaciones, ya que
normalmente se suelen usar para poner ttulo a las cosas y poco ms. En los casos en que uso los labels
para mostrar informacin, puede que no use un array, pero por regla general uso arrays de labels.
Para crear un array de cualquier control, se puede hacer de la siguiente forma: (esta es la que yo uso,
porque entre otras cosas, me mantiene los tamaos que le asign)
Inserta un label, se crear Label1, seleccionalo, asigna el tamao que quieres que tenga, copialo,
(pulsando el botn dereho del ratn y seleccionando Copiar), ahora pulsa en cualquier parte del
formulario y selecciona pegar. Te preguntar si quieres crear un array de Label1 (o el nombre que le
hayas dado), dile que Si y ya lo tienes creado.
La diferencia entre dos labels, (o cualquier otro control), diferentes y dos que estn en un array es, entre
otras, estas:
Controles diferentes

Un Array de Controles

Nombre

Cada una tendr un nombre diferente:


Label1, Label2, etc.

Eventos

Cada control tendr su propio juego de


eventos.

Todas tienen el mismo nombre, pero se


debe usar un ndice para indicar a cual
nos referimos.
Label1(0), Label1(1), etc.
Todos los controles comparten el mismo
evento, pero ese evento incluir un nuevo
parmetro que ser el ndice dentro del
array del control que lo ha producido.

La ventaja de usar arrays es que slo tienes que incluir cdigo en un slo evento, ya que todos los
controles en ese array comparten el mismo "nombre". Pero an as, cada uno de los controles genera su
propio evento. Para poder distinguirlos hay que usar el ndice del array, as si el evento lo ha producido el
que tiene el ndice cero, el parmetro Index valdr cero.
Vamos a ver cmo se mostrara esos eventos en la ventana de cdigo:
Private Sub Label1_MouseMove(Index As Integer, Button As Integer, Shift As Integer, X As Single,
Y As Single)
Los parmetros son los mismos que si no estuviesen en un array, con la diferencia de que ahora se
incluye uno nuevo: Index.
Como te he comentado, ste parmetro es el que nos indicar el control que ha recibido el evento. Para
poder hacer cosas diferentes segn el control que sea, se puede usar una serie de If...Then o Select
Case...End Select, segn tus gustos.
Por ejemplo, en el evento Click de un array de Labels:
Private Sub Label1_Click(Index As Integer)
'Para saber en que etiqueta se ha hecho click:
Select Case Index
Case 0
'Se ha hecho Click en el label de ndice cero
Case 1
'Se ha hecho Click en el label de ndice uno

End Select
End Sub
Esto mismo es aplicable a los TextBox que tengan algn tipo de relacin, la ventaja, como puedes ver es
que comparten los mismos eventos, en algunos casos tendrs que saber el control que se est
procesando, pero en otros no, por ejemplo, si tienes un array de TextBoxes y quieres que se seleccione
todo el texto al recibir el foco, esto se consigue aadiendo el siguiente cdigo en el evento GotFocus:
Private Sub Text2_GotFocus()
'Seleccionar el texto que haya en el Text2
'Si usamos With, es ms cmodo codificar, ya que no hay
'que estar escribiendo el nombre del control.
With Text2
'Posicin incial de la seleccin: cero, el primer caracter
.SelStart = 0
'Seleccionar todo el texto:
'esto se averigua con la longitud del contenido de la
'propiedad Text
.SelLength = Len(.Text)
End With
End Sub
Si tuviesemos un array de Text1, hariamos lo mismo, pero simplemente cambiando el nombre del control
que ponemos despus del With:
Private Sub Text1_GotFocus(Index As Integer)
'Seleccionar el texto que haya en el Text1(Index)
'Si usamos With, es ms cmodo codificar, ya que no hay
'que estar escribiendo el nombre del control.
With Text1(Index)
'Posicin incial de la seleccin: cero, el primer caracter
.SelStart = 0
'Seleccionar todo el texto:
'esto se averigua con la longitud del contenido de la
'propiedad Text
.SelLength = Len(.Text)
End With
End Sub
Fjate que el cdigo usado es el mismo que para Text2. Si tuviesemos 20 cajas de texto, tendramos que
repetir este cdigo veinte veces, una vez para cada control, pero al tener un array slo habra que
ponerlo una vez.
Otra forma de no tener que repetir el cdigo un montn de veces, sera creando un procedimiento que
hiciera ese trabajo. Veamos el cdigo para ese procedimiento:
Antes de ver el cdigo, hay que saber que el procedimiento necesita saber el control en el que se debe
seleccionar, por tanto necesitar recibir como parmetro un textbox... veamos el cdigo y espero que
captes la forma de hacerlo:
Private Sub SeleccionarTexto(unTextBox As TextBox)
'Seleccionar el texto que haya en el TextBox
'Si usamos With, es ms cmodo codificar, ya que no hay
'que estar escribiendo el nombre del control.
With unTextBox
'Posicin incial de la seleccin: cero, el primer caracter
.SelStart = 0
'Seleccionar todo el texto:
'esto se averigua con la longitud del contenido de la
'propiedad Text
.SelLength = Len(.Text)
End With
End Sub

Como puedes comprobar el cdigo es el mismo que en los ejemplos anteriores, lo nico que se cambia
es el nombre del control que est despus del WITH. El tipo de datos que se recibe como parmetro es
del tipo TextBox, ya que ese ese el tipo de control que vamos a manipular, pero si se quisiera hacer ms
genrico y poder usarlo con cualquier control que tenga una propiedad Text, podemos cambiar el tipo de
parmetro para que valga para cualquier control:
Private Sub SeleccionarTexto(unTextBox As Contol)
De esta forma, lo mismo dar usar un RichTextBox, un ComboBox o un control que disponga de las
propiedades usadas.
Para usar este procedimiento, hariamos lo siguiente en el evento GotFocus de los controles en los que
queremos seleccionar al recibir el foco:
'Para el Text2:
Private Sub Text2_GotFocus()
'Llamamos al procedimiento, usando como parmetro
'el control Text2
SeleccionarTexto Text2
End Sub
'Para el array Text1:
Private Sub Text1_GotFocus(Index As Integer)
'Llamamos al procedimiento usando el Text1 correspondiente,
'en ese caso hay que indicar el ndice.
SeleccionarTexto Text1(Index)
End Sub
En el caso del Text1, que es un array, se pasa el TextBox que ha recibido el foco: por tanto hay que
indicarlo con el ndice.
Bueno, vamos al tema, que me estoy despistando un poco... aunque esto tena que contartelo algn da,
as que tampoco ha venido mal del todo... verdad?
Para que un formulario procese la pulsacin de las teclas antes que los controles, hay que asignar a la
propiedad KeyPreview el valor True. Haz click en el formulario, selecciona la ventana de propiedades,
(pulsa F4 si no est visible), busca la propiedad KeyPreview y selecciona True ya que por defecto el valor
es False.
Aade el siguiente cdigo al cdigo del formulario:
Private Sub Form_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyEscape Then 'Se ha pulsado ESC
'Descargamos el formulario
Unload Me
ElseIf KeyAscii = vbKeyReturn Then 'Se ha pulsado Intro
'Borramos la tecla pulsada para que no "pite"
KeyAscii = 0
'Enviamos una pulsacin TAB
SendKeys "{TAB}"
End If
End Sub
Nota: Lo de la pulsacin del Intro no funcionar con los botones ni con las cajas de texto que tengan un
valor True en la propiedad MultiLine, ya que el Intro se usa para cambiar de lnea.
El orden de tabulacin, es decir que control recibir el foco cuando se pulse la tecla TAB, estar indicado
por el valor de la propiedad TabIndex de cada uno de los controles. Ese valor se cambia de forma
automtica cuando se modifica el valor de otro control. Al principio tiene el valor segn los controles
aadidos, pero si quieres cambiarlo, puedes modificar ese valor, sabiendo que el primer control que
recibir el foco ser el que tenga el valor cero y despus los que tengan el 1, 2, etc.

Las etiquetas no reciben el foco, pero tienen esa propiedad, entre otras cosas, es interesante que la
tengan, ya que lo que hacen es pasar el foco al control que tenga el valor siguiente dentro del TabIndex.
Normalmente se le suele dar a una etiqueta el TabIndex anterior al textbox que tenga "asociado", o al
que le est dando el ttulo, en caso de que esa sea su "utilidad".
Pero no podemos darle el foco a una etiqueta.
Entonces que utilidad tiene que tenga la propiedad TabIndex?
Que podemos usar una tecla de acceso rpido y si pulsamos esa "tecla" el foco pasar al control
siguiente.
Vamos a verlo con un ejemplo.
En el formulario habamos aadido dos labels: Label1(0) y Label1(1)
Selecciona la primera y escribe lo siguiente en la propiedad Caption: &Nombre, comprobars que la N
est subrayada, pues esa es la tecla de acceso rpido, para poder acceder a una tecla de acceso rpido
tendrs que pulsar Alt+tecla, en este caso Alt+N.
Selecciona la otra etiqueta y asignale esto en el caption: &Edad. Para poder usar este acceso rpido
tendrs que pulsar Alt+E.
Ahora vamos a poner en orden los valores de TabIndex:
Supongamos que el formulario tiene este aspecto:

--Selecciona el botn Aceptar, pulsa F4 para mostrar la ventana de propiedades, busca TabIndex y
escribe 0, pulsa Intro.
--Selecciona el botn cancelar, en la ventana de propiedades seguir estando seleccionada la misma
propiedad, escribe de nuevo cero.
--Haz lo mismo con el resto de los controles: LblInfo, Text2, Edad, Text1, Nombre
Ahora el orden de los valores de TabIndex ser: Nombre, Text1, Edad, Text2, LblInfo, Cancelar y Aceptar.
Pulsa F5 para ejecutar el programa, el foco lo recibir primero el Text1, el cual se seleccionar. Si pulsas
la tecla TAB vers que el foco va cambiando a Text2, Cancelar y Aceptar, para volver a Text, etc.
Prueba pulsando Intro cuando ests en alguno de los TextBoxes y vers que se cambia el foco al
siguiente control.
Para terminar con las pruebas, pulsa Alt+N y vers que el control que recibe el foco es el Text1, despus
pulsa Alt+E y el que reciba el foco ser el Text2.

Bueno, creo que ya est bien por hoy, no sea que te acostumbre a esto de las entregas largas y no es
cuestin.
En la siguiente entrega veremos algunos eventos ms y con ello concluiremos esta tanda, para pasar a
ver algo sobre las propiedades de los controles y algunas otras cosillas... como adelanto, para tu
tranquilidad, te dir que ya tengo "manuscritas" tres entregas ms y algunos "esbozos" para otras
cuantas... as que no te lo tomes con demasiada calma que voy a seguir dndote la lata...

Curso Bsico de Programacin


en Visual Basic
Entrega Veinticinco: 18/Oct/98 (la entrega de plata)
por Guillermo "guille" Som
Si quieres linkar con las otras entregas, desde el ndice lo puedes hacer

Si esto de los nmeros de las entregas fuese como los aos de un matrimonio, con esta cumpliriamos las
bodas de plata, pero esto no es ningn matrimonio ni nada que se le parezca... o casi, ya que es casi
como un compromiso entre t, el lector, y yo, el profe, as que vamos a ver si seguimos llevandonos bien
para no tener que divorciarnos ni nada por el estilo.
La mejor forma de llevarnos bien es que cada uno haga lo que tiene que hacer, t estudiar y practicar y
yo dedicarme a seguir cumpliendo entregas... que por otro lado son menos pesadas que cumplir aos...
Hoy vamos a continuar con los eventos, esta ser la ltima de la serie, que ya est bien.
En la prxima entrega haremos un pequeo repaso a cmo se deben declarar las variables y algunos
otros consejos que espero que sigas a pies juntillas, o al menos los tenga casi siempre presentes... ya
vers a que me refiero, pero ahora vamos a ver esos cuantos eventos que en algunos casos es
conveniente saber utilizar.

Otros eventos.
Ya habrs comprobado que eventos hay para casi cualquier cosa, muchos de ellos no se suelen usar de
forma habitual, y siquiera los habituales. La razn es porque no siempre es necesario interceptar todos
los avisos que nos envan los controles. Segn el tipo de control y en ciertas de estancias se usan unos u
otros pero an no he visto ninguna aplicacin que necesitara manipular todo, qu digo todo, ni siquiera la
mitad de ellos. Creo que sera una locura.
Hay que saber que algunos eventos son procesados por los controles o formularios cuando ese control o
formulario est activo o recibe el foco, mientras esto no ocurra, el susodicho control estar en standby.

Evento GotFocus.
Cuando un control se convierte en activo y recibe el foco, produce el evento GotFocus, es decir que
tiene el foco de atencin del usuario; de igual forma, cuando deja de ser el control activo, hace sonar la
alarma mediante el evento LostFocus.
El control en el que suele usarse estos eventos, de forma ms habitual, es el TextBox.
Normalmente en el evento de GotFocus se suele seleccionar todo el texto que contenga, para hacerlo,
como ya vimos con "profusin" en la entrega anterior, se suele usar un cdigo como este:
Private Sub Text1_GotFocus()
With Text1
.SelStart = 0
.SelLength = Len(.Text)
End With
End Sub
Aunque ya deberas saberlo, te vuelvo a repetir lo que hacen esas lneas de cdigo:

.SelStart = 0

Le indica al control que la posicin de inicio del texto seleccionado empiece


por la posicin cero, es decir la primera letra.
.SelLength = Len(.Text) SelLength es la longitud del texto seleccionado y el valor que se le asigna es
la longitud total del texto que haya en el control.
Por tanto lo que se hace es seleccionar todo el contenido del TextBox, las propiedades SelStart y
SelLength tambin se podran usar para saber cul es el texto que hay seleccionado y poderlo usar en
los casos de bsqueda y sustitucin de palabras. Pero hay otra forma ms rpida de saberlo, mediante la
propiedadSelText del TextBox, con esta propiedad nos indica que texto es el que est seleccionado en
ese momento.
Para almacenar en una variable el texto que actualmente est seleccionado, haremos esto:
'Guardar en sBuscar el texto seleccionado en Text1
sBuscar = Text1.SelText
Evento LostFocus.
En el evento LostFocus se suele comprobar si el contenido es el que se espera que haya. Realmente es
un pequeo problema el tener que validar los datos en este evento, ya que cuando se producen,
inmediatamente hay otro control que recibe el foco y si resulta que los datos contenidos en ese control no
son los que esperbamos se intente volver a darle el foco a este control, con lo cual se producira un
evento LostFocus en el control que recibi el foco cuando el primero lo perdi y si en ese segundo
control tambin hay una comprobacin de datos y stos son errneos, tendremos tal cacao que el pobre
Visual Basic se terminar quejndose.
Aunque el que se habr quejado habr sido t, ya que me imagino que no te has enterado de lo que
acabo de decir, pero no te voy a dar un ejemplo para que lo entiendas, en vez de eso, te voy a poner un
ejercicio y as de camino practicas un poco.
Crea un proyecto nuevo, en el Form inserta dos TextBox y CommandButton, el botn se usar para salir
del programa, en cada uno de los TextBox se comprobar que el contenido no est vacio y no se
permitir salir del TextBox en cuestin si el contenido no es el que esperamos que sea, por ejemplo,
podras hacer que el primero slo admita nmeros y el segundo slo letras. Aunque esto se podra hacer
de otra forma, prefiero que lo hagas en el LostFocus, para que practiques.
Pero como te digo, si lo prefieres, puedes validar cualquier otra cosa, por ejemplo que tenga algo escrito
o cualquier otra cosa que se te ocurra... yo no suelo validar casi nada en esos eventos ya que
normalmente suelen dar ms quebraderos de cabeza que ventajas. Pero de lo que se trata es que
seas t el que decida que es lo mejor o peor para tus programas, esto es extensible a cualquier otra
cosa que yo u otra persona pueda decirte: evalualo primero y despus decide si es lo que realmente te
hace falta.
Para que realmente funcionen esas comprobaciones, asignales una cadena vacia nada ms cargarse el
formulario y aade tambin cdigo al botn de salir para que descarge el formulario, as podrs
comprobar que hasta que no se cumplan las condiciones especificadas, no dejar de "pitarte" para que
escribas lo que debes escribir.
Por supuesto, estas comprobaciones se harn en los eventos LostFocus de cada control y si el contenido
no cumple las condiciones que esperamos, habr que volver a darle el foco, usando el
mtodo SetFocus, adems de un Beep para que sepamos que los datos contenidos no son vlidos.
El cdigo a usar sera algo como esto:
Private Sub Text1_LostFocus ()
'...
'Si el contenido del control no es vlido entonces
Beep
Text1.SetFocus 'Volvemos a darle el foco
End Sub
Pruebalo y vers cmo ahora entenders lo que digo, y si no lo entiendes al menos habrs visto cmo el
Visual Basic se queja.

Bueno, vale, te pongo el cdigo que no permitir que los TextBoxes estn vacios y si est al cambiar de
control, se quedar en ese, pero como te he dicho, esto volver loco al VB.
'-----------------------------------------------------------------'Pruebas para la entrega veinticinco del curso bsico
(18/Oct/98)
'-----------------------------------------------------------------Option Explicit
Private Sub Form_Load()
'Borramos el contenido de los TextBox
Text1 = ""
Text2 = ""
'Hacemos que el Text1 sea el primero en recibir el foco
Text1.TabIndex = 0
End Sub
Private Sub cmdSalir_Click()
Unload Me
End Sub
Private Sub Text1_LostFocus()
'No permitir que el TextBox est vacio
If Len(Trim$(Text1)) = 0 Then
Beep
Text1.SetFocus
End If
End Sub
Private Sub Text2_LostFocus()
'No permitir que el TextBox est vacio
If Len(Trim$(Text2)) = 0 Then
Beep
Text2.SetFocus
End If
End Sub
Ejecuta el programa, el foco lo tendr el primer cuadro de texto, sin escribir nada, pulsa la tecla TAB para
cambiar al otro control, ver cmo el VB se vuelve turuta... Tendrs que pulsar Control+Break (Cttl+Inter)
para pararlo...
En la versin 6 del VB se incluye un nuevo evento: Validate que ser el que se use para "validar" el
contenido de un TextBox, en lugar de hacerlo en el evento LostFocus. Sobre este evento ya veremos
algo ms adelante (en unas cuantas celebraciones ms), aunque dentro de poco lo podrs vere en la
seccin sobre el VB6 que tengo en mis pginas, las cuales seguramente se sumarn en su momento a
este curso... cuando les toque el turno.

Evento Change.
Otro evento relacionado con los controles que permiten introducir informacin es: Change. Este evento
se disparar siempre que el contenido del control cambie, por tanto en un TextBox se producir si lo que
hay en la propiedad Text cambia.
Esto ya lo vimos en las primeras entregas, adems de cmo no usar este evento, para que no diese un
error de desbordamiento de la pila.

Arrastrar y Soltar controles y otros "objetos".


Pero no creas que esto terminar aqu ya que te voy a explicar algo sobre cmo arrastrar y soltar, ya que
sta es una de las peculiaridades del entorno Windows y es una de las cosillas que deberas de tener
siempre en tus aplicaciones. Aunque el ejemplo y la explicacin que te voy a dar es para el Visual Basic

5, si quieres ver cmo se hace con la versin anterior te recomiendo que te leas los trucos de mis
pginas.
Tambin te voy a dar un ejemplo de cmo hacer que se puedan mover los controles de tamao y o
posicin dentro del formulario, en tiempo de ejecucin, claro. No es perfecto, pero medio funciona, el
problema que tiene es que hay que codificar en muchos eventos, pero para ello he creado unos
procedimientos para hacer menos tedioso el tema...
La "versin" que tena antes de esta "utilidad", no permita que se soltara un control encima de otro, slo
permita que se soltasen en el formulario, osea, si en la nueva posicin haba otro control, no se dejaba
en ese sitio...
Pero como te digo, ahora va mucho mejor... despus de el evento OLEDragDrop veremos el cdigo y un
poco de explicacin.

Evento OLEDragDrop.
Veamos primero cmo hacer que nuestra aplicacin permita que se suelte un fichero y cuando se haga
se muestre en un TextBox, por tanto no pruebes con ficheros que no sean de texto.
Para poder hacer esto, hay que asignar las siguientes propiedades del Form y del TextBox que mostrar
el texto:
OLEDropMode = 1 ' Manual
El TextBox debera ser Multiline para que se muestre bien el fichero soltado.
Para asignar a un TextBox el primer fichero de los que se sueltan en un formulario o cualquier control que
tenga la propiedad OLEDropMode igual a uno, vamos a usar un procedimiento genrico, se supone que
ser para ficheros de texto, incluso documentos RTF si el control en cuestin es un RecichTextBox.
Private Sub AsignarFichero(unTextBox As Control)
'Asignar al TextBox indicado el contenido del fichero soltado
Dim sFic As String
Dim nFic As Long
Dim sText As String
'Asignar slo el primer fichero
sFic = Data.Files(1)
'Abrirlo y leer el contenido
nFic = FreeFile
Open sFic For Input As nFic
sText = Input$(LOF(nFic), nFic)
Close nFic
'Asignarlo al control indicado
unTextBox = sText
End Sub
Para usar este procedimiento, lo llamaremos desde el evento OLEDragDrop del formulario y del control
en cuestin:
Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, _
Button As Integer, Shift As Integer, X As Single, Y As
Single)
AsignarFichero Text3
End Sub
Private Sub Text3_OLEDragDrop(Data As DataObject, Effect As Long, _
Button As Integer, Shift As Integer, X As Single, Y As
Single)
AsignarFichero Text3
End Sub
Ahora ya puedes "soltar" un fichero de texto en el formulario o el TextBox y se mostrar el contenido en
ese TextBox.

Evento DragDrop y propiedad Drag,


Ejemplo de cmo redimensionar y mover controles en tiempo de ejecucin.
Ahora vamos a ver cmo mover controles por el formulario y soltarlos en la posicin deseada. Tambin
vamos a ver cmo, mediante el uso de una llamada al API de Windows, podemos hacer que un control
sea "redimensionable", la nica pega para hacer que sea redimensionable, o si lo prefieres, la nica
condicin, es que el control sea una "ventana", no te confundas, los controles en Visual Basic son
controles, pero el Windows trata a algunos de ellos como si fuesen ventanas, por ejemplo el control
TextBox es para Windows una ventana, sin embargo el control Label no lo es. Normalmente se puede
saber si un cpntrol es "ventanero" si tiene la propiedad hWnd, ya que los que no son realmente una
ventana, no tienen esa propiedad.
Veamos el cdigo y las declaraciones para hacer que todo esto pueda funcionar.
Primero te explico que en cada control hay que hacer lo siguiente en los eventos MouseDown y
DragDrop, salvo en el Form, como veremos despus, ya que en el Form slo se detectar la accin de
soltar el control:
Private Sub NombreDelControl_DragDrop(Source As Control, X As Single, Y As
Single)
EndDragDrop NombreDelControl, Source, X, Y
End Sub
Private Sub NombreDelControl_MouseDown(Button As Integer, Shift As Integer, X
As Single, Y As Single)
IniciarDrag NombreDelControl, Button, X, Y
End Sub
En los controles que no queramos permitir que se suelte, hay que "cancelar" la operacin de Drag &
Drop, por ejemplo, si tenemos un botn y no queremos que se suelte encima, habra que hacer algo
como esto:
Private Sub cmdSalir_DragDrop(Source As Control, X As Single, Y As Single)
'Cancelar la accin de soltado
CancelarDrag Source
End Sub
El procedimiento de calcular la nueva posicin se encarga de hacer las comprobaciones pertinente para
posicionar adecuadamente el control soltado; si el control que se mueve, est contenido a su vez en otro
control, no se permite que se mueva fuera de su contenedor. Esta forma de actuar puedes cambiarla si
quieres, aunque deberas tener en cuenta que el contenedor debe ser el control de destino o el
formulario en caso de que se suelte sobre el form, tambin podras hacer que al soltarse un control en
otro, el que recibe el control fuese el contenedor... todo es cuestin de que hagas pruebas y lo adecues a
tus gustos.
Una cosa que debes tener en cuenta si quieres mover los TextBox, es que no te permitir seleccionar el
texto usando el ratn, ya que al pulsarse con el ratn se llama al procedimiento que "avisa" que se est
haciendo el Drag&Drop y al dejarlo "invisible", pierde el foco, aunque esto se soluciona en el
procedimiento que calcula la nueva posicin, podras querer que no se pueda mover, ese es el caso del
Text4 del ejemplo que pongo a continuacin.
Ahora veamos el cdigo de este ejemplo,
el cdigo lo puedes conseguir pulsando en este link: codigo25.zip (6.62 KB)

'---------------------------------------------'Prueba para redimensionar Pictures


' y mover controles
(23/Sep/96)
'
'Revisado/mejorado: el 18/Oct/98

'
'Guillermo 'guille' Som, 1996-98
'---------------------------------------------Option Explicit
Dim frmName As String
Dim DY As Single
Dim DX As Single
Dim NumColumnas As Integer
Dim NumFilas As Integer
Dim bIniciando As Boolean
'Declaraciones del API para 32 bits
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As
Long
Private Declare Function SetWindowPos Lib "user32" _
(ByVal hWnd As Long, ByVal hWndInsertAfter As Long, _
ByVal X As Long, ByVal Y As Long, ByVal cX As Long, ByVal cY As Long, _
ByVal wFlags As Long) As Long
Const
Const
'
Const
Const
Const
Const

GWL_STYLE = (-16)
WS_THICKFRAME = &H40000
SWP_DRAWFRAME = &H20
SWP_NOMOVE = &H2
SWP_NOSIZE = &H1
SWP_NOZORDER = &H4

Private Sub CmdSalir_Click()


Unload Me
End Sub
Private Sub cmdSalir_DragDrop(Source As Control, X As Single, Y As Single)
'Cancelar la accin de soltado
CancelarDrag Source
End Sub
Private Sub Form_DragDrop(Source As Control, X As Single, Y As Single)
'Cuando se suelta en el form, no especificar el destino
EndDragDrop Source, X, Y
End Sub
Private Sub Form_Load()
bIniciando = True
'Asignamos el nombre del formulario, ya que lo necesitaremos
'para saber si se mueve encima del form o de otro control
frmName = Me.Name
'Hacer estos controles redimensionables,
'usando el API
CambiarEstilo PicColum(0)
CambiarEstilo Text2
CambiarEstilo Picture1
CambiarEstilo Frame1
CambiarEstilo Picture3
CambiarEstilo Picture4
CambiarEstilo Text4
Text3 = "Left= " & Text3.Left & ", Top= " & Text3.Top

'Para crear filas/columnas en un Control


NumFilas = 2
Label1(0) = "Cabecera de la colunma"
Load Text1(1)
With Text1(1)
Set .Container = PicColum(0)
.Visible = True
.Top = Text1(0).Top + Text1(0).Height
End With
Load Label2(1)
With Label2(1)
.Visible = True
.Top = Label2(0).Top + Label2(0).Height
.Caption = "Fila 2"
End With
NumColumnas = 1
bIniciando = False
End Sub
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y
As Single)
Text2.Text = "X= " & Str$(X) & ", Y= " & Str$(Y)
End Sub
Private Sub Frame1_DragDrop(Source As Control, X As Single, Y As Single)
EndDragDrop Source, X, Y, Frame1
End Sub
Private Sub Frame1_MouseDown(Button As Integer, Shift As Integer, X As Single,
Y As Single)
IniciarDrag Frame1, Button, X, Y
End Sub
Private Sub Label1_DragDrop(Index As Integer, Source As Control, X As Single,
Y As Single)
EndDragDrop Source, X, Y, Label1(Index)
End Sub
Private Sub Label2_DragDrop(Index As Integer, Source As Control, X As Single,
Y As Single)
EndDragDrop Source, X, Y, Label2(Index)
End Sub
Private Sub PicColum_DragDrop(Index As Integer, Source As Control, X As
Single, Y As Single)
EndDragDrop Source, X, Y, PicColum(Index)
End Sub
Private Sub PicColum_Resize(Index As Integer)
Dim k As Integer
Dim i As Integer
If bIniciando Then Exit Sub
'ajustar el ancho del Label y los texts
Label1(Index).Width = PicColum(Index).Width
For i = 0 To NumFilas - 1
k = i * NumColumnas + Index
Text1(k).Width = PicColum(Index).Width
Next
PicColum(0).Left = Label2(0).Width
For i = 0 To NumColumnas - 1
If i > 0 Then
PicColum(i).Left = PicColum(i - 1).Left + PicColum(i - 1).Width
End If

PicColum(i).Top = 0

Next
End Sub

Private Sub Picture1_DragDrop(Source As Control, X As Single, Y As Single)


EndDragDrop Source, X, Y, Picture1
End Sub
Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As
Single, Y As Single)
IniciarDrag Picture1, Button, X, Y
End Sub
Private Sub Picture2_DragDrop(Source As Control, X As Single, Y As Single)
EndDragDrop Source, X, Y, Picture2
End Sub
Private Sub Picture2_MouseDown(Button As Integer, Shift As Integer, X As
Single, Y As Single)
IniciarDrag Picture2, Button, X, Y
End Sub
Private Sub Picture3_DragDrop(Source As Control, X As Single, Y As Single)
EndDragDrop Source, X, Y, Picture3
End Sub
Private Sub Picture3_MouseDown(Button As Integer, Shift As Integer, X As
Single, Y As Single)
IniciarDrag Picture3, Button, X, Y
End Sub
Private Sub Picture4_DragDrop(Source As Control, X As Single, Y As Single)
EndDragDrop Source, X, Y, Picture4
End Sub
Private Sub Picture4_MouseDown(Button As Integer, Shift As Integer, X As
Single, Y As Single)
IniciarDrag Picture4, Button, X, Y
End Sub
Private Sub Text1_DragDrop(Index As Integer, Source As Control, X As Single, Y
As Single)
EndDragDrop Source, X, Y, Text1(Index)
End Sub
Private Sub Text2_DragDrop(Source As Control, X As Single, Y As Single)
EndDragDrop Source, X, Y, Text2
End Sub
Private Sub Text2_DragOver(Source As Control, X As Single, Y As Single, State
As Integer)
'Si no se quiere que pase por encima otro control
'CancelarDrag Source
End Sub
Private Sub Text2_MouseDown(Button As Integer, Shift As Integer, X As Single,
Y As Single)
IniciarDrag Text2, Button, X, Y
End Sub
Private Sub Text3_DragDrop(Source As Control, X As Single, Y As Single)
EndDragDrop Source, X, Y, Text3
End Sub
Private Sub Text3_MouseDown(Button As Integer, Shift As Integer, X As Single,
Y As Single)
IniciarDrag Text3, Button, X, Y

End Sub
Private Sub Text4_DragDrop(Source As Control, X As Single, Y As Single)
EndDragDrop Source, X, Y, Text4
End Sub
Private Sub Text4_MouseDown(Button As Integer, Shift As Integer, X As Single,
Y As Single)
'Si se quiere poder seleccionar con el ratn
'quitar la siguiente llamada, aunque entonces no se permitir
'mover el control
'IniciarDrag Text4, Button, X, Y
End Sub
Private Sub CambiarEstilo(queControl As Control)
Dim Style As Long
On Local Error Resume Next
Style = GetWindowLong(queControl.hwnd, GWL_STYLE)
If Err Then
Err = 0
MsgBox "El control " & queControl.Name & " no permite que se
redimensione", vbInformation
Exit Sub
End If
Style = Style Or WS_THICKFRAME
Style = SetWindowLong(queControl.hwnd, GWL_STYLE, Style)
Style = SetWindowPos(queControl.hwnd, _
Me.hwnd, 0, 0, 0, 0, SWP_NOZORDER Or _
SWP_NOSIZE Or SWP_NOMOVE Or SWP_DRAWFRAME)
End Sub
Private Sub CancelarDrag(Source As Control)
Source.Visible = True
Source.Drag vbCancel
End Sub
Private
Dest As
Dim
Dim

Sub EndDragDrop(Source As Control, X As Single, Y As Single, Optional


Object)
posX As Long
posY As Long

If Dest Is Nothing Then


'Si no se especifica el control de origen,
'por ejemplo cuando se suelta en el formulario
posX = -30
posY = -30
'Si el nombre del contenedor del Source no es el nombre
'del destino, no moverlo.
'Esto ocurrir cuando se mueve un control contenido en otro
'y el destino no es el control que lo contiene
If Source.Container.Name <> frmName Then
CancelarDrag Source
Exit Sub
End If
Else
'Si el control destino es el mismo que el contenedor del Source
'Esto ocurrir cuando el control que se mueve se suelta
'en el control en que est contenido
If Dest.Name = Source.Container.Name Then
posX = -60
posY = -60
Else
'Si el nombre del contenedor del Source no es el nombre

'del destino, no moverlo.


'Esto ocurrir cuando se mueve un control contenido en otro
'y el destino no es el control que lo contiene
If Source.Container.Name <> frmName Then
CancelarDrag Source
Exit Sub
End If
With Dest
'El nombre del formulario se asignar
'a la variable frmName
If .Container.Name = frmName Then
'Esto ocurrir cuando se suelte un control
'en otro que est contenido en el formulario,
'no contenido en otro control
posX = .Left
posY = .Top
Else
'Esto ocurrir cuando se suelte en un control
'que est contenido en otro control
posX = .Container.Left + .Left + 60
posY = .Container.Top + .Top + 60
End If
End With
End If
End If
'Posicionar el control soltado
With Source
.Visible = True
.Move posX + X - DX, posY + Y - DY
.Drag vbEndDrag
.ZOrder
End With
'Si el Source es un textbox, darle el foco
If TypeOf Source Is TextBox Then
Source.SetFocus
End If
'Si se van a usar RichTextBox, hacer la comparacin correspondiente
End Sub
Private Sub IniciarDrag(Source As Control, Button As Integer, X As Single, Y
As Single)
If Button = vbLeftButton Then
DX = X
DY = Y
Source.Drag vbBeginDrag
'Cambiar a no visible, ya que si no,
'el form no detectara que se ha soltado,
'si el puntero del ratn no sale del control.
Source.Visible = False
Source.Drag
End If
End Sub
Hasta aqu ha llegado esta "entrega de plata", si quieres hacer un comentario, guardatelo para otra
ocasin... je, je.
Parte de esta entrega la tena escrita desde el 15 de julio de 1998, en total un folio manuscrito por las
dos caras y pasado al Word usando el ViaVoice de IBM que aunque no me entiende, (seguramente
porque yo no "dicto" bien), algo es algo y en cuanto le ensee a entenderme seguramente las entregas
llegarn con mayor rapidez. Aunque es algo "lentillo" y la verdad es que el cdigo no hay forma de
hacerselo entender, pero seguir probando a ver si logro que algn da sepa de que le estoy hablando...
al menos me rio un poco de lo que escribe cuando no me entiende...

Curso Bsico de Programacin


en Visual Basic
Entrega Veintisis: 6/Dic/98
por Guillermo "guille" Som
Si quieres linkar con las otras entregas, desde el ndice lo puedes hacer

La entrega de hoy, para quitarnos un poco la resaca de la "celebracin" de la anterior, se basar en


consejos y observaciones sobre las declaraciones de variables y otras cosillas que debers tener muy en
cuenta para no meter la pata hasta el cuello, ya que en ocasiones "nos equivocamos" por no permitir que
el Visual Basic tenga en cuenta algunas cosillas de las que "intentamos" hacer, con buena intencin,
pero que en ocasiones no son todo lo correctas que debieran. No soy el nico que te dar o que ha dado
estos consejos, ya que todos los programadores que llevamos algn tiempo con el VB solemos hacerlo,
entre otras cosas porque nos da algo de "rabia" que los programadores de otros lenguajes, (lase
Pascal/Delphi y C/C++), se rian de que el Visual Basic es muy propenso a errores tipogrficos...
realmente no lo dicen de esta forma, pero el caso es que se quejan de que este lenguaje no "obligue" a
declarar las variables, lo malo que tienen "esos" programadores es que realmente no conocen el Visual
Basic, al menos no lo habrn visto a fondo o no lo han tocado desde la versin 2... pero para eso
estamos aqu los que si lo hemos "estudiado" y lo seguimos haciendo, para que los menos "expertos"
aprendan lo ms rpido posible y sobre todo lo mejor posible...
Como te comentaba muchos de los errores tipogrficos se solucionan usando una instruccin, que ya te
he comentado en otras ocasiones a lo largo de este curso, interminable, de Visual Basic y no es otra que:
Option Explicit.
Cuando insertamos esta instruccin al principio de un mdulo, ya sea del cdigo de un formulario,
mdulos BAS o de cualquier otro, el VB nos obliga a declarar las variables que usemos. Algunos pueden
ver eso de no tener que declarar las variables como una ventaja del VB, pero a la larga tener que
declarar las variables antes de usarlas, es algo que se agradece... cosa que comprobars en cuanto leas
un poco ms de esta entrega.
De todas formas, no tienes porqu estar incluyendo esta instruccin en cada mdulo, el Visual Basic
puede hacerlo por t de forma automtica cada vez que aadas un nuevo mdulo o formulario en tu
aplicacin. Este automatismo no es un valor por defecto en las versiones anteriores al VB6, (en esta
versin ya lo es y se agradece, al menos para que los que empecis lo tengais por defecto), pero puedes
hacer que lo sea, para ello tendrs que marcar la opcin que para ello tiene el IDE del VB en el men
Herramientas/Opciones en la solapa Editor estar "Require variable declaration" (al menos as se llama
en la versin inglesa del VB, que es la que uso ltimamente)
Que ventajas tiene esto?
Que si te equivocas al escribir el nombre de una variable, el VB te avisar de este eerror y as ser ms
fcil solucionar problemas, te puedo asegurar que "muchos problemas".
Vamos a comprobarlo, crea un nuevo proyecto, te aadir un nuevo formulario (Form1), muestra la
ventana de cdigo y si tiene insertado Option Explicit, borralo. Muestra el form y aade un
CommandButton, aade el siguiente cdigo al evento Click de este botn:
Private Sub Command1_Click()
'
Dim SumaActual As Long
Dim i As Long

SumaActual = 0
For i = 1 To 5000
SumaActual = SumActual + 1
Next
MsgBox "El contenido de SumaActual es " & SumaActual
End Sub
Pulsa F5, haz click en el Command1 y vers que no hace lo que se espera...
Ya que si analizas el cdigo, el valor mostrado debera ser 5000, pero, no es as...
Vamos a dejar que el VB descubra el error por nosotros; para ello vamos a ejecutar de nuevo el
programa, pero esta vez aade Option Explicit al principio del mdulo, es decir en la parte de las
declaraciones generales del formulario, vuelve a ejecutar de nuevo el programa, nada ocurre... pulsa en
el botn Command1 y vers que si que haba un error tipogrfico.
Seguramente dirs que tampoco es para tanto... total, si se escriben bien los nombres de las variables...
pues s, pero cuando tengas proyectos con varios formularios y algunos mdulos de otro tipo... entonces
ya me contars si no es mejor contar con "detector de errores tipogrficos".
Seguramente te habrs fijado que al ejecutar el programa, (usando F5 o pulsando en el botn de la barra
de herramientas), el Visual Basic no te ha avisado del fallo, slo lo ha hecho cuando has hecho click en
el botn, esto est bien, pero no ayuda mucho cuando el proyecto es grande y tiene varios formularios y
varios/muchos procedimientos, ya que hasta que no se ejecute el cdigo que hay en ellos no nos avisar
del "fallo".
Pero, por suerte, esto se puede evitar... y adems de dos formas distintas.
La primera es ejecutando la aplicacin con Ctrl+F5, es decir pulsando la tecla control y al mismo tiempo
F5, de esta forma se analiza todo el cdigo antes de iniciar el programa y si el Visual Basic encuentra
algn error, te avisar.
La otra forma es indicarle al VB que "siempre" analice el cdigo antes de ejecutarlo, de esta forma es
como si siempre pulsaramos Ctrl+F5 aunque slo se pulse F5. Para que esto sea as, muestra el cuadro
de dilogo de Herramientas y en la solapa General busca la casilla "Compile on demand" (o como sea en
la versin en espaol), si est marcada esta opcin, quitale la marca, esto en proyectos grandes hace
que tarde un poquito ms al ejecutarse en el IDE, pero es porque se analiza todo el cdigo antes de
empezar la ejecucin del programa, yo ya me he acostumbrado a que siempre se compile y lo tengo de
esta form, ya que no hay nada que ms me moleste que se detenga el programa al entrar en un
procedimiento por culpa de un error tipogrfico, la verdad es que si esta opcin hubiese estado en el
Basic del MS-DOS nos hubiera evitado algn que otro quebradero de cabeza, por desgracia lleg tarde,
con el Visual Basic para DOS, pero ms vale tarde que nunca... aunque ahora casi ni se utiliza...
Para terminar con esto de las ventajas de usar Option Explicit, vamos a ver cmo saber si una variable
est en uso o no.
Bueno, no es que nos de esa informacin, pero algo parecido, la verdad es que echo de menos una
caracterstica del QuickBasic del MS-DOS y era que al pulsar F1 en una variable, nos indicaba en que
mdulos se estaba usando dicha variable, pero... aunque no existe esa forma de ver cmo est
declarada una variable en el Visual Basic, podemos usar otra forma, que es pulsando Shift+F2; te
mostrar la declaracin de esa variable... si no te muestra la declaracin, es que no est declarada.
A lo que iba, si tenemos declarada una variable, se respeta el "estado" de maysculas/minsculas de ese
nombre de variable, por tanto si en el caso del ejemplo anterior, hubiesemos escrito (todo en minsculas)
sumaactual, el VB automticamente hubiese convertido dicho nombre a SumaActual o como lo
hubiesemos escrito al DIMensionarla; esta es una de las formas de saber si ya tenemos la variable
declarada... aunque sea en otro procedimiento... el nico "fallo" es que el VB recuerda la ltima forma en
que se dimension una variable... es decir, si en un procedimiento tenemos esta declaracin:
Dim j As Integer y en otra parte de nuestro proyecto esta otra:
Dim J As Integer, el VB convertir todas las variables "j" al estado de la ltima declaracin que hayamos
usado...
Pero al menos sabremos que la tenemos declarada y de esto vamos a ver ms cosas...

Declarar las variables del tipo adecuado

Ya que estamos en esto de las declaraciones de las variables, voy a darte otro consejo, que si no estan
evidente como el anterior, en algunas ocasiones puede hacer que tu aplicacin trabaje de forma ms
eficiente... aunque no te voy a hacer ninguna demostracin, ya que la demostracin la tuviste en la
entrega cuatro.
La recomendacin es que declares las variables con el tipo adecuado, es decir, que especifiques el tipo
de la variable cada vez que la declares, si no lo haces, el Visual Basic le asignar el tipo por defecto, que
normalmente suele ser Variant y aunque ese tipo sirva para todo, no es el recomendable para muchas
ocasiones, al menos en lo que a bucles se refiere, por poner un ejemplo.
Tambin puedes especificar el tipo por defecto, esto yo lo haca siempre en mis programas de MS-DOS,
aunque ahora en Visual Basic para Windows no lo suelo hacer, ya que siempre declaro las variable del
tipo que quiero que tengan.
Pero para que lo puedas hacer, aunque me imagino que ya sabrs, te recuerdo cmo hacerlo.
Aade justo despus del Option Explicit la instruccin DEFxxx a-z, sustituye las xxx por el tipp de tu
preferencia, por ejemplo:
DefInt A-Z asignar el tipo Integer a todas las variables declaradas sin un tipo determinado; por otro lado:
DefLng A-Z har que el tipo predeterminado sea el Long.
Se pueden usar varios de estos DEFxxx usando distintos rangos de letras, ya que el Defxxx funciona de
esta forma:
Deftipo rango letras [, rango2 [, rango3, etc]]
dde tipo es Int para Integer, Lng para Long, Sng para Single, etc. (busca esta palabra en la ayuda para
ms informacin)
Los rangos son letras que le indicarn al VB que las variables que empiecen por esas letras sean del tipo
indicado, por ejemplo:
DefInt a-c, i, j
DefLng L-N, R
Declarar las variables, siempre que no se especifique el tipo, que empiecen por a, b, c, i y j como
variables Integer y las que empiecen por L, m, n y r como Long.
Por ejemplo con estas declaraciones:
Dim Ahora, Nombre As String, Longitud, Resultado As Currency
Ahora ser Integer, Longitud ser Long y las otras dos, del tipo indicado: Nombre es String y Resultado
del tipo Currency.
Pero ya te digo que prefiero declarar las variables del tipo adecuado, es decir especificando el tipo que
ser:
Dim Ahora As Integer, Nombre As String, Longitud As Long, Resultado As Currency
Yo as lo tengo ms claro, pero puedes hacerlo como prefieras.
Lo que si debes hacer es usar el tipo que realmente necesites, por ejemplo si vas a hacer bucles que no
supere el valor 32767, puedes usar una variable de tipo Integer, si quieres guardar en sDatos una
cadena, declarala como tipo String, etc.
Ya que si siempre als declaras como el valor por defecto y se te olvida aadir el DEFxxx correspondiente,
tendrs que las variables ser del tipo Variant, que entre otras cosas es ms lenta y ocupa ms memoria.
Adems de que en un futuro te ser ms fcil saber el tipo de datos que esas variables contendrn...
cosa que agradecers cuando veas de nuevo el cdigo unos meses o aos despus...
Y para que te sea ms fcil recordar que debe almacenar cada variable:
Usa nombres descriptivos para las variables
Pues eso, es ms fcil saber que la variable "Nombre" guarda un nombre que si slo usas "n"
Aunque en esto de dar nombre de las variables, coincido con otros programadores, de usar ciertas
variables "no descriptivas" para ciertas cosas, no es por nada, sino porque como todos, he aprendido
viendo cdigo de otros programadores y siempre se te pega algo del "estilo" que se va generalizando...
por ejemplo, en el uso de las variables i, j, k para los bucles.
Otro aspecto es el de usar ciertos "prefijos" para indicar el tipo y la visibilidad de las variables... en esto
no todos estamos de acuerdo, pero casi... Seguramente habrs "oido" hablar de la notacin "hungara"...
no voy a entrar en detalles de que va esto, pero si decirte ms o menos como se aplica, al menos en
algunos casos, a la hora de declarar las variables.
Para simplificar, y mucho, te dir que el prefijo es la letra o letras (normalmente tres), que se usan
delante del nombre de la variable, por ejemplo, las variables del tipo Integer se declararan as:

Dim intContador As Integer, lngContador As Long, strNombre As String, etc...


De esta forma, es fcil saber que strNombre es del tipo String, aunque no tengamos "cerca" la
declaracin de la variable.
Yo suelo abreviar el tema y suelo declararlas de esta otra forma: (como otros programadores, que no
vayas a creer que es invencin mia)
Dim iContador As Integer, sNombre As String
Con el tipo Long no siempre uso la "l" (ele minscula), entre otras cosas porque se confunde con el
nmero "1" y casi siempre suelo declarar las variables Long con "lng".
Para los otros tipos no suelo hacerlo de ninguna forma en particular, aunque el tipo "boolean" las declaro
con la letra "b".
En el caso de que las variables sean pblicas no suelo aadirle ningn tipo de identificador, ya que en el
caso de los formularios se convierten en propiedades, no entro en ms detalles en esto de las
propiedades, ya que ser el tema de la prxima entrega.
Pero esto de los prefijos no slo se aplican a las variables, tambin se hace a los controles y formularios.
Por ejemplo:
Prefijo

Control

Ejemplo

cmd

CommandButon

cmdSalir

txt

TextBoxes

txtNombre

lbl

Labels

lblStatus

chk

CheckBoxes

chkImpresora

cbo

CombosBoxes

cboCiudad

lst

ListBoxes

lstNombres

pic

PictureBox

picStatus

img

Image

imgBoton

Para los tipos definidos las declaraciones del tipo suelo empezarlos con "t_" y las variables declaradas a
partir de un tipo con "t", las enumeraciones (ya las veremos en su momento), las empiezo por "e" y las
constantes con "c"...
En el caso de las variables a nivel de mdulo, las que son visibles en todo el mdulo actual, ahora
veremos ms sobre esto, suelo anteponerle el prefijo "m_". Aunque todo hay que decirlo, no tengo un
estilo fijo en esto de nombrar a las variables y controles, aunque en la mayora de los casos, es ste el
que suelo aplicar... y cada vez con ms "consistencia", ya que a la larga te ayuda el usar algn tipo de
recordatorio del tipo/nivel de visibilidad de los controles y variables.
Para ir acabando con las recomendaciones del da, voy a darte la penltima:
Usa comentarios en tus listados
Y es que los comentarios, entre otras cosas, no ocupan espacio en el programa una vez compilado y a la
larga, siempre es a la larga, ya que cuando el cdigo est reciente, nos acordamos de todo... pero
cuando se lee despus de pasado algunos meses... puede que te ocurra lo que a mi... que al estar
revisando listados antiguos, tuve que entender lo que hacia el cdigo y despus comentarlo para que la
prxima vez que tuviese que modificarlo, me resultara ms fcil.
Por tanto, si no quieres verte en este aprieto, usa y abusa de los comentarios, aunque sea un poco
"pesado", te repito que se agradece, sobre todo si el cdigo cae en manos de otro programador, por
ejemplo en un grupo de trabajo y tiene que entender lo que "pretendas" hacer...

Y para acabar esta entrega "sermonstica" y casi de repaso, vamos a ver el tema de la visibilidad de las
variables o el "alcance" que estas tienen dentro del mdulo e incluso del proyecto completo.
De que va esto de la visibilidad?
Esto va de que cuando se declaran las variables, estas no estn visibles en toda la aplicacin...
AH! que lo que no entiendes es lo de "visible"...
Te lo explico con un ejemplo:
Supn que tienes un procedimiento que cuenta el nmero de veces que una letra est en una cadena,

por ejemplo en "Visual Basic" la letra "a" est dos veces, talvez no tenga mucha utilidad este ejemplo,
pero...
'
Public Function CuantasVeces(ByVal sCadena As String, _
ByVal sLetra As String) As Long
'Esta funcin devolver el nmero de veces que est
'la letra sLetra en la cadena sCadena
Dim i As Long
Dim nVeces As Long

'Variable para el bucle


'variable temporal para el nmero de veces

'bucle para recorrer la cadena completa


For i = 1 To Len(sCadena)
'Si el caracter comprobado es la letra buscada
'(se supone que sLetra es slo un caracter)
If Mid$(sCadena, i, 1) = sLetra Then
'incrementar el nmero de veces
nVeces = nVeces + 1
End If
Next
'Devolver el total de veces
CuantasVeces = nVeces
End Function

En este cdigo hay dos variables declaradas: "i" y "nVeces", pues bien, estas variables slo son visibles
dentro de esta funcin, es decir, que no tendrn nada que ver con otras variables que tengan el mismo
nombre, y estn declaradas en otros sitios.
Talvez este ejemplo "solitario" no est demasiado claro. Pero es un fallo que muchos "cometemos", (o al
menos, algunos hemos cometido, aunque ya lo tengamos superado... o casi.)
He visto ms de un listado en el que se declara una variable en un procedimiento y despus se "intenta"
usar en otro sitio distinto en el cual "no se ve" esa variable... Por supuesto, estos problemas de
"visibilidad" se evitan usando Option Explicit... realmente no se evitan... sino que nos "obliga" (el VB) a
que lo evitemos... ya que no nos dejar usar el programa si no estn las variables "debidamente"
declaradas... o al menos declaradas aunque no sea de la forma adecuada... (ver ms arriba lo que
comento sobre usar el tipo adecuado).
Vamos a verlo con un ejemplillo... para que te des cuenta de lo que podas haberte evitado si usaras el
Option Explicit... y si an no te ha dado tiempo a comprobarlo, porque eres de los que siguen "las
reglas", ahora te dars cuenta de que poda haber sido peor tu aprendizaje...
Para este ejemplo, tendrs que crear un nuevo proyecto, se aade por defecto un formulario (Form1),
aade un mdulo BAS (Module1) y escribe lo siguiente en el mdulo BAS:
'En el mdulo BAS
Option Explicit
Public sNombre As String
Public nVeces As Long
Public Sub MostrarNombre()
'Muestra el nombre y el valor de nVeces
MsgBox "El nombre es: " & sNombre & vbCrLf & _
"y se ha pulsado: " & nVeces & " veces"
End Sub

Escribe esto en el formulario (Form1) que tendr un TextBox (Text1) y botn (Command1):
'En el Form1
Option Explicit

'Esta variable es "privada" y visible slo en este formulario


Private nVeces As Long
Private Sub Command1_Click()
'Declaramos una variable "privada",
'y por tanto slo es "visible" dentro de este procedimiento
Dim sNombre As String
'Asignamos a la variable el contenido del Text1
sNombre = Text1
'incrementamos las veces que se ha pulsado en el botn
nVeces = nVeces + 1
'mostramos la informacin
MostrarNombre
End Sub

Ejecuta el programa y vers que cuando pulses en el Command1, no te muestra el nombre y las veces
siempre sern cero... aunque pulses varias veces.
Por qu ocurre esto si las variables sNombre y nVeces estn declaradas como pblicas en el mdulo
BAS?
Esto es as, porque a pesar de haber declarado esas dos variables como pblicas en el mdulo BAS, (es
decir visible en todo el proyecto), no se ha asignado nada a ellas...
Seguro?
Entonces, que pintan las asignaciones: sNombre = Text1 y nVeces = nVeces + 1 que hay en el
procedimiento Command1_Click?
Te lo explico:
El caso de sNombre es ms fcil de comprender, a saber, cuando el Visual Basic entra en el
procedimiento Command1_Click, declara una variable de tipo cadena llamada sNombre, esa variable
slo es visible dentro de este procedimiento, es decir que cuando se use, el VB usar la memoria que ha
reservado al encontrarse esa declaracin, por tanto el contenido del TextBox se guardar en ese espacio
de memoria, osea: la variable sNombre del procedimiento Command1_Click.
En el caso de nVeces es parecido al de sNombre, pero en este caso la "visibilidad" de esta variable es
ms amplia que la de sNombre, ya que al estar declarada a nivel de mdulo, es visible en todo el
formulario, pero al ser privada slo ser visible, (o accesible, o disponible, como prefieras), dentro del
cdigo que est en el propio formulario y no fuera de l.
Por tanto, al llamar al procedimiento MostrarNombre, (que est declarado como pblico en el mdulo
BAS y por tanto disponible en todo el proyecto), el VB se encuentra con que queremos usar dos
variables... comprueba si est debidamente declaradas y usa los valores que contienen... es decir,
ninguno; por tanto muestra los valores por defecto... una cadena vacia y un valor cero.
Esto en ingls se llama "scope", mbito o alcance; si lo entiendes mejor es la "cobertura" que tiene esa
variable, como la de los telfonos mviles (celulares) o emisoras de radio... si no tiene cobertura en una
zona, no se escuchar en esa zona...
Vamos a ver las distintas formas de declaracin de una variable, para ver el "alcance" que tienen:
-Declaradas en un procedimiento (Sub, Function o Property)
Slo son visibles en ese procedimiento
-Declaradas Privadas (o con Dim) en un formulario o mdulo (BAS, CLS u otro tipo)
Slo son visibles en ese formulario o mdulo, incluidos todos los procedimientos de ese
mdulo, salvo la restriccin anterior.
-Declaradas Pblicas (o Globales) en un mdulo BAS
Son visibles en todo el proyecto, salvo cuando se encuentren con variables declaradas
en los casos anteriores.
-Declaradas Pblicas en formularios o mdulos de clase
Sern visibles en cualquier sitio, siempre que se preceda con el nombre del formulario o
clase... (ya veremos esto en otra ocasin)
O slo dentro de ese mdulo, como si fuesen privadas al propio mdulo.

Por tanto, las variables que tengan el mismo nombre, se usarn segn la ltima declaracin que tenga
esa variable y si est al alcance del procedimiento en el que se est usando... que lio, verdad?
Esta cercana en la declaracin de la variable se puede explicar tambin as:
Primero se usarn las que estn declaradas en el propio procedimiento
Despus las que estn en el mismo mdulo (o formulario o clase o... cuando digo mdulo, me refiero
al "sitio" en el que escribes el cdigo)
Por ltimo, las declaradas como globales o pblicas en un mdulo BAS
Hay que puntualizar que las variables pblicas declaradas en un formulario, mdulo de clase o control de
usuario, se convierten en propiedades de esos "objetos", y como sabrs para usar una propiedad de un
"objeto", debes especificar el nombre del objeto seguido de un punto y despus el nombre de la
propiedad; aunque cuando se usan en el mismo mdulo o formulario, no es necesario usar el nombre del
"objeto que las contiene", por tanto, si no se especifica el nombre del mdulo, slo son visibles dentro del
mismo mdulo en el que se han declarado.
Para que el ejemplo anterior funcionara como debe, tendrs que quitar las declaraciones que hay de las
variables sNombre y nVeces en el formulario y slo dejar las del mdulo BAS.
Pruebalo y vers que ahora si que se muestra lo que se debe mostrar.

Usar una variable indicando el mdulo en el que se han declarado


Ya que he tocado el tema de especificar el nombre del "objeto" delante de las variables, tambin se
pueden usar de esa forma y as evitariamos el tema este de la visibilidad y alcance de las variables,
aunque es algo ms "liante"...
Esta forma de usarlo fuera del mdulo en el que se ha declarado, slo es vlido si las variables son
"pblicas".
Para verlo, un ejemplo:
Crea un nuevo proyecto, se crear un formulario (Form1), aade un mdulo BAS (se crear Module1, no
le cambies el nombre al mdulo)
Escribe esto en el mdulo BAS y el formulario, segn se especifica:
'En el mdulo BAS
Option Explicit
Private pVariable As Long
'Esta variable est declarada en el Form1 y en este mdulo
Public unaVariable As Long
Public gVariable As Long
'El Form1 escribe:
Option Explicit
Private unaVariable As Long
Public otraVariable As Long
Private Sub Form_Load()
Show
'para saber si est declarada,
'selecciona la variable y pulsa Shift+F2,
'te mostrar dnde est declarada
'Esta variable es la declarada en este formulario
unaVariable = 10
'Estas variables estn declaradas como pblicas en el mdulo BAS
otraVariable = 20
gVariable = 30

'Esta otra est declarada como pblica en el mdulo BAS,


'pero como tiene el mismo nombre que la declarada en el formulario,
'para poder usarla, hay que especificar el nombre del mdulo
Module1.unaVariable = 40
'Esta dar error ya que es privada en el mdulo BAS
'(Variable no definida)
'pVariable = 50
'si se usa de esta forma:
'Module1.pVariable = 50
'se encontrar la declaracin al pulsar Shift+F2,
'pero dar error de que no se encuentra el mtodo
'Mostrar el contenido de las variables:
Print "unaVariable="; unaVariable
Print "otraVariable="; otraVariable
Print "gVariable ="; gVariable
Print "Module1.unaVariable ="; Module1.unaVariable
'Esta no se puede mostrar porque es Privada y por tanto
'slo visible dentro del mdulo BAS
'Print "Module1.pVariable ="; Module1.pVariable
End Sub

Creo que los comentarios son aclaradores, as que ejecutalo y vers lo que muestra, prueba a quitar
Module1 cuando se use y asigne a "unaVariable" y vers que el primer valor se pierde (como debe ser...).

Bueno, aunque he tardado en publicarla... al fin hemos continuado con las entregas del cursillo bsico...
La verdad es que el manuscrito era del 30 de Septiembre, empec a escribirlo en el OutLook Express
cuando estaba en Canarias el 29 de Octubre y por fin lo he acabado el 6 de Diciembre... pero ms vale
tarde que nunca... verdad?
Confio en que haya servido de algo tanta espera... as que si quieres hacer algn comentario... hazlo
pulsando en este link...

Curso Bsico de Programacin


en Visual Basic
Entrega Veintisiete: 14/Ene/99
por Guillermo "guille" Som
Si quieres linkar con las otras entregas, desde el ndice lo puedes hacer

Ha pasado un largo tiempo, verdad? aunque en otras ocasiones las esperas han sido an
ms largas, as que no te quejes demasiado... De todas formas, aunque ya lo habrs
notado, las ltimas entregas que estoy publicando ya las tena escrita desde haca un
montn de tiempo, esta en particular desde el 7 de Octubre del 98, pero la pereza unida a
la falta de tiempo... hacen que se retrasen en publicar, pero ya sabes que esto de
"mecanografiar" no es lo mio... pero ms vale tarde que nunca.
Y ahora vamos a ver de que va todo esto y a ver si vale la pena, esperar tanto...

Propiedades, mtodos... y lo que se me ocurra


Una vez vistos los eventos, al menos los ms usuales, vamos a tratar ahora
con las propiedades y mtodos de los formularios y controles.
Que es una propiedad?
Una propiedad, simplificando para que se entienda, es una informacin o
dato "propio" del objeto; por ejemplo, un "objeto" label tiene una
propiedad Caption que le indica lo que tiene que mostrar.
Las propiedades son como variables que le indican al control o formulario y
por extensin a todos los objetos, qu mostrar, cmo mostrarse o hacer
cualquier otra cosa... sino hacer, al menos tener informacin para poder
hacer algo...
Veamos ms ejemplos, as conocers algunas propiedades "comunes" a la
mayora de controles:
Width
Height
Top

Left
Visible
Enabled
Name
Tag

Caption

Text

Indica el ancho del control. Cambiando el valor de esta propiedad,


cambiamos el ancho del control... como es de suponer...
El alto del control, si queremos cambiarlo...
La posicin superior del control. Normalmente hace referencia al control
que lo contiene. Un form normal, har referencia a la posicin en la
pantalla.
La posicin izquierda del control. Mismo comentario que para Top
Si se muestra o no
Si est disponible o no.
El nombre del control u objeto.
Para usos "personalizados", es como una especie de variable que tiene
cada control, en el que podemos guardar lo que queramos y no afectar
al aspecto y/o funcionamiento del control.
Esta no est presente en todos los controles, pero es tpico para los
botones command y las etiquetas. Sirve para contener el texto a
mostrar.
Esta tampoco es comn a todos los controles, pero tambin sirve para
mostrar texto, aunque normalmente los controles que la tienen suelen
permitir que ese texto se modifique, el caso tpico son los TextBox.

Y como estas, muchas ms, para saber las propiedades que tiene un control,
busca en la ayuda y te dir las que dispone... je,je... a ver si os acostumbro
a pulsar F1 y me ahorro seguir con las entregas...
No es que yo no quiera decirtelo, pero me parece absurdo documentar algo
que ya est documentado y aunque no te lo creas bastante bien... aunque
habr algunas propiedades que necesitarn de alguna explicacin y
ejemplos... y esas, casi seguro, que las veremos.
Ahora vamos con los mtodos.
Los mtodos no son otra cosa que procedimientos (SUB o FUNCTION).
Un mtodo siempre hace algo, a diferencia de las propiedades que, aunque
tambin pueden hacer algo, su papel suele ser parecido a una variable; por

ejemplo, si queremos ocultar un formulario, llamamos al mtodo Hide, que


queremos mover el formulario, pues usamos Movecon los parmetros
correspondientes y asunto arreglado.
Es decir, son procedimientos normales y corrientes, pero su comportamiento
est relacionado con el objeto, control o formulario, al que pertenece.
Muchas veces a las funciones se las considera propiedades en lugar de
mtodos, a esta "opinin" no debes darle ms importancia de la que tiene y
centrarte en lo que realmente te interesa: aprender a usarlas e incluso a
crearlas.
Para saber ms sobre los mtodos... te digo lo mismo que con las
propiedades, pulsa F1 y leete la ayuda.

Algunas propiedades son slo de lectura, es decir que no puedes modificarla


en tiempo de ejecucin, aunque normalemente si las que puedes modificar
en tiempo de diseo, es decir cuando ests trabajando en el IDE del Visual
Basic (bien! es la primera vez que sale el nombre en lo que llevo escrito... no te preocupes,
este desvaro debe ser a causa del "catarro" que tengo)
Por ejemplo, la propiedad Sorted que le indica a un ListBox si debe mostrar
los elementos clasificados o no, es de slo lectura cuando ejecutamos el
programa, pero mientras "diseamos" el proyecto, nos permite cambiar ese
valor.
Como el ttulo de esta entrega decia: Propiedades, mtodos y lo que se me
ocurra, se me ocurre comentarte que con el VB5 y superior, puedes crearte
tus propios controles, para que? para personalizar su funcionalidad a tu
gusto o a tus necesidades... pero si no tienes el VB5, an puedes seguir
leyendo, ya que no voy a explicar nada, al menos por ahora, que no puedas
hacer con el VB4 (lo siento por los que usen VB3, aunque tampoco vendra
mal seguir leyendo).
Cuando apareci el VB4, adems de permitir crear aplicaciones de 32 bits,
tanto el Windows 95 como el Windows NT son sistemas operativos que
"soportan" aplicaciones de 32 bits, aunque tambin funcionan las de 16 bits;
sin embargo el Windows 3.xx slo soporta aplicaciones de 16 bits, aunque
con un "apao" permite ejecutar algunas de 32 bits... aunque no las de VB...
a que vena todo esto?
Como intentaba decirte antes de "desvariar", con el VB4 lleg la primera
intentona de Microsoft para hacer del Visual Basic un lenguaje orientado a
objetos, en este punto te podra contar cmo llamaban la gente de Microsoft
a esta versin del VB, pero como lo que se, lo he leido en otros libros... no
est bien que te lo cuente... como soy... verdad? (mejor te hubieras callao Guille)
Bueno, al grano. Con el Visual Basic 4 lleg un nuevo tipo de mdulo: el
mdulo de clase, el cual tiene como extensin .cls
Adems de esta nueva extensin, los proyectos de VB tambin estrenaron
"look" y pasaron de ser .MAK a .VBP (Visual Basic Project), no es que sea
una ventaja, pero al menos se les dio "personalidad" a los proyectos de VB,
ya que la extensin MAK, adems de ser usada por las versiones anteriores
de VB, tambin las usaban (y usan) los compiladores de Microsoft, tanto

para BASIC como para C/C++ y lo ms frustante del compilador del BASIC
de MS-DOS, es que exista una utilidad llamanda MAKE, (para crear los
ejecutables), que tambin las usaba... y algunas veces era un folln...
Dejemos el cuento, que algunas veces me paso con mis "pelculas"...
Para ir calentando motores, ya que no creers que te voy a explicar cmo
usar este nuevo tipo de mdulos... bueno, no te lo voy a explicar por ahora,
pero si dentro de poquitas entregas...
Vamos a ver cmo usarlo de forma "muy" genrica, para que al menos sepas
que puedes crear tus propias "propiedades" y mtodos... gracias a:
Los mdulos de clase
Aunque sin necesidad de "conocer" las clases, puedes crear tus propiedades
y mtodos en los formularios... aunque eso creo que lo tengo anotado para
una entrega posterior... (es que ahora intento adelantar trabajo y voy
preparando algo de material...)
Venga, va!... vamos a insertar un mdulo de clase:
Si tienes un proyecto abierto, en el men "project" (proyecto), selecciona
aadir mdulo de clase.
Esto crear una clase llamada Class1.
Cambiale el nombre y haz que se llame cNombre.
En el cdigo escribe esto:
Public Nombre As String
Public AoNacimiento As Integer

Con esto acabamos de crear dos propiedades, ahora vamos a ver cmo
usarlas.
Antes vamos a crear un mtodo que calcular la Edad:
Public Function Edad() As Integer
Edad = Year(Now) - AoNacimiento
End Function

Cuando queramos saber la edad que tenemos (o que tiene la clase),


simplemente le restamos al ao actual nuestro ao de nacimiento... La
funcin Now devuelve un valor que es la fecha actual (da y hora), por su
lado Year toma slo el ao de la fecha indicada...
PST! Aqu puedes hacer trampas, por ejemplo si quieres quitarte algunos
aillos:
Edad = Year(Now) - AoNacimiento -10
'Cambia el 10, por lo que quieras "rejuvenecer"
Ahora en serio, vamos a ver cmo usar esta clase.
A diferencia de los Form y mdulos BAS, las variables (propiedades) y procedimientos
(mtodos) de las clases no se pueden usar si no le hemos indicado a Visual Basic que sepa
de su existencia y no me refiero a tener que DIMensionar una variable, cosa que hay que
hacer siempre, sino a otra forma de "existencia"...
Para poder usar un mdulo de clase, tendremos que declarar una variable de una forma
parecida a como lo hacemos con el resto de tipos de datos que ya hemos visto:

Dim unNombre As New cNombre


Con esta declaracin le decimos al VB que cree una nueva (New) variable que nos permita
usar esta clase llamada cNombre.
Una vez que tenemos creado el "objeto", lo usamos de la misma forma que haciamos con
los tipos definidos:
unNombre.Nombre ="Guillermo"
unNombre.AoNacimiento = 1957
'Para mostrar la edad de este cuarentn, haremos:
MsgBox unNombre.Nombre & " tiene " & unNombre.Edad & " aos..."
Esto imprimir: (suponiedo que estamos en 1999)
Guillermo tiene 42 aos... (aunque debera decir "tendr", pero bueno...)
Ahora analiza el cdigo y deduce cmo funciona... ya que lo vamos a dejar aqu... as
parecer una teleserie y estars pendiente de la pantalla... je, je... esto es la "revancha" por
reirte de mi edad.
Nos vemos
Guillermo
P.S.
No te preocupes por la "cortedad" de esta entrega... pronto habrs ms...
P.S. 2
Si hubiese querido, me podra haber enrrollado mostrndote un montn de propiedades y
mtodos con lo cual habra "rellenado" un montn de espacio..., pero, como te dije antes,
pulsa F1 y mira lo que te dice la ayuda del Visual Basic.

Curso Bsico de Programacin


en Visual Basic
Entrega Veintiocho: 28/Mar/99
por Guillermo "guille" Som
Si quieres linkar con las otras entregas, desde el ndice lo puedes hacer

Cada vez que miro las fechas en que estn escritas las entregas y en la que las publico, me
da no se qu... pero es que no puedo hacer ms...
Aunque ahora, gracias a Encarnica, esto puede que cunda ms...
Quin es Encarnica... Encarni?, (que sino se puede mosquear...)
Es la "secretaria" de la empresa... bueno, lo de secretaria es por llamarla de alguna forma,
ya que tambin se encarga de otros menesteres administrativos... y ahora, adems, en sus
ratos libres, se atreve a pasarme a mquina mis "manuscritos"... trabajo que le dar por un
lado, entender mi letra y por otro entender el Visual Basic, lo mismo hasta aprende... je, je.
Gracias Encarni!...
No os doy un e-mail para que les deis tambin las gracias, porque no tiene, pero si quieres
agradecerselo, usa este link.
Nota: No es necesario que escribas nada, con el asunto es suficiente, pero si escribes... que
sepas que no debes incluir consultas ni nada de eso que acostumbrais a hacer cada vez que

os encontrais con un link para enviar un mensaje... este link es exclusivo para agradecer a
Encarni el que me alivie el trabajo de teclear y que las entregas aparezcan con mayor
frecuencia...

Formularios, mdulos y algo ms...


Ya habrs visto que cada vez que se crea un nuevo proyecto, por regla general, se aade un
formulario (Form1.frm) en este formulario podemos aadir algunos controles para
interactuar con el usuario es decir, que el usuario puede escribir en las cajas de texto,
pulsar botones, etc. Tambin, hemos visto, aunque sea por encima, cmo controlar y poder
interceptar algunos eventos
Pues, ya est si sabes todo eso, para que seguir?.
En nuestros proyectos, podemos tener ms de un formulario, por ejemplo, uno podra ser el
principal, el que hace la mayor parte del trabajo, otro podra mostrarnos mensajes de aviso
o el resultado de cualquier ora accin
La cuestin es que podemos usar y mostrar cuando sea conveniente otros formularios.
Vamos a ver un ejemplo, sencillito para no complicarnos demasiado la vida, en el que
veremos tres formularios este ejemplo jugar a adivinar un nmero y nos informar de las
veces que hemos jugado, etc. Tambin se podr cambiar de jugador
El formulario principal lo usaremos como punto de inicio, y nos mostrar el nombre del
jugador actual, las veces que ha jugado y los puntos conseguidos, adems tendr 3
botones, uno para cambiar de jugador, otro para jugar una partidita, y un tercero para
terminar el programa.
Usaremos otro formulario que permitir escribir el nombre del jugador, y otro ms, que
usaremos para jugar, aunque todo esto no sera necesario, pero as es ms fcil y
manipulamos ms formularios.
Necesitamos una serie de variables que sean globales a todo el proyecto, por ejemplo, el
nombre del jugador.
Esto podemos hacerlo de dos formas:
Aadiendo un mdulo bas, y declarando una variable pblica, para que sea visible en todo el
proyecto.
Otra forma sera aadiendo una variable pblica al formulario principal Tambin sera
visible en todo el proyecto, aunque para acceder a ella tendramos que indicar el nombre del
formulario
Vamos a usar el segundo mtodo, ya que al ser el formulario que se usar como punta de
entrada, siempre estar disponible.
Veamos el cdigo del formulario principal al que llamaremos frmPrincipal, para hacer esto,
haz que se muestre el formulario, pulsa F4 y en las propiedades, selecciona name
(nombre) y sustituye form1 por frmPrincipal.
A partir de ahora, cada vez que quieras referirte al formulario principal, tendrs que hacerlo
con ese nombre: frmPrincipal.
Muestra la ventana de cdigo de este formulario y aade esto (recuerdas para que sirve
Option Explicit?)
Option Explict
Public Nombre As String
Ahora nuestro formulario tiene una nueva propiedad, a la que podremos acceder desde el
resto del proyecto usndolo de esta forma: frmPrincipal.Nombre
Este formulario principal hace pocas cosas, no s por qu todos los que tienen un papel
principal suelen hacer pocas cosas

Bueno, al lio... La verdad es que lo nico que hace es llamar a otros formularios y acabar
t dirs lo que quieras, pero esto de mandar, hacer poco y adems ser el principal en
fin cosas de la vida
Vamos a aadir un nuevo formulario, que se llamar frmNombre.
Para hacerlo, selecciona el men Proyecto, Aadir formulario, selecciona uno normal y ya
est disponible para que le cambies el nombre y codifiques en l.
Recuerda: pulsa F4 y selecciona la propiedad Name, borra Form2 y escribre frmNombre.
Como te coment, este formulario jefe tiene tres botones, a los que llamar:
cmdNombre, cmdJugar, cmdTerminar; cada uno de ellos hace lo que los nombres, ms o
menos, indican.
Veamos el cdigo:
Private Sub cmdNombre_Click()
' Mostranos el form que pide el nombre
' Esto har que se muestre y no se pueda hacer otra cosa
' hasta que se cierre u oculte
frmNombre.Show vbModal
End Sub
Ya ves que hace poco, simplemente muestra otro formulario que se encargar de pedir el
nombre del jugador.
Aqu hay unas cosillas a tener en cuenta, incluso deberas tomar nota, as que toma nota
y qudate con la copla
Con Show mostramos el formulario en cuestin, fjate que se usa NombreFormulario.Show,
lo cual llama a un mtodo propio de ese formulario, que lo que hace es mostralo Otra cosa
a tener en cuanta es que si es formulario no est cargado en memoria, al usar este mtodo
se carga de forma automtica, esto lo veremos en ms ocasiones, as que... tranquilzate,
toma aire, que todo llega
El mtodo Show acepta algunos parmetros, que yo conozca son dos, ambos son opcionales
y por el momento slo veremos el primero de ellos.
ste primer parmetro del mtodo Show, lo que hace es mostrar el formulario de forma
modal o no.
Mostrar un formulario modal lo que hace es mostrar ese formulario y no hacer otra casa en
la aplicacin hasta que deje de mostrarse; es como si toda la aplicacin, (la nuestra), se
congele y slo preste atencin a lo que ocurre en ese formulario, esto es importante sobre
todo cuando es necesario esperar a que el usuario introduzca los datos necesarios

Debo reconocer que cuando empec con el Visual Basic, esto de no saber que
exista esta forma de mostrar los formularios, me dio algn que otro come-coco
Por suerte, aprend que la tecla F1 serva para algo ms que estar al lado de F2...

Cuando no necesites esperar a que el usuario introduzca datos o no sea importante que se
siga usando las aplicaciones a pesar de que se muestre ese formulario; puedes mostrarlo de
forma no modal, ese es el valor por defecto del primer parmetro, es decir que si se usa:
NombreFormulario.Show, el formulario no se muestra modal, as que ojito
A lo que vamos, usando frmNombre.Show vbModal, se muestra el formulario y se espera a
que se cierre u oculte.
Veamos lo que hace este formulario, la verdad es que tampoco hace mucho, salvo darle
informacin al formulario principal. Ahora veremos como.

El formulario frmNombre tiene este aspecto:

Un textbox para el nombre del usuario, un botn aceptar y otro cancelar


Los nombres de estos controles son: txtNombre, cmdAceptar y cmdCancelar.
Podramos haber usado la funcin InputBox para hacer esto, pero no es lo mismo
El botn cancelar simplemente descarga el formulario de la memoria con: Unload Me.
El botn aceptar tambin descarga el formulario, pero antes de eso, asigna el nombre
introducido en la propiedad Nombre del formulario principal, fjate en el cdigo para ver
como se hace:
frmPrincipal.Nombre = txtNombre
Como ya coment antes, las propiedades de un formulario se pueden acceder siempre
usando el nombre del formulario en cuestin, si no se usara cmo sabramos qu
formulario es? La nica excepcin es cuando esas propiedades se usan dentro del mismo
formulario ahora lo veremos.
Pero esto no est bien o casi si dejsemos en el textbox del formulario que se usa para
pedir el nombre, el valor que hay por defecto, es decir el que se muestra cuando se aade
el control al formulario, en este caso Text1, nos daramos cuenta que sera ms lgico
que se mostrase el nombre del usuario actual, si hubiese alguno, por tanto se debera
mostrar el nombre y as permitir usar ese nombre o escribir uno nuevo. Esto lo podemos
hacer de dos formas:
Una: cmo la propiedad Nombre del form principal es pblica, podemos asignarla al textbox
cuando se cargue el formulario que pide el nombre, es decir en el evento Load de
frmNombre:
Private Sub Form_Load()
txtNombre = frmPrincipal.Nombre
End Sub
La otra forma, sera usar la posibilidad de poder referirnos a los controles de un formulario
desde otro formulario; se har de la misma forma que para acceder a una propiedad
Veamos el cdigo, en este caso, la asignacin se hace en el procedimiento que se encarga
de mostrar el formulario frmNombre, es decir en el evento cmdNombre_Click
Private Sub cmdNombre_Click()
frmNombre.txtNombre = Nombre
frmNombre.Show vbModal
End Sub
Nota: Cuando se muestra un form modal, es importante no usar el mtodo Show dentro del
cdigo del evento Form_Load del formulario mostrado, en el caso de que se haga, el VB nos
dar un error indicndonos que no se puede mostrar un formulario que se est mostrando
en forma modal.
Espero que lo tengas claro, ya que te voy a complicar un poco ms la vida, aunque antes
veamos unas consideraciones:

Habrs oido de reutilizacin de cdigo y esas otras cosillas relacionadas con la


Programacin Orientada a Objetos, (OOP), aunque no toda las buenas formas de hacer las
cosas tienen que estar relacionadas con la OOP aunque mejor no entrar en polmica.
Si usamos el formulario tal como lo he codificado, no podrs usarlo de forma genrica,
(reutilizarlo), ya que dentro de ese cdigo se hace referencia a otro formulario es decir,
siempre que usemos frmNombre, necesitaremos tener otro formulario llamado frmPrincipal
que al menos tenga una propiedad llamada Nombre Aunque no tiene porqu ser una
propiedad como hemos visto, tambin podra ser un control pero olvdate de esto para
que no te les demasiado
Bien, cmo lo solucionamos?
Si has ledo algo sobre la programacin orientada a objetos, puede que te hayas encontrado
con palabras como encapsulacin de
Qu significa esto? Sin entrar en demasiados detalles didcticos, encapsular sera tener la
autonoma suficiente para no depender del exterior y an asi, poder funcionar o lo que es
lo mismo, al formulario frmNombre no le importa si el formulario que quiere usarlo tiene o
no una propiedad llamada Nombre, tampoco le molestar que ese formulario se llame
frmPrincipal o de otra forma.
El que tiene que saber cosas de frmNombre, ser el formulario que quiere usarlo
Qu tiene que saber?
En este ejemplo slo existe una propiedad llamada txtNombre que se encargar de
devolver el nombre introducido y tambin debera indicar que se ha cancelado aunque
esto te lo dejo, (por ahora), a ti ya veremos la respuesta ms adelante.
Veamos el cdigo tal como estara despus de todo esto que te he explicado.
Empecemos por el final, veamos el cdigo del formulario encapsulador, (frmNombre):
Option Explicit
Private Sub cmdAceptar_Click()
Hide
End Sub
Private Sub cmdCancelar_Click()
Hide
End Sub
Ahora te explico de que va esto Veamos antes el cdigo del form principal (frmPrincipal):
Option Explicit
Public Nombre As String
Private Sub cmdNombrer_Click()
frmNombre.txtNombre = Nombre
frmNombre.Show vbModal
Nombre = frmNombre.txtNombre
Unload frmNombre
End Sub
Dirs que nos hemos complicado demasiado antes era ms corto no todo van a ser
ventajas, aunque si por aadir dos lneas de cdigos ganamos un formulario que es
independiente tu decides
Aunque, personalmente, este ltimo cdigo los escribira as:
Private Sub cmdNombrer_Click()
With frmNombre
.txtNombre = Nombre
.Show vbModal
Nombre = .txtNombre

End With
Unload frmNombre
End Sub
Ahora tenemos ms lneas de cdigo, pero ganamos en claridad adems si te acostumbras
a usar With, (segn dicen), el cdigo es ms rpido, al menos cuando se hacen referencias
a objetos con distintos niveles, este no es el caso, pero ya te topars con casos de
mltiples referencias todo llegar
Antes de seguir encontrando pegas, veamos porqu ha cambiado Unload Me por Hide:
Unload

Hide

Descarga un formulario de la memoria, despus de Unload se debe


indicar el nombre del formulario. En este caso se usa Me para
indicar que se descarga el formulario en el que est esa instruccin.
Simplemente oculta el formulario, pero no lo descarga.

La diferencia est en que si descargamos el formulario, lo borramos de la memoria, por


tanto destruimos todo el contenido y lo que hubiese almacenado en los controles y esto
no es lo que nos interesa, ya que necesitamos conservar el contenido del txtNombre para
que el cdigo que use frmNombre pueda saber el nombre que se introdujo.
Un lo verdad? Pues si te las con cuatro lneas de cdigo, no sabes lo que te espera... je,
je.
Espero que te vayas quedando con la esencia y que vayas asimilando cosas no pretendas
saber programar lo que pretendo es que al final, (si es que esto puede terminar algn da),
sepas programar y por extensin saber desenvolverte con el Visual Basic.
Ahora te dejo con el ejercicio de mejorar lo presente, por ejemplo que el formulario principal
sepa que se ha pulsado en Cancelar no te comas mucho el coco y no te compliques
demasiado, intenta buscar soluciones fciles, que las hay aunque tambin puedes
complicarte la existencia y hacerlo de otra forma diferente usando otras propiedades,
por ejemplo ops! ...creo que me he pasado con la ayuda
En la prxima entrega seguiremos que ya es tarde y maana hay que currar
Pincha este link para ver una de las soluciones

Curso Bsico de Programacin


en Visual Basic
Entrega Veintinueve: 25/Abr/99
por Guillermo "guille" Som
Si quieres linkar con las otras entregas, desde el ndice lo puedes hacer

Si has notado que la entrega anterior est "inacabada" ests en lo cierto... la verdad es que
gracias a uno de los "tpicos" despistes que me caracterizan, se me fue un poco la "olla" y
cre haberla acabado, pero... no fue as, por tanto, espero que no te enfades mucho
conmigo y tengas paciencia, que pronto estar terminada... por ahora sigue con lo que hay
que al ser un tema diferente no te causar ningn transtorno cerebral... y si te lo causa...
bienvenido al club!

Esta entrega tambin ha sido "mecanografiada" por Encarnica... que ya tiene pasadas a
limpio hasta la entrega 32... aunque slo la parte explicativa, ya que el cdigo me lo deja a
mi... que ella an no sabe porgramar... as que si hay retrasos en la publicacin, es slo
culpa mia...
Tambin quiero daros las gracias, en nombre de Encarni por los que la habeis felicitado por
"ofrecerse" a pasar a limpio mis notas "ininteligibles".
Gracias otra vez Encarni!

Mens, submens, popupmens y ajuste de tamaos.


En la entrega de hoy vamos a ver cmo aadir mens a nuestros programas. Para verlo
"ejemplarizado" vamos a crear un minieditor (por fin!) pero no te hagas ilusiones... ser
tan simple que casi slo vamos a utilizar un cuadro de texto y sus posibilidades sern
bsicamente las que nos de el textbox... bueno, realmente tendr algunas ms... ya
veremos.
Para crear el programa, abre un proyecto nuevo, el el form que se crea por defecto, aade
un TextBox, asgnale estos valores a las propiedades indicadas:

Propiedad

Valor

Multiline

True

Scrollbars

3-Both

Left

Top

Name

txtEditor

Multiline para que permita ms de una lnea de texto; los dos Scrollbars para que
podamos escribir lneas de cualquier longitud y que slo cambien al pulsar
Intro; Left y Top, para que se posicione en la esquina superior izquierda del formulario.

Crear una barra de estado (StatusBar)


Vamos a aadirle al formulario un Picture para que nos sirva de Statusbar, para ello aade
un picture al proyecto, seleccinalo y asgnale la propiedad Align a 2 - Align Bottom para
que se pegue a la parte inferior del formulario. Asgnale un valor 315 a la propiedad Height,
en la propiedad BorderStyle, asignale un 0 (sin borde). Selecciona del toolbar una etiqueta
haz doble click y se insertar en el formulario. Selecciona la etiqueta y crtala (men
edicin / cortar). Selecciona el picture y pega la etiqueta (men edicion / pegar). Asgnale
estas valores a las propiedades indicadas: Height = 285, Top = 15, Left =
30, BorderStyle = 1 (con borde).
Ahora vamos a darles nombre a los controles, al TextBox llmalo txtEditor, el Picture ser
picStatus, el Label se llamar lblStatus.

Posicionar los controles automticamente en el formulario


Antes de empezar a crear los mens, vamos a indicarle al Visual Basic que "posicione"
correctamente los controles cuando el formulario cambie de tamao. Para ello, abre la
pantalla del cdigo, selecciona Form de la lista de la izquierda y Resize en la lista de la
derecha.

Cada vez que un fomulario cambia de tamao se ejecuta el evento Form_Resize, por tanto
este es el sitio en el que tendremos que codificar para adaptar los controles al tamao
adecuado. Lo que vamos a hacer es ajustar el tamao de la etiqueta al tamao del Picture y
el TexBox para que ocupe todo el tamao restante.
Pero slo haremos los clculos cuando el form no se minimice, ya que si est minimizado,
no se ve nada, as que para que vamos a ajustar el tamao de algo que no se ve; para
indicarle al VB que slo ejecute el cdigo cuando no vaya a minimizar la aplicacin usaremos
la propiedad WindowState, si esta es diferente de vbMinimized querr decir que no se ha
minimizado, as pues, aade este cdigo:
' Slo cuando no est minimizado el formulario
If WindowState <> vbMinimized Then
Y ahora empezaremos a ajustar los tamaos:
El label ser igual de ancho que el PicStatus menos 60, para que tenga un poco de "respiro"
por los lados:
'
lblStatus.Width = picStatus.ScaleWidth - 60
esta es simple, ahora haremos lo mismo lo mismo con el txtEditor:
'
txtEditor.Width = ScaleWidth
el alto ser el alto del form menos el alto del PicStatus:
'
txtEditor.Height = ScaleHeight - picStatus.Height
y ya est. Se supone que en tiempo de diseo asignaste 0 a las propiedades Left y Top del
txtEditor, aunque si quieres, puedes hacerlo en este mismo evento:
'
txtEditor.Move 0, 0
eso es lo mismo que haber asignado 0 a las propiedades Left y Top es ms rpido cambiar
el tamao de un control con Move que asignando cada una de las propiedades por separado,
ya que se usa un slo mtodo en lugar de 4 asignaciones a propiedades, as pues,
podramos haber cambiado el tamao del txtEditor de esta otra forma, aunque seguramente
sera menos "instructivo":
'
txtEditor.Move 0, 0, ScaleWidth, ScaleHeight - picStatus.Height
Vamos a probarlo :
Pulsa F5 y cambia el tamao de la ventana, vers como se "adaptan" los controles aunque
el label no parece enterarse verdad?

Para que el label se ajuste al tamao del picture, hay que ajustar ese tamao en el evento
Resize del picStatus:
'
Private Sub picStatus_Resize()
' Slo cuando no est minimizado el formulario
If WindowState <> vbMinimized Then
' Aqu se ajustar el tamao del label

' cuando cambie el del picStatus


lblStatus.Width = picStatus.ScaleWidth - 60
End If
End Sub

Algo sobre los tamaos de los controles: Diferencia entre Height/Width y


ScaleHeight/ScaleWidth
Como habrs notado, para ajustar el ancho y alto, se est
usando ScaleWidth y ScaleHeight, aunque para calcular el alto del textbox tambin se
usa picStatus.Height, en cuanto te explique que significan estas propiedades, seguro que
lo entiendes.
ScaleWidth y ScaleHeight son propiedades que nos informan del ancho y alto "interno"
del formulario o control, es decir lo que miden sin contar el borde. Width y Height, por
otro lado, nos dicen que el ancho y alto "externo" del form o control.
Cuando se calcula el alto del txtEditor necesitamos saber el alto interno del formulario
(ScaleHeight) al que hay que restarle el alto total de picStatus (picStatus.Height). Si
hubiesemos usado Height en el lugar de ScaleHeight, los clculos no nos hubiesen salido
correctos, ya en el valor devuelto por esa propiedad nos indicara el alto total del form.
Ahora mismo, tal como est el programa habra poco diferencia, aunque an as no se
ajustara perfectamente, "desajuste" que quedara demasiado evidente en cuanto aadamos
mens. (mens? No era de eso de lo que iba a tratar esta entrega).
Otro detalle es que para referirnos al alto y ancho "interno" del formulario, lo hemos usado
sin indicar nada ms, esto siempre es as cuando hagamos referencia a una propiedad de un
objeto, (en este caso un formulario), y el cdigo se ejecuta "dentro" de ese formulario. Sin
embargo cuando hacemos referencia a las propiedades de otros controles, (incluso de otro
formulario), tendremos que anteponer el nombre de ese control delante de la propiedad o
mtodo, para que el VB sepa a que control nos estamos refiriendo.
Borra la lnea que cambiaba el tamao de la etiqueta en el evento Form_Resize y vuelve a
pulsar F5, cambia el tamao del formulario, esta vez si que se adapta bien el lblStatus
dentro del picture que la contiene.
Ya puedes detener el programa, pulsando en la "x" del form. Haz que se muesre el
fomulario ya que es necesario para poder aadir mens a nuestro "mini-editor".

Aadir mens a un formulario


Como habrs observado en todas las aplicaciones de Windows, los mens se muestran en la
parte superior de las aplicaciones, esto no es ningn descubrimiento, excepcional pero la
cuestin es que si se muestran en la parte superior tendremos que hacer un nuevo clculo
al cambiar el tamao del formulario?
La respuesta es: no.
Al aadir mens a nuestro formulario, el tamao de ste se ajusta automticamente y no
tendremos que tener en cuenta el espacio que ocupa para "ajustar" los controles que
tengamos en l. Es decir, que el cdigo del Form_Resire sigue siendo vlido con o sin
mens.
Una vez aclarado este punto, antes de empezar a aadir mens, otro poco de teora pero
no te asustes, no es demasiado la teora, slo para aclarar "conceptos".

Cuando creamos mens tenemos varios "niveles", normalmente son dos: el men principal
que siempre est visible en la parte superior y los elementos que se muestran cuando
hacemos click (o pulsamos) en ese men principal. Cada vez que pulsamos en un elemento
de la "lista" de mens principal se muestran los que "cuelgan" de l. Habrs observado que
muchos de los elementos de los mens, tanto principales como secundarios, tienen una
letra subrayada, eso quiere decir que pulsando Alt ms esa letra, se despliega o selecciona
esa opcin del men, es como si pulsramos con el ratn. Cuando empiece con la
explicacin vers cmo podemos crear nuestras propias letras de acceso, incluso cmo
aadir "accesos rpidos" a algunas de las opciones de los mens, todo esto lo veremos
ahora mismo.

Cmo aadir mens a nuestro formulario (ahora si)


Para poder "disear" los mens, tienes que tener visible el formulario en el que
mostraremos los mens, as que si el formulario no est mostrado, haz que se muestre,
(haciendo dobleclick en la ventana del explorador de proyectos)
Para entrar en modo de diseo de mens, puedes hacerlo de dos formas: seleccionando del
men Tools (Herramientas) la opcin Menu Editor o pulsando el icono
herramientas. Te mostrar un cuadro de dilogo como el que sigue:

de la barra de

Las partes ms importantes son:


Caption/Descripcin que es el texto que se mostrar,
Name/Nombre del men que ser donde escribamos el cdigo a ejecutar cuando se
seleccione ese men.
Vamos a empezar por aadir un men "Fichero", (o archivo si as lo prefieres), en este
men tendremos las opciones de Abrir, Guardar, Guardar como y Salir, despus aadiremos
otras, segn convenga. Tambin tendremos otro men principal llamado Edicin con las
clsicas opciones de ese tipo de men: Deshacer, Cortar, Copiar, Pegar, etc.
Pero empecemos por el de fichero:

Escribe en el "Caption", &Ficheros, el signo & le indicar al Visual Basic que muestre
subrayada la letra que sigue a ese signo, de esa forma se podr acceder pulsando Alt y la
letra subrayada, es decir Alt+F
En el nombre del men escribe: mnuFic y pulsa Intro o en el botn Siguiente. Se
"limpiarn" las casillas de texto y estar listo para escribir las opciones de este men:
Escribe en Caption: &Abrir... y en nombre mnuFicAbrir los tres puntos suspensivos es una
norma recomendable, que indica que se mostrar un cuadro de dilogo, acostmbrate a
seguirla, de esta forma tus aplicaciones tendrn un aspecto "standard windows" (realmente
no es un estndard de windows, sino una norma anterior anterior, pero)
Despus de la opcin Abrir vamos a aadir Guardar, por tanto en el caption del men
escribimos &Guardar y en el nombre de esa opcin: mnuFicGuardar, en este caso no
aadimos los tres puntos seguidos ya que lo habitual en las opciones guardar, es guardar
sin preguntar, salvo que an no se le haya dado nombre al fichero.
Como habrs observado cada vez que aades una opcin se va mostrando en la lista
inferior. Antes de seguir vamos a ver cmo quedan nuestros mens.
Pulsa el botn "aceptar" del cuadro de dilogo del "diseador de mens".
Sorpresa!
Como puedes observar, tenemos tres opciones "principales": Ficheros, Abrir y Guardar,
pero esta no era la intencin, ya que Abrir y Guardar slo se deberan mostrar al seleccionar
el men Ficheros
Qu ha pasado?
Muy fcil, al menos cuando se sabe cmo trabaja esto de los mens, que al no indicarle lo
contrario todos los mens se muestran en la barra principal! cmo podemos crear los
submens (o mens que se muestran al seleccionar un men)?
Ahora lo veremos, antes de hacerlo, en tiempo de diseo, es decir, sin pulsar F5, pulsa en el
men Fichero. Se mostrar la ventana de cdigo, el combo de en la parte izquierda se
mostrar mnuFic y en el de la derecha vers que es el evento click, por tanto estaremos en
el procedimiento mnuFic_Click. Todo lo que escribas en este men se ejecutar cuando
selecciones esta opcin. No escribas nada, cierra la ventana de cdigo para volver a mostrar
el formulario.
Vamos a hacer que los mens se muestren como deben: al seleccionar Ficheros que se
despliegue el men con las opciones Abrir, Guardar, etc.
Entra en el diseo de mens, (esto tendrs que hacerlo siempre que quieras aadir nuevas
opciones de mens o modificar las ya existentes.)
Si te fijas en la lista inferior, vers que las tres opciones que tenemos estn alineadas a la
izquierda.
Selecciona Abrir en la lista inferior, comprobars que se "rellenan" las casillas con la
descripcin y el nombre del men, eso nos indica que est seleccionada esa opcin y que
cualquier cambio que hagamos, se har en esa opcin. S que todo esto es evidente, pero
por si no lo habas captado ahora pulsa en la flecha que seala a la derecha, esto har que
la opcin seleccionada se desplace a la derecha, esto se muestra por tres puntos delante de
Abrir, no los confundas con los tres puntos que nosotros le aadimos al final.
Haz lo mismo con "Guardar"
Cierra el cuadro de dilogo y veras que ahora slo se muestra el men Ficheros. Bien! Ya
tenemos lo que queramos! Selecciona ese men y vers que se muestran las dos opciones
que hemos aadido; en esta ocasin no se muestra la ventana de cdigo, pero ya veremos
que e evento "sigue operativo".

Pulsa en la opcin "Abrir..." y en esta ocasin se mostrar la ventana de cdigo con el


procedimiento: "mnuFicAbrir_Click", para comprobar que funciona vamos a aadir un
mensaje que se mostrar cuando seleccionemos esta opcion:
'
Private Sub mnuFicAbrir_Click()
' Abrir
MsgBox "Esta es la opcin Abrir..."
End Sub

Ahora para comprobarlo, pulsa F5 y selecciona el men Ficheros, se mostrarn las dos
opciones que tenemos en este men: Abrir y guardar. Selecciona Abrir y vers que se
muestra el mensaje, lo cual quiere decir que todo est bien.
Cierra la aplicacin y vuelve a mostrar el formulario para aadir ms opciones a los mens;
as que haz que se muestre el diseador de mens.
Selecciona la ltima de las opciones de la lista y pulsa en el botn Siguiente para que
podamos aadir ms opciones. Escribe G&uardar como... en la descripcin
y mnuFicGuardarComo en el nombre. Si esta nueva opcin se muestra en la lista
totalmente a la izquierda, pulsa en la flecha de identacin a la derecha para que est al
mismo nivel que las otras dos, es decir que tenga tres puntos delante del Caption que le
hemos dado.
Pulsa de nuevo en el botn Siguiente, ahora tendrs que escribir un guin, (signo menos),
en la descripcin del men, en el nombre del mismo escribe: mnuFicSep1, no sirve de
nada, ya que las lines "divisorias" no se pueden seleccionar, pero deben tener un nombre.
Lo que debes "recordar" es que si se indica un "-" en la descripcin del men, estamos
indicndole al VB que lo que queremos es que muestre una lnea de divisin. Pulsa en
siguiente y escribe: &Salir y mnuFicSalir (ya no es necesario que te diga dnde debes
escribirlo, verdad?)
Ya tenemos las opciones del men Ficheros, ahora vamos con el men de edicin. Aade
este men a continuacin de Salir, escribe &Edicin en el Caption y mnuEdit en el nombre.
Cuando lo hayas escrito ver que est debajo de Salir y con los tres puntos delante, si lo
dejamos as, no se mostrar en la barra principal de mens, sino que ser una opcin ms
del men Ficheros, y eso no es lo que queremos, por tanto, pulsa en la flecha que seala a
la izquierda para que se pegue totalmente a la izquierda, y desaparezcan los puntos
suspensivos que hay delante del Caption. Porque como ya vimos antes, las opciones que se
muestran en la lista y que estn sin los puntos suspensivos son las que se mostrarn en la
barra de mens. Antes de aadir opciones al men de edicin, vamos a modificar las
opciones que tenemos, insertaremos una nueva al principio, que servir para crear un
nuevo fichero. El caption, como puedes imaginar, ser Nuevo y el nombre del men
ser mnuFicNuevo.
Vamos a aadirla: asegrate que estemos en modo de diseo de mens.
La nueva opcin la vamos a insertar al principio, es decir justo antes de Abrir. Por tanto,
selecciona Abrir de la lista inferior, pulsa el botn insertar y podrs escribir la
descripcin: &Nuevo y el nombre del men: nmuFicNuevo.
Cada vez que quieras insertar una nueva opcin puedes hacerlo de esta forma o bien
aadiendo la opcin al final y despus "situarla" en el lugar correspondiente usando las
flechas arriba y abajo.
Cuando insertas una opcin, usando el botn insertar, la opcin insertada tiene la misma
"indentacin" que la que estaba seleccionada antes de pulsar en insertar. Ya sabes que
puedes modificar dicha identacin, o desplazamiento, usando las flechas de izquierda y
derecha.
Si lo que quieres es borrar un elemento de men, simplemente la seleccionas y pulsa en
"eliminar", aunque esto slo elimina la opcin del men, no el cdigo que tuviese asociado,
lo mismo ocurre cuando eliminamos o cambiamos el nombre de un control: si ya tena
cdigo en algunos eventos, este cdigo sigue estando, pero no en el sitio que debiera no

voy a seguir con esto, ya que lo veremos en otra ocasin, pero al menos cuando le llegue el
turno te "sonara"
Como ya vimos en La entrega 26 se suele seguir unas "normas" a la hora de nombrar a los
controles y variables, y si no se "suele" seguir, al menos se recomienda. En este caso los
mens se preceden con "mnu" seguido del nombre de men principal y por ltimo el
nombre de la opcin. Aunque, como todos los consejos, eres libre de seguir estas normas o
de crear las tuyas propias. En mi caso, "intento" seguir stas que te estoy indicando,
aunque algunas veces me las salto, normalmente con la opcin "Salir" que simplemente la
llamo: mnuSalir, aunque es mejor llamarlo mnuFicSalir para que sepamos que est
"incluida" en el men fic-heros.
Pero en esto de los nombre de los mens, aparte de que los puedes "nombrar" como
quieras, existe otra forma de hacerlo.
Ya vimos que se pueden crear "arrays" de controles y que la ventaja era, sobre todo si
estaban relacionados, que no necesitamos escribir el mismo cdigo para cada uno de los
eventos que queramos interceptar; simplemente usando el ndice podramos distinguir un
control de otro; pero siempre, y esa es la ventaja, en un mismo procedimiento de evento.
Pues esto mismo se puede hacer con los mens: podemos crear un array.
La nica diferencia es que se crea de forma un poco ms manual y se hace en la "ventana
de diseo de mens".

Array de mens
Para ello, se usa el mismo nombre de men, pero usando un "ndice" diferente para cada
opcin.
El nico requisito "obligatorio" es que los elementos de un array de mens han de estar
correlativos. Habitualmente se incluyen en ese array todos los elementos de un men
principal bueno, los que se muestran al seleccionar esa opcin. Y esto es lo que vamos a
hacer nosotros: incluir en un array todos las opciones del men edicin, que sern las
siguientes: Deshacer, separacin, cortar, copiar, pegar, separacin, seleccionar todo;
posteriormente aadiremos ms opciones aunque seguramente ser en otra entrega.
El nombre del array ser: mnuEditor, el primer elemento, de ndice cero, ser: Deshacer.
Vamos a aadirlo pasito a pasito, para que no tropieces y te "descalabres".
Supongo que ya estars en el diseador de mens y que la opcin seleccionada es la
ltima: Edicin.
Pulsa en el botn Siguiente y escribe en el Caption: Des&hacer, en el nombre del
men: mnuEditor, (sin acento o tilde... como prefieras llamarlo), en Index escribe 0;
pulsa el botn con la flecha a la derecha, para indicar que esta opcin pertenece al men
Edicin.
Pulsa en siguiente, si no se identa, ya sabes cmo debes hacerlo; escribe un "-" en el
Caption, mnuEditor en el nombre, pero en ndice escribe 1, ya que al llamarse de la misma
forma el men, el Visual Basic esperar encontrarse con un ndice que lo diferencie. Haz lo
mismo con el resto e las opciones y recuerda usar ndices correlativos, y por supuesto
diferentes...
Cuando hayas introducido todas las opciones, cierra el diseador de mens si te da algn
tipo de error, puede ser porque no hayas usado el mismo nombre de men para todas las
opciones del men edicin, porque no estn los ndices correlativos o porque no estn todos
indentados en el mismo nivel, es decir con tres puntos suspensivos a la izquierda (esto es lo
que se muestra en la lista y no tienes que escribirlos).
Este sera el aspecto:

Recuerda que los elementos de un array de mens deber ser correlativos y estar en el
mismo nivel de indentacin ("osease" pertenecer al mismo men).
Si todo est bien, al mostrar el formulario en tiempo de diseo, no en ejecucin, y pulsar en
el men edicin, vers que se muestra las opciones que hemos escrito. Pulsa en cualquier
de ellas y vers que siempre se muestra el mismo evento en la pantalla de cdigo:
mnuEditor_Click (Index As Integer)
El parmetro index ser el que nos indique cual de las opciones ha sido la que se ha
coleccionado.
Para poder hacer cosas diferentes segn la opcin seleccionada haremos algo como esto:
'
Private Sub mnuEditor_Click(Index As Integer)
Select Case Index
Case 0
' Deshacer
Case 2
' Cortar
' Etc...
'
End Select
End Sub

Pero para que resulte ms fcilmente entendible y modificable, en lugar de nmeros, vamos
a usar constantes, de esta forma, si aadimos o eliminamos alguna de las opciones del
men, slo tendremos que cambiar el valor de la constante y el resto del cdigo no habr
que modificarlo.
As pues, en la ventana de cdigo, selecciona la parte general de las declaraciones y aade
esto:
'
' Constantes para el men de Edicin.
' Los valores se corresponden con el ndice de mnuEditor
Const cEdDeshacer = 0
Const cEdCortar = 2

Const cEdCopiar = 3
Const cEdPegar = 4
Const cEdSeleccionarTodo = 6

Ahora las distintas opciones de "select" en el evento mnuEditor_Click quedarn as:


'
Private Sub mnuEditor_Click(Index As Integer)
Select Case Index
Case cEdDeshacer
'
Case cEdCortar
'
Case cEdCopiar
'
Case cEdPegar
'
Case cEdSeleccionarTodo
'
End Select
End Sub

Con lo cual hemos ganado en "legibilidad" en el cdigo y, aunque an no lo "sepas", en


facilidad a la hora de modificar el cdigo.
El cdigo a usar ser el contenido de la siguiente entrega, ya que esta se acaba aqu.
Adems del cdigo a usar, veremos cmo aadirle, a las opciones del men, teclas de
acceso rpido, por ejemplo:
Control + X para cortar, etc.
Pero eso ser en nuestro siguientes episodio.
Permanezca atento a la pantalla continuar.
Nos vemos
Guillermo
Manuscrito original escrito en Las Palmas de Gran Canaria el 26 de Oct de 1998

Vous aimerez peut-être aussi