Anda di halaman 1dari 143

&XUVR%iVLFRGH3URJUDPDFLyQHQ9LVXDO%DVLF

INTRODUCCIN
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 en la variables nombre, tendriamos que hacer (o casi):
Nombre =
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 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 = ""
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 ?
Podras hacer esto, multiplicar a por 7 (como no hay bastante con uno...)
Paliza = "" * 7
Pero el Basic te dira que eso no est bien, no porque (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:
= 5
Paliza = * 7
El Basic tomara el 5 y lo almacenara en ena variable numrica llamada .
Despus se encuentra con: Paliza = * 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 , es decir al ejemplo de Paliza = * 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 es 5 y 5 * 7 es 35
(y sin calculadora!!!)
Veamos si es cierto que vale 5. Haciendo Print , mostrar un 5.
LECCION 1.
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()
= 5
Paliza = * 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
Pulsa de nuevo F5 y vers que ahora adems del 35, hay un 5 debajo. El valor de la variable .
Pero, que ocurrira si cambiasemos el valor de ?
Aade estas lneas a continuacin de la anteriores, para que quede de esta forma:
Private Sub Form_Load()
= 5
Paliza = * 7
Print Paliza
Print
= 10
Print
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 , 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 = * 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()
Nombre = ""
Print Nombre
End Sub
Pulsa F5 y vers que se muestra el contenido de la variable Nombre, es decir .
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 , fijate que despus de hola y antes de cerrar las comillas hay
un espacio.
Nota: En todos Ios FORM_LOAD debers poner SHOW aI principio para
que se muestre Io que se imprime.
LECCION 2.
Seguimos con este cursillo bsico. Antes de nada una pequea aclaracin, para que los
ejemplos que se dieron en la leccin 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 leccin 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 leccin 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 leccin 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 leccin, 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 lnteger)
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.
Bueno, aqu voy a dejar la cosa, pues creo que con esto es te puedes ir "entreteniendo".
LECCIN 3.
Esta leccin 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 leccin 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 Sub Command1_Click()
Dim nlnt As lnteger
Dim nLng As Long
Dim nSng As Single
Dim nDob As Double
Dim nCur As Currency
Dim nVar As Variant

Dim timer1#, timer2 As Double
Const minBucle = 1, maxBucle = 10

Command1.Caption = "Calculando..."
timer1 = Timer
For nlnt = minBucle To maxBucle
Contar Clnt(nlnt), Label1
Next
timer2 = CDbl(Timer - timer1)
Label1 = "Duracin con lnteger: " & timer2
DoEvents

timer1 = Timer
For nLng = minBucle To maxBucle
Contar Clnt(nLng), Label2
Next
timer2 = CDbl(Timer - timer1)
Label2 = "Duracin con Long: " & timer2
DoEvents

timer1 = Timer
For nSng = minBucle To maxBucle
Contar Clnt(nSng), Label3
Next
timer2 = CDbl(Timer - timer1)
Label3 = "Duracin con Single: " & timer2
DoEvents

timer1 = Timer
For nDob = minBucle To maxBucle
Contar Clnt(nDob), Label4
Next
timer2 = CDbl(Timer - timer1)
Label4 = "Duracin con Double: " & timer2
DoEvents

timer1 = Timer
For nCur = minBucle To maxBucle
Contar Clnt(nCur), Label5
Next
timer2 = CDbl(Timer - timer1)
Label5 = "Duracin con Currency: " & timer2
DoEvents

timer1 = Timer
For nVar = minBucle To maxBucle
Contar Clnt(nVar), Label6
Next
timer2 = CDbl(Timer - timer1)
Label6 = "Duracin con Variant: " & timer2
DoEvents
Command1.Caption = "Calcular"
End Sub

Private Sub Contar(valor As lnteger, etiqueta As Control)
Dim i As lnteger
Dim unDoble As Double
Const elMaximo = 1000&

For i = 1 To elMaximo
unDoble = unDoble + 1
etiqueta.Caption = valor * elMaximo + unDoble
DoEvents
Next
End Sub
LECCIN 4.
En la segunda leccin, 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 leccin 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 leccin 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 leccin 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:
lf Contando Then
Command1.Caption = "Calcular"
Contando = 0
DoEvents
Exit Sub
End lf
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...
LECCIN 5.
No voy a dar la solucin al problema/ejercicio planteado en la leccin 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 leccin 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 leccin. 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 leccin 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
leccin, 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 leccin
anterior.
Pero, este form de la segunda leccin 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 leccin 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 lnteger
For i = 1 To 2
Print "i en contar= "; i
Next
End Sub
Ahora en el Form_Load, escribe esto otro:
Dim i As lnteger

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 lnteger)
Dim i As lnteger
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 leccin, 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 leccin 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 leccin 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 leccin.
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 lnteger
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 leccin...
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 leccin 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)
Solucin de los ejercicios de la leccin 5.
Solucin al primero, preguntar el nombre, preguntar la edad y mostrar el nombre "edad" veces:
Tenemos dos TextBoxes: Text1 y Text2, un botn: Command1, el cdigo sera:
Private Sub Command1_Click()
Dim i As lnteger
Dim j As lnteger
Dim Nombre As String

j = Val(Text2)
Nombre = Text1
For i = 1 To j
Print Nombre
Next
End Sub
El segundo es un poco ms complicado, pero no tanto, espero.
Slo hay que asignar el nombre al Label, suponiendo que fuese Label3, sera algo como esto:
Private Sub Command1_Click()
Dim i As lnteger
Dim j As lnteger
Dim Nombre As String

j = Val(Text2)
Nombre = Text1
For i = 1 To j
Label3 = Label3 & Nombre
Next
End Sub
Por ltimo, para que cada nombre se muestre en una lnea diferente, hay que aadirle a
continuacin un retorno de carro y cambio de lnea, en VB4 hay una cosntante definida para
ello: vbCrLf, en el VB3 habra que declararla de esta forma:
Dim vbCrLf As String
vbCrLf = Chr$(13) & Chr$(10)
Este sera el cdigo:
Private Sub Command1_Click()
Dim i As lnteger
Dim j As lnteger
Dim Nombre As String
j = Val(Text2)
Nombre = Text1
For i = 1 To j
Label3 = Label3 & Nombre & vbCrLf
Next
End Sub
LECCION 6.
Como hemos visto en el apndice de la leccin anterior, la instruccin IF... THEN... nos permite
tomar decisiones segn el valor de una variable o el resultado de una expresin. En esta
leccin 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:
lF <expresin> THEN
<si se cumple>
ELSE
<si no se cumple>
END lF
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:
lF numero > limite THEN
Print "tu nmero es grande"
ELSE
Print "OK, McKey!"
END lF
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 lF A <= 10 THEN GOTO 20
'Con el Commodore este programa se sola escribir as:
10 A=1
20 PRlNTA:A=A+1:lFA<=10GOTO20
'Sin ESPAClOS Nl NADA... TODO APELMAZADO... que ms daba usar el
GOTO?
Imagine theres 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 o
While A While 1
Print A Print A
A = A + 1 A = A + 1
Wend 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!
LECCIN 7.
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 leccin, 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 leccin, hace los ejercicios y me "mailea" dicindome que no
le muestra nada... y eso que lo he puesto al final de la primera leccin 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 leccin iba a estar el mes
pasado...
SOLUCIONES A LOS EJERCICIOS DE LA SEXTA leccin:
1.)
Private Sub Command1_Click()
Dim A As lnteger
Dim B As lnteger
Dim i As lnteger
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 lnteger
Dim B As lnteger
Dim C As lnteger
Dim i As lnteger
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 lnteger
'...
'...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 Ia Ieccin reaI, es decir Ia 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 ponerIos 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 lnteger
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 lnteger
Dim a As lnteger, 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 lnteger

'recuedas que tienes que poner Show?

A = 5
lf Not A>10 Then
Print A;"no es mayor que 10"
End lf
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
lf Not A Then
Print A;"es cero"
Else
Print A;"es distinto de cero"
End lf
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
lf Not A Then
Print A;"es cero"
Else
Print A;"es distinto de cero"
End lf
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...
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 lnteger
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
lf lngNum And 2 ^ i Then
sTmp = sTmp & "1"
Else
sTmp = sTmp & "0"
End lf
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:
lf Not A<>0 Then
Print A;"es CERO"
Else
Print A;"NO es CERO"
End lf
Esto siempre funcionar de la forma esperada.
Pero sera ms fcil, o al menos ms inteligible, hacerlo as:
lf A=0 Then
Print A;"es CERO"
Else
Print A;"NO es CERO"
End lf
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 lnteger
Existe = Len(Dir$(Archivo))
lf Existe Then
Label1 = Archivo & " Si existe"
Else
Label1 = Archivo & " No existe"
End lf
'Esto es ms corto, pero talvez menos evidente:
'Label1 = Archivo & llf(Existe, " Si", " No") & " existe"
DoEvents
End Function
Private Sub Form_Load()

Dim A As lnteger, Nombre As String

Show

Label1 = ""
Nombre = "C:\Autoexec.BlN"
A=5
lf 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 lf
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 lnteger, Nombre As String

Show

Label1 = ""
Nombre = "C:\Autoexec.BlN"
A = 5
lf A > 10 Then
lf Existe(Nombre) Then
Print A; "mayor de 10 y " & Nombre & " existe"
Else
Print A; "es mayor de 10 pero " & Nombre & " no existe"
End lf
Else
Print A; "no es mayor de 10 o " & Nombre & " no existe"
End lf
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"...
lf 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:
lf 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.
LECCIN 8.
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 lecciones, 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 lecciones.
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 leccin), 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 leccin 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.
LECCIN 9.
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 lecciones... No voy a prometerte que voy a ser ms aplicado y no tardar tanto
entre cada leccin 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 leccin
El primero:
'Poner este cdigo en el Form_Load
Dim Hora(24) As lnteger
Dim i As lnteger, Dim Mayor As lnteger

'Llenar el array con nmeros...
'(en esta leccin veremos cmo hacerlo de forma aleatoria)
'...
'Comprobar cual es el mayor
For i = 1 To 24
lf Hora(i) > Mayor Then
Mayor = Hora(i)
End lf
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 leccin.
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 lnteger
Dim i As lnteger, Dim Menor As lnteger
'
For i = 1 To 24
lf Hora(i) Then 'Slo si no vale cero
lf Menor = 0 Then 'Si an no tiene un valor
Menor = Hora(i) 'se lo asignamos
Else
lf Hora(i) < Menor Then 'Si el contenido de Hora(i) es menor
Menor = Hora(i) 'lo asignamos como menor
End lf
End lf
End lf
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 leccin...
Ahora vamos a empezar la Novena leccin.
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 lecciones, 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 leccin 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:
lf 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:
lf 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
leccin "especial"
Solucin de los ejercicios de la leccin 9.
El juego bsico:
Dim n As lnteger
Dim x As lnteger

Randomize Timer
x = lnt(Rnd * 100) + 1
Do
n = Val(lnputBox$("Escribe un nmero del 1 al 100"))
lf n = x Then Exit Do
lf n < x Then
MsgBox "El nmero " & CStr(n) & " es menor."
Else
MsgBox "El nmero " & CStr(n) & " es mayor."
End lf
Loop
MsgBox "Lo has acertado."
1. Comprobar que el nmero introducido en el InputBox est entre 1 y 100, en caso de que no
sea as, volver a preguntar. Una de las soluciones, sin usar el GOTO:
Dim n As lnteger
Dim x As lnteger

Randomize Timer
x = lnt(Rnd * 100) + 1
Do
Do
n = Val(lnputBox$("Escribe un nmero del 1 al 100"))
Loop While n < 1 Or n > 100
lf n = x Then Exit Do
lf n < x Then
MsgBox "El nmero " & CStr(n) & " es menor."
Else
MsgBox "El nmero " & CStr(n) & " es mayor."
End lf
Loop
MsgBox "Lo has acertado."
2. Si se escribe CERO mostrar el nmero que el VB haba "pensado" y terminar.
Dim n As lnteger
Dim x As lnteger
Randomize Timer
x = lnt(Rnd * 100) + 1
Do
Do
n = Val(lnputBox$("Escribe un nmero del 1 al 100"))
lf n = 0 Then
MsgBox "Mi nmero era el " & CStr(x)
Unload Me
End
End lf
Loop While n < 1 Or n > 100
lf n = x Then Exit Do
lf n < x Then
MsgBox "El nmero " & CStr(n) & " es menor."
Else
MsgBox "El nmero " & CStr(n) & " es mayor."
End lf
Loop
MsgBox "Lo has acertado."
3. Cuando lo acertemos que nos indique en cuantos intentos lo hemos conseguido.
Dim n As lnteger
Dim x As lnteger
Dim v As lnteger

Randomize Timer
x = lnt(Rnd * 100) + 1
Do
Do
n = Val(lnputBox$("Escribe un nmero del 1 al 100"))
lf n = 0 Then
MsgBox "Mi nmero era el " & CStr(x)
'Si est en el Form_Load
'End
'Si est en un procedimiento
Exit Sub
End lf
Loop While n < 1 Or n > 100
v = v + 1
lf n = x Then Exit Do
lf n < x Then
MsgBox "El nmero " & CStr(n) & " es menor."
Else
MsgBox "El nmero " & CStr(n) & " es mayor."
End lf
Loop
MsgBox "Lo has acertado en " & CStr(v) & " veces."
4. Ahora 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.
Dim x As lnteger
Dim v As lnteger

Randomize Timer
Do
x = lnt(Rnd * 100) + 1
v = v + 1
lf MsgBox("Mi nmero es: " & CStr(x) & Chr$(13) & "He acertado?", 4) = 6 Then
MsgBox "Lo he acertado en " & CStr(v) & " veces."
Exit Do
End lf
Loop
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...
Dim x As lnteger
Dim v As lnteger
Dim a As lnteger
Dim z As lnteger

a = 1
z = 100
'En este caso no necesitamos nmeros aleatorios
Do
x = (z - a) / 2 + a
v = v + 1
lf MsgBox("Mi nmero es: " & CStr(x) & Chr$(13) & "He acertado?", 4) = 6 Then
MsgBox "Lo he acertado en " & CStr(v) & " veces."
Exit Do
Else
lf MsgBox("Entonces... " & CStr(x) & " es mayor?", 4) = 6 Then
'El nmero del ordenador es mayor
'debe estar entre x-1 y a
z = x - 1
Else
'El nmero del ordenador es menor
'debe estar entre x+1 y z
a = x + 1
End lf
End lf
Loop

LECCIN 10.
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 leccin, 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 leccin 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
leccin 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 leccin 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 = lnt(Rnd * 31) + 20 'Nmero de rascadas, T valdr de 20 a 50
For i = 1 To T
H = lnt(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.
Solucin de los ejercicios de la leccin 10.
Primero: He hecho un pequeo cambio al ejemplo que se usara, para que tambin se incluya
la HORA CERO, esta sera una de las formas de conseguirlo:
'Ejercicio 1
Dim T%, i%, H%, Horas%(0 To 23)

Randomize

T = lnt(Rnd * 31) + 20 'Nmero de rascadas, T valdr de 20 a 50
For i = 1 To T
H = lnt(Rnd * 24) 'H valdr de 0 a 23
Horas(H) = Horas(H) + 1
Next

Dim ValorMayor%, HoraValorMayor%, HoralnicioRascada%

'Este valor ser para saber que no se ha asignado
Const NoAsignado = -1

ValorMayor = 0
HoraValorMayor = NoAsignado
HoralnicioRascada = NoAsignado

'Las horas van de 0 a 23
For H = 0 To 23
'Si esta hora tiene algn valor, hacer las comprobaciones
lf Horas(H) Then
'
'===Para saber la primera hora de la rascada===
'
'Si la hora de inicio no se ha asignado
lf HoralnicioRascada = NoAsignado Then
'Asignar esta hora
HoralnicioRascada = H
End lf
'
'===Para saber la hora que tiene el valor mayor===
'
'Si el valor actual es mayor...
lf Horas(H) > ValorMayor Then
ValorMayor = Horas(H)
HoraValorMayor = H
End lf
End lf
Next
'
'Para mostrar los valores:
'HoraValorMayor ser la hora que tiene el valor mayor
'El valor mayor se puede conseguir as:
' ValorMayor
' Horas(HoraValorMayor) Esta forma dar error si no hay ninguna hora con el valor mayor
'
'HoralnicioRascada ser la hora en la que empezastes a rascarte...
'
Lo nico que hay que notar es lo siguiente:
Ya que las horas empezarn por CERO, debemos asignar un valor "inexistente" a los valores
de las variables que contendrn las horas de inicio y de mayor valor...
Por qu? Porque el Basic asigna automticamente el valor cero a las variables numricas y
como estas variables pueden tener un valor de CERO (0) a Veintitrs (23), el valor por defecto
puede ser un valor vlido... as que asignndole -1 (menos uno), nos aseguramos que no
tendr un valor que pueda confundirnos... lo captas? si no es as... ya te enterars cuando te
ocurra... ;-)
El segundo: Usando la parte de asignacin de las horas, es lo mismo que para saber la primera
hora, pero usando otra variable.
'Ejercicio 2
Dim UltimaHora%

'Este valor ser para saber que no se ha asignado
Const NoAsignado = -1

UltimaHora = NoAsignado

'Las horas van de 0 a 23
For H = 0 To 23
'Si esta hora tiene algn valor, hacer las comprobaciones
lf Horas(H) Then
'
'===Para saber la ultima hora de la rascada===
'
'Si la hora actual es mayor que la asignada
lf H > UltimaHora Then
'Asignar esta hora
UltimaHora = H
End lf
End lf
Next
Esta solucin no tiene mayor inconveniente, una vez comprendida la primera solucin.
El tercero: Para que el nmero aleatorio que se asigna est entre 100 y 1000, cambia la
asignacin a T de esta forma:
T = lnt(Rnd * 901) + 100
Recuerda que Int(Rnd * 901) produce un valor que va desde 0 a 900 ambos inclusives, as que
sumandole 100 tendremos un valor de 100 a 1000.
Para averiguar la hora con el menor valor, usaremos dos variables, una para guardar el valor
menor y otra para que "recuerde" a que hora ocurri eso...
Aunque habrs comprobado que eso de averiguar el valor menor no es tan "lgico" como
parece...
La explicacin es que al asignar el valor CERO a una variable cuando se inicializa, este valor
puede ser menor que cualquiera que se haya asignado, este problema no existe si se asignan
valores negativos, pero como ese no es el caso...
Para solucionarlo, se pueden hacer varias cosas, aqu explico las dos que creo que cubren
todas las posibilidades:
1. Si HoraValorMenor an no se ha asignado, la primera hora que se compruebe, ser la
hora con el menor valor.
2. Cuando es la "primera" hora que se comprueba, ese debe ser el valor menor hasta el
momento.
Esto mismo se puede hacer para el valor mayor, si sabemos que pueden asignarse
valores negativos... ya que si asi fuera, al tener un valor cero, ste sera mayor que
cualquier nmero negativo...
'Ejercicio 3
Dim T%, i%, H%, Horas%(0 To 23)

Randomize

T = lnt(Rnd * 901) + 100 'Nmero de rascadas, T valdr de 100 a 1000
For i = 1 To T
H = lnt(Rnd * 24) 'H valdr de 0 a 23
Horas(H) = Horas(H) + 1
Next

Dim ValorMenor%, HoraValorMenor%

'Este valor ser para saber que no se ha asignado
Const NoAsignado = -1

ValorMenor = 0
HoraValorMenor = NoAsignado

'Las horas van de 0 a 23
For H = 0 To 23
'Si esta hora tiene algn valor, hacer las comprobaciones
lf Horas(H) Then
'
'===Para saber la hora que tiene el valor menor===
'
'NOTA:
'Para que FUNClONE, hay que hacer una de estas dos cosas:
'
'1- Si no se ha asignado el valor menor...
lf HoraValorMenor = NoAsignado Then
ValorMenor = Horas(H)
HoraValorMenor = H
End lf
'2- Si es el primer valor, ser el menor...
lf H = 0 Then
ValorMenor = Horas(H)
HoraValorMenor = H
End lf
'
'hasta que se demuestre lo contrario...
lf Horas(H) < ValorMenor Then
ValorMenor = Horas(H)
HoraValorMenor = H
End lf
End lf
Next
Para Terminar: Bien, ya tenemos todas las soluciones, ahora pongamoslo todo junto y veamos
para que sirve eso de NoAsignado...
'Todos los ejercicios
Dim T%, i%, H%, Horas%(0 To 23)

Randomize
T = lnt(Rnd * 901) + 100 'Nmero de rascadas, T valdr de 100 a 1000
For i = 1 To T
H = lnt(Rnd * 24) 'H valdr de 0 a 23
Horas(H) = Horas(H) + 1
Next

Dim ValorMayor%, HoraValorMayor%, HoralnicioRascada%
Dim UltimaHora%
Dim ValorMenor%, HoraValorMenor%

'Este valor ser para saber que no se ha asignado
Const NoAsignado = -1

ValorMayor = 0
HoraValorMayor = NoAsignado
HoralnicioRascada = NoAsignado
UltimaHora = NoAsignado
ValorMenor = 0
HoraValorMenor = NoAsignado

'Las horas van de 0 a 23
For H = 0 To 23

'Si esta hora tiene algn valor, hacer las comprobaciones
lf Horas(H) Then
'
'===Para saber la primera hora de la rascada===
'
'Si la hora de inicio no se ha asignado
lf HoralnicioRascada = NoAsignado Then
'Asignar esta hora
HoralnicioRascada = H
End lf
'
'===Para saber la ultima hora de la rascada===
'
'Si la hora no se ha asignado
lf H > UltimaHora Then
'Asignar esta hora
UltimaHora = H
End lf
'
'===Para saber la hora que tiene el valor mayor===
'
'Si el valor actual es mayor...
lf Horas(H) > ValorMayor Then
ValorMayor = Horas(H)
HoraValorMayor = H
End lf
'
'===Para saber la hora que tiene el valor menor===
'
'NOTA:
'Para que FUNClONE, hay que hacer una de estas dos cosas:
'
'1- Si no se ha asignado el valor menor...
lf HoraValorMenor = NoAsignado Then
ValorMenor = Horas(H)
HoraValorMenor = H
End lf
'2- Si es el primer valor, ser el menor...
lf H = 0 Then
ValorMenor = Horas(H)
HoraValorMenor = H
End lf
'
'hasta que se demuestre lo contrario...
lf Horas(H) < ValorMenor Then
ValorMenor = Horas(H)
HoraValorMenor = H
End lf
End lf
Next

'Mostrar los datos:
Dim sTmp$

sTmp = "Estos son los valores:" & vbCrLf

lf HoralnicioRascada <> NoAsignado Then
sTmp = sTmp & "Hora de inicio de rascada: " & CStr(HoralnicioRascada) & vbCrLf
End lf
lf UltimaHora <> NoAsignado Then
sTmp = sTmp & "ltima hora de rascada: " & CStr(UltimaHora) & vbCrLf
End lf
lf HoraValorMenor <> NoAsignado Then
sTmp = sTmp & "La hora en la que empezastes a rascarte fue: " & CStr(HoraValorMenor) &
vbCrLf
End lf
lf HoraValorMayor <> NoAsignado Then
sTmp = sTmp & "La hora en la que terminastes de rascarte fue: " & CStr(HoraValorMayor) &
vbCrLf
End lf

MsgBox sTmp
LECCIN 11.
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
English-speaken 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 lnteger, PuntoX(1000) As lnteger
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 lnteger
Y As lnteger
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 leccin 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: Tener los datos de todos los colegas y otros que no lo son tanto.
Datos: Nombre y apellidos, direccin, telfono fijo, telfono mvil, direccin e-mail,
URL y cualquier otra cosa que se te ocurra.
El Tipo: 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 lnteger
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 lecciones 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(lnt(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 lecciones 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...
Vamos a continuar la leccin con un ejemplo.
Crea un nuevo proyecto, aade 6 labels y 6 textboxes, un par de commandbuttons...
Cmo? Que no sabes cmo hacerlo... hum!
Cuando inicias el VB, se crea un nuevo proyecto con un form por defecto, as que ese paso lo
puedes conseguir simplemente cargando el Visual Basic.
Una vez que tienes esto, te mostrar una pantalla como esta:
Pantalla de inicio del VB4
A la izquierda est la barra con los controles que se pueden usar, pulsa (doble click) en el que
tiene la A, esto situar una etiqueta llamada Label1, en el centro del form... sitala en la
esquina superior izquierda, para ello pulsala con el botn izquierdo del ratn y arrastrala hasta
arriba y a la izquierda... Pulsa otras cinco veces... y ve colocndolas debajo de la anterior, es
decir una debajo de otra...
Ahora debes pulsar el que est al lado de la etiqueta: (textbox) y haz la misma operacin,
pero los situa junto a cada una de las etiquetas anteriores. Una vez terminado todo el proceso,
debers tener seis etiquetas y seis cajas de texto.
Por ltimo pulsa en el botn que est debajo de la caja de texto y los colocas en la parte
inderior derecha, pulsa de nuevo en el mismo objeto y lo pones justo al lado del anterior, al final
debes tener algo como esto:
El form de prueba, con todos los controles
Hay una forma ms rpida de hacerlo... y que adems te permite, si quieres, crear arrays de
controles.
Sera pulsando en el Label una vez, a continuacin en el TextBox. Los seleccionas y le das a
Edicin/Copiar, tambin con el botn derecho del ratn.
Cmo los seleccionas para poder copiarlo? Pulsa el Label, pulsa la tecla Control, dejando
pulsada la tecla control, pulsa en el TextBox, vers que se quedan los dos "resaltados", ahora
suelta la tecla Control, en el men de Edicin, selecciona Copiar (o Copy si tienes la edicin
inglesa).
Ya estn copiados en la memoria del VB, ahora en el men Edicin selecciona Pegar (Paste en
guiri), te mostrar un mensaje de que si quieres crear un array del Label1, pulsa Si o No,
dependiendo de que quieras crear ese array o no, en el Label haz lo que quieras, pero cuando
te pregunte si quieres crearlo del TextBox, dile que no... Situa los nuevos controles debajo de
los anteriores y repite la operacin, pero en esta ocasin slo tienes que volver a pegar... ya
que an siguen copiados en memoria.
Ahora ocurrirn dos cosas, dependiendo de si le dijistes que SI o NO a la creacin de arrays
del Label, en caso de haberle dicho SI, slo preguntar si quieres crear un array de TextBox1;
por otro lado, si le contestaste No, te preguntar de nuevo si quieres crear el array de Label1 y
despus te interrogar sobre el TextBox1...
Repitelo hasta que tengas 6 controles de cada en el form y despus haces lo de los botones...
Esto lo practicas unas 500.000 veces y acabas por cogerle el "tranquillo"... 8-)
Un detalle: el texto que te mostrar ser Label1 y Text1, pero los nombres de los controles
sern diferentes, sino me crees, ve pulsndo cada uno de ellos y busca la propiedad Name de
la ventana esa que hay a la derecha, la que pone Properties - Form1.
Lo que interesa es que tengas los controles mostrados en la figura anterior y que los TextBoxes
tengan los nombres Text1, Text2... hasta Text6, los botones deben llamarse Command1 y
Command2.
Ahora abre el panel de cdigo, para hacer esto... cosa que a estas alturas ya deberas saber,
es pulsando en el botn "View Code", ese que est en la ventana del proyecto, s, esa... la de
la esquina superior derecha.
Escribe esto:
El cdigo de las declaraciones
Con esto acabamos de declarar el tipo definido, una constante con el nmero mximo de
colegas que por ahora queremos tener, un array para almacenar los datos de esos colegas y
una variable que ir llevando la cuenta de los colegas que tenemos actualmente.
Volvamos al form, pulsa en el botn Command1 y en la ventana de propiedades busca la que
pone Caption, selecciona el texto Command1 y escribe esto: "Nuevo Colega", ahora pulsa en el
Commad2 y cambia el caption por "Mostrar".
En cada uno de los Labels, empezando por el de arriba, escribe el nombre de los campos de
que se componen nuestro tipo definido, en el ltimo, puedes poner algo ms corto... por
ejemplo: Veces.
El siguiente cdigo lo pones en el Form_Load, para que se ejecute cuando inicies el proyecto.
Cdigo que se ejecutar al iniciarse el proyecto
Esto otro lo escribes en el Command1_Click:
Cdigo que se ejecutar al pulsar en el Command1
Y por ltimo, escribe esto en el Command2_Click:
Cdigo que se ejecutar al pulsar en Command2
Con esto, ya puedes escribir los datos correspondientes y despus pulsas en Nuevo Colega,
los datos escritos se asignarn a cada uno de los campos del tipo definido, como estamos
usando un array, hay que especificar el nmero en el que queremos insertar esos datos, la
variable Colega se va incrementando y en caso de que pulsemos en nuevo colega y ya
tengamos el nmero mximo, nos mostrar un mensaje indicndonos que ya no hay espacio
para ms.
El botn de mostrar los datos, lo que hace es que va mostrando cada uno de los colegas que
tenemos... te los tienes que ver todos... as que... prepara el cuerpo para los ejercicios de esta
leccin, ah van:
1. Poder modificar uno de los colegas.
Pista: Aade un nuevo TextBox, un nuevo CommandButton, en el caption del botn
escribes: "Modificar" y el nmero que introduzcas en el nuevo TextBox ser el colega a
modificar.
2. Mostrar los colegas a partir de un nmero determinado,
por ejemplo, si en ese TextBox escribes 5, mostrar desde el 5 hasta el ltimo
introducido, puedes usar el mismo botn Mostrar, de forma que si pones 0 1, te
muestre todos.
Solucin de los ejercicios de la leccin 11.
1.- Poder modificar uno de los colegas.
Este es el cdigo a insertar en el Command3_Click:
Cdigo para modificar un colega
El truco ser primero mostrar slo un colega y a continuacin, modificar los campos que
queramos, el cdigo del Command2_Click quedara as, para que al escribir un nmero en el
Text7, sea este colega el que se muestre, en caso de que el nmero introducido sea menor
que 1 o mayor que el nmero actual de colegas, se mostrarn todos.
Los cambios al Command2_Click
LECCIN 12.
Con esta leccin, empiezo la serie de manejo de datos almacenados en disco. As que presta
atencin a esta y las siguientes lecciones, 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 lecciones 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 lecciones...
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
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)
Modo
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.
As NmeroFichero
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 lecciones 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 lnput As nF
lnput #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 Sub Command1_Click()
Dim Numeros(1 To 10) As lnteger
Dim i%
Dim nFic%

Randomize

'Asignamos los valores
For i = 1 To 10
Numeros(i) = lnt(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 Sub Command2_Click()
Dim MasNumeros(1 To 10) As lnteger
Dim i%
Dim nFic%

'Abrimos el fichero para leer los datos
nFic = FreeFile
Open "C:\Prueba.txt" For lnput As nFic
For i = 1 To 10
lnput #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.
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 leccin, o en las soluciones, pero te explico
brevemente cmo funciona:

Solucin de los ejercicios de la leccin 12.
Solucin 1: Sin usar Array:
Private Sub Command1_Click()
Dim i%
Dim nFic%
Dim Nombre$

'Solucin 1, sin array
nFic = FreeFile
'Abrimos el fichero para almacenar los datos
Open "C:\Prueba.txt" For Output As nFic
For i = 1 To 10
Nombre = lnputBox("Escribe el nombre nmero " & CStr(i))
Print #nFic, Nombre
Next
Close nFic

End Sub

Private Sub Command2_Click()
Dim i%
Dim nFic%
Dim Nombre$

'Solucin 1, sin array
Label1 = ""
nFic = FreeFile
'Abrimos el fichero para leer los datos
Open "C:\Prueba.txt" For lnput As nFic
For i = 1 To 10
lnput #nFic, Nombre
Label1 = Label1 & Nombre & vbCrLf
Next
Close nFic
End Sub

Solucin 2: Usando un Array:
Private Sub Command1_Click()
Dim i%
Dim nFic%
Dim losNombres(1 To 10) As String

'Solucin 1, sin array
'Primero preguntamos los nombres
For i = 1 To 10
losNombres(i) = lnputBox("Escribe el nombre nmero " & CStr(i))
Next

'Ahora los guardamos
nFic = FreeFile
Open "C:\Prueba.txt" For Output As nFic
For i = 1 To 10
Print #nFic, losNombres(i)
Next
Close nFic

End Sub

Private Sub Command2_Click()
Dim i%
Dim nFic%
Dim variosNombres(1 To 10) As String

'Solucin 2, con array
nFic = FreeFile
Open "C:\Prueba.txt" For lnput As nFic
'Leer los diez nombres
For i = 1 To 10
Line lnput #nFic, variosNombres(i)
Next
Close nFic

'mostrar los nombres
Label1 = ""
For i = 1 To 10
Label1 = Label1 & variosNombres(i) & vbCrLf
Next
End Sub
Fijate que con esta segunda forma, si usas un array a nivel de mdulo o global, puedes mostrar
los datos cuando quieras, leyndolos una vez y despus mostrndolos en cualquier ocasin,
hasta que asignes nuevos datos.
Lo mismo ocurre al pedir esos nombres y despus guardndolos en el disco cuando quieras.
En el siguiente listado, puedes ver un ejemplo (simple) de esto que te digo.
Fijate que a la hora de leer los nombres, primero se comprueba si existe el fichero, esto ya lo
vimos en la leccin del IF...THEN
Option Explicit

Dim losNombres(1 To 10) As String

Private Sub cmdGuardar_Click()
Dim i%
Dim nFic%

'Ahora los guardamos
nFic = FreeFile
Open "C:\Prueba.txt" For Output As nFic
For i = 1 To 10
Print #nFic, losNombres(i)
Next
Close nFic
Label1 = "Datos guardados correctamente"

End Sub

Private Sub cmdLeer_Click()
Dim i%
Dim nFic%

'Nos aseguramos que exista el fichero:
lf Len(Dir$("C:\Prueba.txt")) Then
nFic = FreeFile
Open "C:\Prueba.txt" For lnput As nFic
'Leer los diez nombres
For i = 1 To 10
Line lnput #nFic, losNombres(i)
Next
Close nFic
Label1 = "Datos leidos correctamente"
Else
Label1 = "No existe el fichero de nombres"
End lf

End Sub

Private Sub cmdMostrar_Click()
Dim i%

'mostrar los nombres
Label1 = ""
For i = 1 To 10
Label1 = Label1 & losNombres(i) & vbCrLf
Next

End Sub

Private Sub cmdPreguntar_Click()
Dim i%

Label1 = ""
'Borramos el contenido anterior
For i = 1 To 10
losNombres(i) = ""
Next
'Tambin se puede hacer as: (esto es ms rpido)
'ReDim losNombres(1 To 10)

'Preguntamos los nombres
For i = 1 To 10
losNombres(i) = lnputBox("Escribe el nombre nmero " & CStr(i))
Next
End Sub

Private Sub Form_Load()
Label1 = ""
End Sub
LECCIN 13.
En la leccin 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 lnteger
Dim sFic As String
Dim tamFic As Long

sFic = "C:\Autoexec.bat"

nFic = Freefile
Open sFic For lnput 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 = lnputBox("Nombre del fichero:", "Mostrar tamao", "C:\Autoexec.bat")
lf Len(sFic) Then
MsgBox "El tamao de " & sFic & vbCrLf & "es de " & FileLen(sFic) & " bytes"
End lf
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 nFic As lnteger
Dim sFic As String
Dim tamFic As Long
Dim sContenido As String

sFic = lnputBox("Nombre del fichero:", "Mostrar fichero", "C:\Autoexec.bat")
lf Len(Dir$(sFic)) Then
nFic = FreeFile
Open sFic For lnput As nFic
tamFic = LOF(nFic)
sContenido = lnput$(tamFic, nFic)
Close nFic
MsgBox sContenido
End lf
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 Mostrar todos los ficheros que empiecen por Auto y que la
extensin sea .bat
Dir Auto*
o
Dir Auto*.*
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.
Dir A?t*.* 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.
Dir Dato??98.txt 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:
lf Existe(unFichero) Then
'Si existe, hacer lo que corresponda
End lf

lf Not Existe(unFichero) Then
'El fichero en cuestin no existe
End lf
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 lecciones, pero usando la deteccin de errores:
Private Function Existe(ByVal unFichero As String) As Boolean
On Local Error Resume Next

Existe = Len(Dir$(unFichero))
lf Err Then
Existe = False
End lf
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*.*") Then comprobar 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:
lf Not Existe("algo.txt") Then
MsgBox "El fichero indicado no existe"
End lf
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()
lf Existe(Text1.Text) Then
MsgBox "Si existe el fichero: " & Text1.Text
Else
MsgBox "NO EXlSTE el fichero: " & Text1.Text
End lf
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...
LECCIN 14.
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)
lf Err = 0 Then
Do While Len(sTmp) 'Repetir mientras haya ficheros
List1.Addltem sTmp 'Lo aadimos a la lista
sTmp = Dir$ 'Asignar el siguiente fichero
Loop
End lf
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.
Solucin de los ejercicios de la leccin 14.
Estos eran 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.
Vamos a ver la solucin al primero de los ejercicios de las dos formas que propuse, es decir
usando un nmero fijo de ficheros y uno variable.
En el caso del nmero fijo, he asignado un valor de 50, como ese valor est en una constante,
slo tendrs que cambiar el valor de la constante para cambiar el nmero de ficheros, veamos
el listado:
Private Sub Command1_Click()
Dim sTmp As String
Const MaxFicheros = 50
Dim sFicheros(1 To MaxFicheros) As String
Dim nFic As lnteger

On Local Error Resume Next

sTmp = Dir$(Text1.Text)
nFic = 0
lf Err = 0 Then
Do While Len(sTmp) 'Repetir mientras haya ficheros
'slo asignarlo si tenemos espacio reservado
lf nFic < MaxFicheros Then
nFic = nFic + 1
'Lo aadimos al array
sFicheros(nFic) = sTmp
End lf
sTmp = Dir$ 'Asignar el siguiente fichero
Loop
End lf
Err = 0
End Sub
Usando un nmero variable de ficheros.
En esta ocasin usaremos el Redim Preserve para hacer hueco en el array que guardar los
nombres de los archivos.
Private Sub Command1_Click()
Dim sTmp As String
Dim sFicheros() As String
Dim nFic As lnteger

On Local Error Resume Next

sTmp = Dir$(Text1.Text)
nFic = 0
lf Err = 0 Then
Do While Len(sTmp) 'Repetir mientras haya ficheros
nFic = nFic + 1
'Adecuar el tamao del array a los ficheros leidos
ReDim Preserve sFicheros(nFic)
'Lo aadimos al array
sFicheros(nFic) = sTmp
sTmp = Dir$ 'Asignar el siguiente fichero
Loop
End lf
Err = 0
End Sub
En el segundo ejercicio, hay que guardar el contenido del array, en este caso, el array debe
estar declarado a nivel de mdulo, ya que un array declarado dentro de un procedimiento es
local a ese procedimiento y por tanto no estar disponible fuera de el.
Si no lo haces as cada uno de los arrays que uses (y dimensiones) en cada SUB ser slo
visible en ese procedimiento...
Por tanto el Dim sFicheros() As String debes ponerlo en la parte de las declaraciones del form.
Este cdigo debers agregarlo despus de asignar todos los ficheros al array, justo despus
del Loop, para que est dentro del IF que comprueba que no se haya producido error..
Dim i As lnteger

'Guardar el contenido del array
Open "prueba.txt" For Output As 1
For i = 1 To nFic
Print #1, sFicheros(i)
Next
Close 1
Fijate que no he usado el Freefile para "buscar" un canal libre. En lugar de eso he usado el
nmero 1. Te lo digo por dos razones, la primera es para que no lo confundas con la letra L
minscula y la segunda es para que sepas que se pueden usar constantes, aunque no te lo
recomiendo, pero como en este caso, se con toda seguridad de que mi aplicacin no tiene
abierto ningn otro fichero, puedo permitirme el lujo de hacerlo as, de forma directa.
El tercer ejercicio, no debera tener mayor problema, todo lo que hay que hacer es un bucle que
asigne al listbox cada uno de los ficheros del array:
'Borrar el contenido del listbox
List1.Clear
'Agregarle cada uno de los ficheros del array
For i = 1 To nFic
List1.Addltem sFicheros(i)
Next
Este cdigo aadelo justo despus de guardar los datos en el disco, aunque tambin puedes
ponerlo despus, siempre que est despus del Loop, cualquier sitio es bueno.
Fijate que a pesar de que selecciones distintos tipos de ficheros, sin cerrar el programa, por
supuesto, estos no se incrementan en la lista, no slo por el List1.Clear, sino porque al hacer
Redim Preserve el nmero de elementos del array se adapta al valor de nFic y este valor
empieza siempre por cero, as que siempre se tendr en el array el nmero correcto de
ficheros.
La asignacin que hago para ponerlo a cero, no es necesaria, ya que cuando se dimensiona
una varible numrica, sta variable contiene inicialmente un valor cero.
Pero imaginate que no haces esa asignacin o que quieres asegurarte que el contenido del
array se "libere" antes de empezar a asignarle datos... para ello tendras que usar: ERASE
sFicheros, con esta instruccin borramos el contenido del array. En el caso de que el nmero
de elementos del array fuese fijo, a lo que se llama un array esttico, simplemente se borrara
el contenido del array, pero seguira existiendo el array con las 50 "dimensiones" creadas. Si,
por el contrario, el array es dinmico, es decir que podemos cambiar el tamao del mismo, lo
que hacemos es "eliminarlo" de la memoria, por tanto necesitaremos dimensionarlo (o
REdimensionarlo) para poder usarlo nuevamente.
LECCIN 15.
En esta leccin 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
vamos a "programar" un verdadero editor... 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
leccin 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

lf Existe(Text1.Text) Then
Text2.Text = ""
i = FreeFile
Open Text1.Text For lnput As i
tamFic = LOF(i)
Text2.Text = lnput$(tamFic, i)
Close i
End lf
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 Slo el scroll horizontal, para cambiar de lnea debes pulsar Intro
2- Vertical
Slo el scroll vertical, esto es como sin scrolls, pero nos permite
navegar hacia abajo.
3- Both 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 lnteger

'Valor del TextBox actual
QueText2Ant = QueText2
'Nuevo valor
QueText2 = QueText2 + 1
'si nos pasamos... volvemos al principio
lf 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
lf Existe(Text1.Text) Then
lf MsgBox("ATENClN, el fichero ya existe." & vbCrLf & _
"Quieres sobreescribirlo?", vbQuestion + vbYesNo) = vbNo Then
'Hemos contestado que no, as que...
SobreEscribir = False
End lf
End lf

'Si no existe o se quiere sobreescribir...
lf SobreEscribir Then
i = FreeFile
Open Text1.Text For Output As i
Print #i, Text2.Text
Close i
End lf
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 leccin, 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:
lf Modificado Then
lf MsgBox("El texto se ha modificado..." & vbCrLf & _
"Quieres guardarlo?", vbQuestion + vbYesNo) = vbYes Then
'Guardarlo
'...
End lf
End lf
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

lf Modificado Then
lf 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 lf
End lf
'Asignamos el nombre del fichero
sFichero = Text1.Text
lf Existe(sFichero) Then
Text2.Text = ""
i = FreeFile
Open sFichero For lnput As i
tamFic = LOF(i)
Text2.Text = lnput$(tamFic, i)
Close i
End lf
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 lnteger)
lf Modificado Then
lf MsgBox("El texto se ha modificado..." & vbCrLf & _
"Quieres guardarlo?", vbQuestion + vbYesNo) = vbYes Then
'Asignar el anterior
Text1.Text = sFichero
'guardarlo...
cmdGuardar_Click
End lf
End lf

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...
Solucin de los ejercicios de la leccin 15.
1.- Comprobar que no tenga ms de 32000 caracteres y en caso de que el fichero los tenga, no
abrirlo.
'Esta es la parte que se encarga de abrirlo, el cdigo anterior lo he omitido
'Asignamos el nombre del fichero
sFichero = Text1.Text
lf Existe(sFichero) Then
Text2.Text = ""
i = FreeFile
Open sFichero For lnput As i
tamFic = LOF(i)
lf tamFic <= 32000 Then
Text2.Text = lnput$(tamFic, i)
End lf
Close i
'Una vez abierto, no est modificado
Modificado = False
End lf
En este caso, lo nico que hay que hacer es comprobar si el tamao es menor o igual al
mximo indicado, si es as, abrir el fichero, por tanto, slo tendremos que poner la parte que
asigna al Text2 el contenido del fichero, dentro de la comparacin.
2.- En caso de que sea mayor de 32000 caracteres, leer slo los 32000 primeros.
La solucin es casi como la anterior, bueno, casi, es decir tendremos que hacer una
comparacin y en caso del que sea cierta, asignar a la variable que indica el nmero de
caracteres a leer el valor mximo que queremos.
'Asignamos el nombre del fichero
sFichero = Text1.Text
lf Existe(sFichero) Then
Text2.Text = ""
i = FreeFile
Open sFichero For lnput As i
tamFic = LOF(i)
'
lf tamFic > 32000 Then
tamFic = 32000
End lf
Text2.Text = lnput$(tamFic, i)
Close i
'Una vez abierto, no est modificado
Modificado = False
End lf
Por tanto comprobamos si el contenido de tamFic es mayor de 32000, en caso de ser cierto, se
cumple la condicin, asignamos este valor a esa variable, de esta forma slo se leern esos
caracteres.
3.- Si el tamao es mayor de 32000 no poder guardarlo (y como extra: no poder editarlo)
Para conseguir esto, debemos aprovechar el cdigo usado en la segunda solucin, de forma
que si es mayor de 32000, podamos asignar un flag, para saber que no se debe guardar.
Tambin podramos evitar que se modificase el contenido del TextBox, esto se consigue
asignando la propiedad Locked a True. De esta forma no se podr escribir en el TextBox. Por
supuesto que en caso contrario se debera permitir la escritura, ahora veremos cmo hacer
estas cosas.
Veamos las cosas por partes:
'Asignamos el nombre del fichero
sFichero = Text1.Text
lf Existe(sFichero) Then
Text2.Text = ""
i = FreeFile
Open sFichero For lnput As i
tamFic = LOF(i)
'Nos aseguramos que se pueda editar
Text2.Locked = False
Text2.ForeColor = vbWindowText
lf tamFic > 32000 Then
tamFic = 32000
'Si el tamao no es el leido,
'no permitir escribir
Text2.Locked = True
'si adems cambiamos el color... mejor
Text2.ForeColor = vbGrayText
End lf
Text2.Text = lnput$(tamFic, i)

Close i
'Una vez abierto, no est modificado
Modificado = False
En esta primera solucin, an no evitamos que se pueda guardar, pero al menos cambiamos el
color del texto y evitamos que se pueda modificar el contenido, para ello he cambiado el valor
de la propiedad ForeColor, usando dos constantes predefinidas, la primera es para asignar el
color normal del texto y la segunda es para asignar el color Gris cuando no podamos escribir en
el TextBox, la ventaja de usar estas constantes, al menos con el VB5, es que si cambias los
colores, usando el panel de control de Windows, estos se usan de forma automtica al
asignarlos con estas constantes.
Ahora pasemos a ver cmo evitar que se guarde, cuando se abra parcialmente un fichero.
Para ello necesitaremos otra variable a nivel de mdulo:
Dim PoderGuardar As Boolean
Con esta indicaremos que podemos o no guardar el contenido del TextBox.
Se asignar al abrir el fichero y se comprobar al guardarlo.
Veamos al completo los procedimientos de Abrir y Guardar:
Private Sub cmdAbrir_Click()
'Abrir
Dim i As Long, tamFic As Long
Dim sTmp As String

lf Modificado Then
lf 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 lf
End lf
'Asignamos el nombre del fichero
sFichero = Text1.Text
lf Existe(sFichero) Then
Text2.Text = ""
i = FreeFile
Open sFichero For lnput As i
tamFic = LOF(i)
'Nos aseguramos que se pueda editar
Text2.Locked = False
Text2.ForeColor = vbWindowText
'y que se pueda guardar
PoderGuardar = True
lf tamFic > 32000 Then
tamFic = 32000
'Si el tamao no es el leido,
'no permitir escribir
Text2.Locked = True
'si adems cambiamos el color... mejor
Text2.ForeColor = vbGrayText
'No permitir que se guarde
PoderGuardar = False
End lf
Text2.Text = lnput$(tamFic, i)

Close i
'Una vez abierto, no est modificado
Modificado = False
End lf
End Sub

Private Sub cmdGuardar_Click()
'Guardar
Dim i As Long
Dim SobreEscribir As Boolean

'Slo se ejecuta el cdigo si se puede guardar
lf PoderGuardar Then
'Se asigna el valor Verdadero, por si no existe
SobreEscribir = True
'Si ya existe, preguntar
lf Existe(Text1.Text) Then
lf MsgBox("ATENClN, el fichero ya existe." & vbCrLf & _
"Quieres sobreescribirlo?", vbQuestion + vbYesNo) = vbNo Then
'Hemos contestado que no, as que...
SobreEscribir = False
End lf
End lf

'Si no existe o se quiere sobreescribir...
lf SobreEscribir Then
i = FreeFile
Open Text1.Text For Output As i
Print #i, Text2.Text
Close i
'Ya hemos guardado las modificaciones
Modificado = False
sFichero = Text1.Text
End lf
End lf
End Sub

LECCIN 16.
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 lnteger
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 leccin 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 unaCadena As String * 82
Dim elNombre As String * 30
Dim laEdad As String * 2
Dim 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 Function Mki(ByVal unInteger As Integer) As String
Dim sLoByte As String
Dim sHiByte As String
Dim 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 "Colega 2:"
Print Mid$(unaCadena, 1, 30)
Print Cvi(Mid$(unaCadena, 31, 2))
Print 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 leccin
"medio" preparada... ya que de la que tena prevista de 7 pginas "manuscritas" slo he usado
2 y poco ms...
Para completar esta "extraa" leccin... 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.
Solucin de los ejercicios de la leccin 16.
1- Haz que se muestren los caracteres de una cadena al revs.
Dim unaCadena As String
Dim i As Integer

unaCadena = "Hola Mundo"

Cls

For i = Len(unaCadena) To 1 Step -1
Print Mid$(unaCadena, i, 1);
Next
Print
Lo que se hace es un bucle "al revs", es decir: empezando por el ltimo caracter... avanzando
hasta el primero.
De eso se encarga el STEP -1
2- Usando esta misma cadena, es decir "Hola Mundo", dividela en las dos palabras.
'
Dim unaCadena As String
Dim i As Integer
Dim palabra1 As String
Dim palabra2 As String

unaCadena = "Hola Mundo"

Cls

For i = 1 To Len(unaCadena)
If Mid$(unaCadena, i, 1) = " " Then
palabra1 = Mid$(unaCadena, 1, i)
'Tambin as:
'palabra1 = Left$(unaCadena, i)

palabra2 = Mid$(unaCadena, i + 1)

'Realmente deberamos abandonar el bucle
'Por la tremenda:
'Exit For
'Terminando el bucle:
'i = Len(unaCadena)
End If
Next
Print palabra1
Print palabra2
En este segundo ejemplo, si no abandonamos el bucle, bien usando EXIT FOR, (algunos me
odiarn por esto), bien asignando a la variable i el valor mximo que puede tener:
Len(unaCadena); en el caso de que la variable tenga ms de un espacio, se asignar a
palabra2 la ltima palabra y a palabra1 todo lo anterior. Si se abandona el bucle, en ese mismo
caso: palabra1 tendr la primera palabra y palabra2 todo el resto.
Para comprobarlo, cambia la asignacin por esta otra:
unaCadena = "Hola Mundo desastroso"
Ms adelante veremos otras formas de "obtener" cada una de las palabras de una cadena...
LECCIN 17.
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.
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 leccin 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 Sub cmdGuardar_Click()
Dim unColega As t_colega
Dim nFic As Long
Dim 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 Sub cmdLeer_Click()
Dim unColega As t_colega
Dim nFic As Long
Dim 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 leccin:
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 leccin, o al menos cuando veamos los ficheros de acceso binario,
(mi intencin es que sea en la prxima leccin, 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 leccin 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 leccin nmero once cuando se usaron
arrays de tipos definidos...
El aspecto del "programilla" sera algo as:
Solucin de los ejercicios de la leccin 17.
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 Sub cmdConvertir_Click()
Dim unColega As t_Colega, unColega2 As t_Colega2
Dim nFic As Long, nFic2 As Long
Dim numColegas As Long
Dim 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 leccin 18 (26/Abr/98)
'
' '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 el contenido de los TextBox
Text1 = ""
Text2 = ""
Text3 = ""
Text4 = ""

'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
LECCIN 18.
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 leccin 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...
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 Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim 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 Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim sCadena As String
Dim 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 Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim 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 Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim sCadena As String
Dim 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 Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim sCadena As String
Dim sEOF As String * 1
Dim 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 Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim 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 leccin, que
puede ser que te empaches con tantas cosas y no es bueno.
Los ejercicios
Recuerdas uno de los ejercicios de la leccin 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.
Solucin de los ejercicios de la leccin 18.
Esta es una foto del programa en ejecucin y el listado del mismo:
'------------------------------------------------------------------
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 lnteger
' 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 Tablndex,
'(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 lNl para que se pueda leer de forma
'fcil, incluso usando el ejemplo de la leccin 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

Anda mungkin juga menyukai