Todo el código en cualquier proyecto de Visual Basic es almacenado en módulos. A partir de Visual Basic 5.0, había ya tres clases de módulos:
(1) El módulo de una forma.
(2) El módulo estándard
(3) El módulo de clase
Los módulos de formas son guardados como parte de un proyecto con la extensión de archivo .FRM, los módulos estándard son guardados como parte de un proyecto con la extensión de archivo .BAS (lo cual sugiere que se trata de código escrito al estilo del lenguaje BASIC) y los módulos de clase son guardados con la extensión de archivo .CLS; estos últimos son la piedra angular de la programación orientada a objetos en Visual Basic (recuérdese que todos los objetos son instanciaciones de una clase que sirve como esqueleto o molde para llevar a cabo a partir de la misma la creación de objetos).
Ya hemos visto desde el principio que las aplicaciones sencillas en Visual Basic pueden consistir de una sola forma que al final será ejecutada como una ventana, y todo el código de la aplicación reside en ese módulo de forma. Conforme las aplicaciones se van haciendo más grandes y complejas, se requiere ir creando formas adicionales dentro de un proyecto. Eventualmente se encuentra que hay código común que queremos que se ejecute en varias formas. No queremos una duplicidad de código en dos formas distintas, así que para estos casos creamos un módulo separado que contiene un procedimiento que implementa el código que es común a dos (o más) formas. Este módulo debe ser un módulo estándard. Con el tiempo, se puede construír una librería de módulos que contiene procedimientos compartidos.
Cada módulo de forma, estándard y de clase puede contener:
Declaraciones.- Podemos poner declaraciones de constantes, tipos, variables y librerías de enlace dinámico DLL (Dynamic Link Libraries) al nivel de módulo de una forma, módulo estándard o módulo de clase.
Procedimientos.- Aquí estamos hablando de funciones Sub, o procedimientos de Propiedad que contiene piezas de código que queremos que se ejecuten como una unidad.
Ya sabemos cómo podemos crear una forma (.FRM) para ser agregada a un proyecto en Visual Basic recurriendo a la barra de Menú de Visual Basic, en la opción de File (Archivo) seleccionamos la sub-opción New Form con la cual se crea una nueva forma que es agregada al proyecto. Pero no hemos visto aún cómo crear un módulo estándard (.BAS) para ser agregado a un proyecto. Esto lo podemos hacer también desde la barra de Menú de Visual Basic en la misma opción de File, pero seleccionando la sub-opción New Module. Cada nuevo módulo tendrá asignado de manera automática la extensión de archivo .BAS cuando el proyecto sea guardado en la computadora. En la siguiente ventana que dá el listado de un proyecto, podemos ver que para tal proyecto se han creado cuatro formas (.FRM) y se le han agregado tres módulos (Module1.bas, Module2.bas y Module3.bas):
Si seleccionamos uno de los módulos estándard (.BAS), veremos que el botón “View Form” (Ver Forma) es obscurecido, el único botón activo es el botón “View Code” (Ver Código), esto en virtud de que los módulos estándard no contienen ni formas ni objetos, sólo contienen código al estilo de BASIC.
En esta última ventana, que corresponde a una de las primeras versiones de Visual Basic, la versión 3.0 que apareció en 1993, puede verse que hay tres controles con terminación .VBX, los controles CMDIALOG.VBX (requerido para poder construír cajas de diálogo), GRID.VBX (requerido para construír rejillas para contener y manejar datos al estilo de como se acostumbra hacerlo en hojas de trabajo tipo Excel) y MSOLE2.VBX. Agregar módulos de clase con extensión .CLS solo sería posible en versiones posteriores de Visual Basic (como la versión 5.0) al requerirse que el entorno Visual Basic pudiese ser utilizado no sólo para la construcción de aplicaciones sino también para el diseño de controles por parte del programador.
A estas alturas, debemos estar suficientemente familiarizados con los módulos que corresponden a las formas, hemos estado metiendo en las formas cajas de texto, etiquetas, botones de opción y botones de comando. Hemos visto ya que las formas pueden contener procedimientos para el manejo de eventos tales como Click(), DblClick(), KeyDown(), KeyPress(), Load() y Unload(). Hemos visto también que, además de eventos, las formas pueden contener procedimientos generales, y declaraciones al nivel de la forma de variables, constantes, tipos y procedimientos externos. Podemos inspeccionar el contenido de cualquier tipo de forma .FRM abriendo el archivo deseadi con un editor de texto como el Bloc de Notas (Notepad), pudiendo ver las descripciones de la forma y sus controles. El contenido de un archivo como CALC.FRM, por ejemplo, puede tener algo como lo siguiente:
VERSION 2.00 Begin Form Calculator BorderStyle = 1 'Fixed Single Caption = "Calculator" ClipControls = 0 'False FontBold = -1 'True FontItalic = 0 'False FontName = "System" FontSize = 9.75 FontStrikethru = 0 'False FontUnderline = 0 'False Height = 3390 Icon = CALC.FRX:0000 Left = 3075 LinkMode = 1 'Source LinkTopic = "Form1" MaxButton = 0 'False ScaleHeight = 2985 ScaleWidth = 3240 Top = 1665 Width = 3360 Begin CommandButton Number Caption = "7" FontBold = -1 'True FontItalic = 0 'False FontName = "System" FontSize = 9.75 FontStrikethru = 0 'False FontUnderline = 0 'False Height = 480 Index = 7 Left = 120 TabIndex = 7 Top = 600 Width = 480 End Begin CommandButton Number Caption = "8" FontBold = -1 'True FontItalic = 0 'False FontName = "System" FontSize = 9.75 FontStrikethru = 0 'False FontUnderline = 0 'False Height = 480 Index = 8 Left = 720 TabIndex = 8 Top = 600 Width = 480 End ....... Sub Cancel_Click () ReadOut = "0." Op1 = 0 Op2 = 0 Form_Load End Sub Sub CancelEntry_Click () ReadOut = "0." DecimalFlag = False LastInput = "CE" End Sub ....... End
El código que escribimos en un módulo de forma es específico a la aplicación particular a la cual pertenece la forma; también puede referenciar otras formas y objetos dentro de la misma aplicación.
Los módulos estándard, los cuales no son formas, sirven como contenedores para declaraciones y procedimientos que son accesados con frecuencia por otros módulos dentro de una aplicación. Pueden contener lo que se conoce como variables globales, las cuales están a disposición de toda la aplicación, así como también constantes globales, tipos globales, y procedimientos globales. Lo que más nos interesa es que el código que se escribe en un módulo estándard no está necesariamente atado a una aplicación específica; si tenemos la precaución de no referenciar formas y controles por nombres, el mismo módulo estándard se puede utilizar en muchas otras aplicaciones. Puesto que los módulos estándard contienen declaraciones y procedimientos escritos en la sintaxis de Visual Basic, sus contenidos también pueden ser inspeccionados en cualquier momento abriendo los archivos con extensión .BAS con un editor de texto.
En relación a lo anterior, cabe destacar que cuando Visual Basic hizo su aparición por vez primera, al abrirse un proyecto se incluía de manera automática predeterminada un módulo llamado <b>Global</b> en el cual se escribían declaraciones destinadas para ser usadas por todo el programa y no sólo por por algún módulo en particular. Cada proyecto tenía un módulo Global archivado como Global.BAS. Sin embargo, posteriormente se eliminó dicho módulo, haciéndolo una opción de creación del programador mediante la sub-opción (desde la línea del menú) New Module.
En cuanto a los módulos de clase, éstos nos permiten escribir código para crear nuevos objetos. Los nuevos objetos pueden incluír propiedades y métodos definidos por nosotros mismos. De hecho, las formas son simplemente módulos de clase que contienen a las cuales se les han metido controles y pueden ser puestas en marcha como ventanas por el usuario final (sin embargo, los módulos de las formas no fueron reclasificados también como módulos de clase en virtud de que la mayoría de los programadores convenció a Microsoft que manteniendo la distinción entre ambos módulos facilitaba enormemente la construcción de un proyecto).
Todas las versiones de Visual Basic incluyen un compilador que permite tomar todos los archivos de los que consta un proyecto (archivos con extensión .FRM, archivos con extensión .BAS y archivos con extensión .CLS) para construír con ellos un archivo ejecutable (un archivo con extensión .EXE) que es el propósito final de todo proyecto llevado a cabo en Visual Basic. Además de estos archivos, Visual Basic en la creación de un archivo ejecutable incorpora controles adicionales que no forman parte de los controles instrínsecos de Visual Basic, ya sea controles creados por el propio programador (esta opción solo está disponible en las versiones más avanzadas de Visual Basic) o controles puestos en venta por otras casas de programación, los cuales en el sistema de guardado de archivos tienen extensión .VBX (en el caso de las primeras versiones de Visual Basic) o .OCX (que terminaron reemplazando los archivos .VBX). Aquí nos falta mencionar otro archivo, un archivo que puede tener una extensión como .MAK o como .VBP, que contiene toda la información concerniente al proyecto actualizado; cada vez que se abre un proyecto en el que se está trabajando Visual Basic recurre a ese tipo de archivo para abrir el proyecto.
Así pues, el compilador en el entorno Visual Basic toma los archivos ya mencionados y construye un programa ejecutable que el usuario final puede correr por cuenta propia sin necesitar tener instalado en su máquina ningún Visual Basic:
Obsérvese en la figura cómo se puede requerir la inclusión de bibliotecas de enlazado dinámico DLL (Dynamic Link Libraries) para poder llevar a cabo una interacción más estrecha con funciones más avanzadas del sistema operativo, funciones que forman parte de un repertorio rico que cuando nació fue bautizado por Microsoft como la Interfaz de Programación de Aplicaciones API (Applications Programming Interface). Pero este ya es un tipo de programación más avanzada que separa a los programadores novatos de los programadores profesionales.
En un proyecto Visual Basic ya terminado, el paquete del proyecto puede contener grupos de archivos estándard tales como un módulo DECONSTS.BAS usado para declarar constantes de uso global, otro módulo titulado DECVARBS.BAS para declarar variables de uso global, otro módulo titulado DECSUBS.BAS para declarar procedimientos Sub de alcance global, otro módulo DECFUNCS.BAS para declarar funciones de alcance global, así como varios archivos de formas tituladas DEX.FRM, EXPERMT1.FRM, EXPERMT2.FRM, GAUSSIAN.FRM y TAGUCHI.FRM; a lo cual se le agregan archivos de clase que pueden tener los nombres GRID.VBX, PAINT.OCX, WORDSTAR.VBX, LOTUS123.VBX, MODEMHAY.OCX y OLE3.OCX. En cada caso, resulta muy conveniente que los archivos que forman parte de un proyecto grande en vez de tener los nombres predeterminados que les asigna Visual Basic tengan nombres que sugieren el propósito y contenido de cada archivo, lo cual puede hacer más eficiente el desarrollo de un proyecto hasta su etapa final así como hacer más fácil darle mantenimiento al programa en respuesta a las retroalimentaciones proporcionadas por los clientes y usuarios del programa terminado.
Si bien, por propósitos didácticos, en las entradas anteriores no dimos mucha importancia a ciertas cosas como el orden en el cual se van poniendo los controles en una forma. o a la separación en módulos distintos de las declaraciones de variables y procedimientos Sub así como funciones Function() dependiendo de qué tan accesibles queremos que sean, ya sea públicos (accesibles desde cualquier parte de un programa) o privados (accesibles únicamente dentro de una forma o del procedimiento de un control), ha llegado la hora de poner cierto orden en estas cosas.
Por la fuerza de la costumbre, muchos usuarios de computadoras caseras con el sistema operativo Windows instalado en ellas se han llegado a convencer a sí mismos de que no es posible llevar a cabo ni siquiera las tareas más elementales tales como la localización de archivos si la computadora no tiene instalado un Mouse. Sin embargo, esto no es cierto; podemos lograr muchas cosas directamente desde el teclado sin tener que recurrir al Mouse (menos intuitivo y más incómodo, cierto, pero no imposible). Después de todo, cuando aparecieron las primeras computadoras, el Mouse no existía, y cuando apareció era considerado un lujo, pero aún así la gente se las arreglaba perfectamente bien haciendo todas sus operaciones desde el teclado. Al ser introducidas las primeras versiones de la interfaz visual de Windows, aunque se podían hacer cosas con un Mouse instalado en la máquina, tales como copiado y empastado de texto, se tomaba en cuenta que muchos usuarios no tenían un Mouse instalado en sus máquinas, y desde un principio Windows incorporó la opción de poder hacer todo (o casi todo) desde un teclado. Para poder “navegar” de una aplicación a otra o de una opción a otra dentro de una aplicación, Windows utiliza la tecla del tabulador Tab (generalmente puesta a la izquierda del teclado). Oprimiendo repetidamente la tecla Tab se puede ir cambiando el enfoque de un lado a otro. Esto en lo que respecta al sistema operativo Windows, en una máquina que ha sido encendida sin un Mouse instalado en ella. En lo que respecta a un programa de aplicación, el “enfoque” va cambiando de una opción a otra también con la ayuda de la tecla Tab. Dentro del programa de aplicación, se espera que conforme la tecla Tab va siendo oprimida el enfoque se vaya desplazando de izquierda a derecha y de arriba hacia abajo. Pero en un programa ejecutable elaborado con Visual Basic, ello sólo ocurrirá si el programador fue lo suficientemente cuidadoso de ir metiendo los controles dentro de cada forma siguiendo el mismo orden, de izquierda a derecha y de arriba hacia abajo, habido el hecho de que Visual Basic asigna el orden a la tecla Tab no por la posición final en la que aparecen los controles dentro de una forma terminada sino por el orden en el cual los controles fueron metidos por el programador.
A modo de ejemplo, supóngase que en cierto programa diseñado como una Calculadora de Préstamos (Loan Calculator) el programador fue metiendo los once controles que se muestran siguiendo el orden indicado en números rojos:
Esto signica que, al abrirse el programa y cuando el sistema operativo haya hecho la transferencia del control de la máquina al programa, el programa arrancará con el enfoque puesto en la tecla de cálculo “Calc”... ¡cuando aún no se le ha metido ninguna información a la calculadora! Presionando la tecla Tab, el enfoque será transferido al ícono que invoca a la impresora... ¡cuando aún no hay nada que imprimir! No hay, pues, ningún orden en la forma en la cual el enfoque debe ser pasado en forma natural, o sea de arriba hacia abajo y de izquierda a derecha, todo ello porque el programador metió en la forma primero el control (1), después el control (2), y así sucesivamente.
Para corregir el orden en el cual actuará la tecla Tab dentro de una forma, hay que recurrir a la ventana de Propiedades de cada objeto en cuestión, y en la propiedad TabIndex se debe asignar el número apropiado que le toque a cada control (nota: la numeración en la asignación del orden no empieza a partir de 1 sino a partir de 0):
Se puediera argumentar que este trabajo extra se lo pudo haber evitado el programador si desde un principio hubiera planificado cuidasosamente el diseño de su forma metiendo los controles en el orden natural, aunque también pudiera argumentarse que en la etapa de diseño suelen ocurrir cambios por mejoras de última hora que no es posible anticipar. Afortunadamente, en la etapa de diseño se puede corregir todo, absolutamente todo, algo que seguramente los usuarios finales del programa seguramente agradecerán.
Aunque hay cosas que hacemos en la computadora (tales como algunas operaciones matemáticas con una calculadora como la que incluyen todos los sistemas operativos Windows y Apple en su conjunto de programas accesorios, o escuchar música) de las cuales no tenemos necesidad o interés alguno en guardar resultados que vayamos obteniendo del uso de la máquina, hay otras situaciones en las cuales la prioridad es guardar en forma permanente nuestro trabajo en algún formato o formatos, tales como cuando estamos elaborando un libro en un procesador de documentos, ya sea en discos de memoria magnética (inicialmente esto se llevaba a cabo en discos flexibles, tras lo cual se hizo en diskettes, tras lo cual se hizo en los discos duros) o en alguna memoria portátil o inclusive en algún lugar de Internet de esos conocidos como la “nube”, lugares de donde podamos recuperar la información cuando ello se requiera. Los programas que corren bajo el sistema operativo Windows incluyen típicamente en la línea de menú una sub-opción Abrir... (Open...) para proporcionar acceso a archivos de datos específicos a alguna aplicación que están guardados en la memoria permanente de la computadora (disco duro, micro SD, etc.). En la caja de diálogo proporcionada por este comando, podemos esperar llevar a cabo los siguientes pasos en el proceso de localizar y abrir un archivo:
- Cambiar de ubicación (por ejemplo, del disco duro a la memoria portátil USB).
- Encontrar la carpeta (directorio) en donde se encuentra el archivo que estamos buscando.
- Seleccionar el archivo, y abrirlo.
Cuando la forma se está ejecutando ya como una ventana, los controles adquieren una funcionalidad como esta:
Bajo la dirección del código de un programa, estos controles trabajan juntos de manera coordinada para darle al usuario acceso a cualquier archivo específico que esté almacenado en la memoria permanente de la computadora. La caja de listado de drives tiene una lista expandible que muestra todos los dispositivos de memoria permanente disponibles en la computadora. Cuando el usuario hace clic en esta lista en el nombre de algún dispositivo de memoria permanente (drive), la caja de listado de directorios muestra la jerarquía de directorios (carpetas) disponibles en el drive. Así pues, cuando el usuario selecciona un directorio (carpeta) la caja de listado de archivos se abre mostrando los nombres de todos los archivos guardados en ese directorio. La coordinación de los tres controles no es del todo automática, aunque bajo Visual Basic no se requiere mucha programación.
Siendo cada control un objeto, las cajas de listado de drives, listado de directorios y listado de archivos son también objetos, con propiedades y eventos. Para integrar las cajas de listado de drives, listado de directorios y listado de archivos, un programa monitorea los eventos a través de los eventos Change y Click, así como los cambios resultantes que ocurren en las propiedades cuando el usuario hace selecciones mediante estos objetos. La manera en la cual se lleva a cabo la coordinación es la siguiente:
(A) La caja de listado de drives es una caja colgante (drop-down box) de listado. De manera predeterminada, el drive actualmente en uso por el sistema operativo es el drive mostrado. Cuando el control de listado de drives tiene el enfoque, el usuario puede escribir en el mismo cualquier designación válida de drive o usar la flecha “hacia abajo” puesta del lado derecho de la caja de listado de drives. Cuando el usuario hace clic en la flecha, la caja colgante cae hacia abajo mostrando todos los drives disponibles en la máquina. Si el usuario selecciona un nuevo drive de la lista, ese drive es puesto al principio de la lista. El nombre predeterminado de este control es Drive1, y tiene una propiedad Drive que representa el nombre de la memoria permanente (drive) actualmente seleccionada. Esta es una de las propiedades que no aparece en la ventana de listado de Propiedades para el control Drive1, sin embargo el programador debe saber que tal propiedad existe. Se puede escribir código para examinar la propiedad Drive y determinar cuál drive es el que está actualmente seleccionado. El programa de aplicación también puede especificar cuál drive aparecerá en el tope de la caja de listado de drives con una asignación tan sencilla como la siguiente (puesta en el código del programa):
Drive1.Drive = "C:\"
Cuando el usuario escoge una nueva selección de la caja de listado de drives, el evento Change resultante se convierte en una oportunidad para que el programa pueda leer la nueva condición de Drive y pasársela a la caja de listado de directorios.
Sub Drive1_Change ()
' Código
End Sub
(B) El nombre predeterminado de la caja de listado de directorios es Dir1. Este control tiene una propiedad llamada Path (ruta) que representa la ruta del directorio actual; esta es otra de las propiedades que no aparecen en la ventana de listado de Propiedades para el control Dir1. Sin embargo el programador debe saber que tal propiedad existe. El programa debe asignar la condición del Drive de la caja de listado de directorios a la propiedad Path del directorio, lo cual ocasionará que la caja de listado de directorios muestre la jerarquía del directorio de drive más recientemente seleccionado. Cuando el usuario abre subsecuentemente un nuevo directorio, un procedimiento Change en el programa debe leer la nueva condición de la propiedad Path del control del directorio, pasándole dicho valor a la caja de listado de archivos. Esto se lleva a cabo mediante el siguiente enunciado que se antoja ridículamente sencillo:
Dir1.Path = Drive1.Drive
Cuando esta asignación es ejecutada en el código, la caja de listado de directorios muestra todos los directorios y sub-directorios disponibles en ese drive (Drive1).
Cuando el usuario hace clic sencillo en un artículo en la caja de listado de directorios, dicho artículo es resaltado. Cuando el usuario hace doble-clic el artículo es asignado a la propiedad Path, su propiedad ListIndex recibe el valor de -1, y la caja de listado de directorios es reconfigurada en la pantalla para mostrar sus sub-directorios inmediatos.
(3) El nombre predeterminado de la caja de listado de archivos es File1. La caja de listado de archivos también tiene su propia propiedad Path. En este caso, la condición de Path especifica la ruta de directorio de donde la lista de archivos será leída. Mediante código, podemos hacer que se muestren todos los archivos en el directorio en uso actual en el drive en uso actual mediante el siguiente enunciado que se antoja ridículamente sencillo:
File1.Path = Dir1.Path
Podemos hacer que se muestren no todos los archivos sino tan solo un subconjunto de dichos archivos mediante la propiedad de patrón Pattern (esta propiedad sí aparece en la ventana de propiedades de la caja de listado de archivos, y está puesta en forma predeterminada como *.*). Por ejemplo, *.DOC muestra únicamente los archivos con tal extensión. La propiedad Pattern también puede aceptar una lista delimitada por semicolones (:). Por ejemplo, una línea con el siguiente código hace que la caja de listado de archivos muestre todos los archivos con las extensiones .DOC y .TXT:
File1.Pattern = "*.DOC; *.TXT"
Antes de continuar, es menester dar un repaso rápido sobre la manera en la cual fueron evolucionando las designaciones para los directorios raíz que son el principio de las jeraraquías del sistema de archivaje en las computadoras caseras. En un principio, cuando aparecieron las primeras computadoras caseras IBM, el sistema operativo PC-DOS que IBM le encargó a una entonces pequeña empresa llamada Microsoft no estaba contenido en disco duro alguno, ya que esas primeras computadoras carecían de disco duro. Bajo su concepto de arquitectura de hardware expandible, las computadoras IBM tenían varias bahías de montaje disponibles en sus gabinetes, y como mínimo había una bahía en la cual se introducían en un drive los otrora famosos discos flexibles. El sistema operativo PC-DOS (PC Disk Operating System) era proporcionado por IBM en un disco flexible que tenía que estar colocado en el drive de discos flexibles para que al ser encendida la máquina el sistema operativo se pudiera instalar en la memoria RAM de la máquina; de modo tal que el sistema operativo en sí nunca residía en la máquina, residía en un disco flexible que tenía que ser puesto en el drive por el usuario cada vez que la máquina era encendida. A este único drive se le simbolizó en el sistema operativo como:
A:
Eventualmente, muchos usuarios optaron por llevar a cabo una expansión del hardware de sus máquinas agregándoles un segundo drive para discos flexibles (lo cual era una gran comodidad al hacer duplicados completos de discos flexibles). A este segundo drive se le llamó:
B:
Ya para cuando IBM introdujo sus computadoras personales IBM PC AT, había discos duros que podían ser instalados como accesorio optativo en dichas computadoras, además de los dos drives A: y B: que pudieran tener. Con la finalidad de que no hubiera conflictos en las expansiones del hardware, al disco duro se le designó como:
C:
Eventualmente, se fueron descontinuando los dos drives A: y B: quedando uno solo (el drive A: usado para diskettes) , pero no el disco duro que fue tomando el lugar de los mismos, quedando la designación C: como pegoste para simbolizar el directorio raíz de la computadora que contiene todas las demás carpetas y archivos.
Eventualmente, a alguien se le ocurrió que se le podía agregar un segundo disco duro a las máquinas, y también un disco duro podía ser sub-dividido en lo que se conoce como particiones lógicas, además de que se le podían agregar a la máquina lectores de CD-ROM y DVD, todo lo cual requirió ampliar la simbolización a partir de la designación C: usada para el disco duro principal en el cual reside en forma permanente el sistema operativo; con lo cual se requirieron las simbolizaciones D:, E:, F:, etecétera.
En la siguiente captura de imagen, tenemos la vista de los contenidos de la máquina que nos proporciona el programa Explorador (Explorer) de una máquina que tiene instalado un sistema operativo Windows XP:
La máquina, como puede verse, es una máquina que contiene un drive de diskettes simbolizado como A:, un drive de discos flexibles simbolizado como B:, un disco duro simbolizado como C:, un lector de CD-ROM simbolizado como D:, y dos particiones lógicas del disco duro simbolizadas como E: y F:, teniendo además conectada la máquina una memoria portátil USB simbolizada como G:. Todas estas simbolizaciones las adjudica automáticamente el sistema operativo.
Cualquiera que haya tenido alguna experiencia previa con el manejo de una ventana de línea de comandos sabe que la siguiente designación DOS:
C:\WINDOWS\SYSTEM32\MACROMED\FLASH\FLASH.OCX
es precisamente la ruta (Path) del archivo en DOS (y también en Visual Basic), representando a un archivo FLASH.OCX, que está puesto bajo el sub-directorio FLASH, el cual a su vez está puesto bajo otro sub-directorio titulado MACROMED, el cual a su vez está puesto bajo otro subdirectorio titulado SYSTEM32, el cual a su vez está puesto bajo una carpeta titulada WINDOWS, la cual a su vez se encuentra almacenada permanentemente bajo el drive C: que es el directorio raíz del disco duro. Cuando los controles del sistema de archivos, o sea la caja de listado de drives, la caja de listado de directorios (carpetas) y la caja de listado de archivos son usados de manera sincronizada, en realidad Visual Basic está tratando en todo momento de construír una ruta como la que se muestra arriba. Todo, absolutamente todo lo que se encuentra en la memoria permanente de la máquina (inclusive aunque sea una memoria tipo micro SD NAND FLASH como la que usan las tableas electrónicas, en lugar de un disco duro), o sea todas las carpetas y archivos, están identificados de manera unívoca e individual por la ruta DOS que conduce a cada carpeta y archivo. Los tres controles de manejo de archivos van construyendo cada ruta del modo siguiente:
Así pues, en una aplicación real, cuando a los tres controles de listado de drives, directorios y archivos se les ha dejado intacto su nombre predeterminado de Drive1, Dir1 y File1, la secuencia de eventos puede ser la siguiente:
(A) El usuario selecciona en su máquina algún drive en la caja de listado Drive1.
(B) Se genera un evento Drive1_Change, y en la pantalla de Drive1 se actualiza la información para reflejar el drive nuevo.
(C) El código en el procedimiento de evento Drive1_Change() asigna la nueva selección (la propiedad Drive1.Drive) a la propiedad Path de la caja de listado Dir1 con los siguientes enunciados:
Sub Drive1_Change()
Dir1. Path = Drive1.Drive
End Sub
(D) La asignación a la propiedad Path genera un evento Dir1_Change y actualiza la pantalla para que Dir1 refleje el directorio actual del nuevo drive.
(E) Código en el procedimiento de evento Dir1_Change asigna la nueva ruta (la propiedad Dir1.Path) a la propiedad File1.Path de la caja de listado File1:
Sub Dir1_Change()
File1.Path = Dir1.Path
End Sub
(F) La asignación a la propiedad File1.Path ocasiona que la caja de listado File1 refleje la especificación actual de la ruta Dir1.
Una cosa que podemos hacer, con código, cuando arranca un programa de aplicación, es inicializar un drive, la ruta (Path), y el patrón (Pattern) del tipo de archivos que queremos que se encuentre (generalmente, de acuerdo a su extensión), del mismo modo en que cuando se abre una hoja de trabajo tipo Excel al buscar entre una lista de archivos queremos que se nos muestre únicamente archivos con la extensión .XLS excluyendo de la lista mostrada otros archivos con otra extensión como .DOC o .PPS. La inicialización, cuando se carga una forma (ventana), se lleva a cabo de una manera como la siguiente (en esta ocasión le daremos nombres a los controles de manejo de directorios y archivos en lugar de usar los nombres predeterminados dados por Visual Basic):
Sub Form_Load()
ListadoDrive.Drive = "C:"
ListadoDirectorio.Path = ListadoDrive.Drive + "\"
ListadoArchivo.Path = ListadoDirectorio.Path
ListadoArchiv.Pattern = "*.PNG"
End Sub
PROBLEMA: Elaborar un programa Visual Basic en el cual se imprima la ruta completa hacia cierto archivo que haya sido seleccionado de un listado de archivos a partir de cierto directorio.
Esto resulta fácil si metemos en una forma un control de listado de directorios, un control de listado de archivos, y un control de etiqueta (label). En el procedimiento de evento Change() del control de listado de directorios, especificamos lo siguiente:
Sub Dir1_Change ()
File1.Path = Dir1.Path
End Sub
Y en el procedimiento de evento Click() del control de listado de archivos, especificamos lo siguiente:
Sub File1_Click ()
Label1.Caption = "Ruta: " + Dir1.Path + "\" + File1.FileName
End Sub
De este modo, si en la etapa de diseño la forma tiene el siguiente aspecto:
entonces al ejecutarse el programa, dependiendo del directorio y del archivo que sean seleccionados por el usuario, la ventana de la aplicación podrá mostrar un efecto como el siguiente (tal vez haya usuarios que desearían que la interfaz Explorer de los sistemas operativos Windows hubiera tenido una opción como ésta para escribir las rutas):
Obsérvese que no se usó una caja de texto para escribir la ruta sino una etiqueta (Label), a través de su propiedad Caption. Esto porque el programador no quiere que el usuario pueda escribir algo dentro de la cajita, lo que se escriba en ella debe estar bajo el control completo del programa.
La caja de listado de archivos, además de tener una propiedad de patrón Pattern para el filtrado selectivo de archivos, también posee un procedimiento de evento llamado PatternChange (cambio de patrón), el cual puede ser utilizado en combinación con la propiedad Pattern para actualizar un listado de acuerdo a la selección que quiera efectuar un usuario. Para ver un ejemplo de esto, a lo anterior le podemos agregar una caja de texto en la cual el usuario podrá especificar el tipo de archivo que desea que se le muestre, y un botón de comando para pedir al programa que el listado de archivos sea actualizado filtrando los archivos de acuerdo a lo que se quiere ver. El código para el botón de comando es:
Sub Command1_Click ()
File1.FileName = Text1.Text
Label1.Caption = "Ruta: " + Dir1.Path + "\" + File1.FileName
End Sub
Y el código del procedimiento de evento PatternChange() para el control de listado de archivos File1 es:
Sub File1_PatternChange ()
Text1.Text = File1.Pattern
End Sub
De este modo, al ejecutar el programa y meter en la caja de texto la hilera *.txt (pidiéndole con ello al programa que nos propocione un listado completo de todos los archivos de texto cuya extensión es .txt):
al apretar el botón de comando Command1 el listado es actualizado en una forma como la que se muestra (quedan varios detalles por corregir tales como borrar al cargarse el programa en la memoria RAM la hilera “Text1” que aparece en la caja de texto y cambiar la hilera “Label1” por la hilera “Ruta: ”, aunque esto es algo que puede hacer el programador fácilmente mediante las propiedades de estos objetos):
Hemos visto la manera en la cual podemos localizar cualquier archivo guardado dentro de la máquina mediante un programa de aplicación elaborado bajo Visual Basic. Pero, ¿qué es lo que vamos a hacer a continuación? A menos de que queramos borrar un archivo del disco duro, para lo cual basta con las opciones que el mismo sistema operativo nos dá para ello, lo más seguro es que queremos abrir el archivo para llevar a cabo alguna acción sobre el mismo (modificarlo, por ejemplo, o imprimirlo). Y esto es algo que tenemos que especificar mediante el código adecuado.
Por varias razones técnicas, en la mayoría de los sistemas operativos el trabajar con un archivo implica:
- Abrir el archivo con alguna operación del tipo OPEN.
- Hacer modificaciones al archivo o llevar a cabo operaciones con el mismo (por ejemplo, imprimirlo o enviarlo por correo).
- Cerrar el archivo con alguna operación del tipo CLOSE.
Para abrir un archivo, el enunciado Visual Basic que habremos de utilizar depende del tipo de archivo que queremos abrir. ¿Se trata de un archivo de texto, o de un archivo de imagen? ¿Se trata acaso de algún archivo que actuando como una base de datos tiene información almacenada en forma ordenada en paquetes subdivididos en tamaños iguales?
Como mínimo, la mayoría de las versiones de Visual Basic proporcionan elementos para el manejo de los siguientes tres tipos de archivos:
- Acceso Secuencial
- Acceso Aleatorio
- Acceso Binario
Para abrir un archivo secuencial, se usa la siguiente sintaxis con el enunciado Open:
Open nombre For Input As #número
nombre es el nombre de un archivo que ya existe en el disco duro (o dispositivo de memoria), mientras que número es el número entero que se usa para identificar al archivo en enunciados subsecuentes de entrada/salida I/O, considerando la posibilidad de que el usuario quiera tener no uno sino varios archivos del mismo tipo abiertos al mismo tiempo, en cuyo caso se le debe proporcionar al programa alguna manera de no confundirlos, siendo el número lo que se encarga de darle una identidad propia a cada archivo que se vaya abriendo. Si nombre no se puede localizar en el disco duro, el intento de abrir el archivo resulta en un error en tiempo de ejecución. Sin embargo, podemos evitar una interrupción en la ejecución del programa montando una trampa de error:
On Error GoTo etiqueta
Open nombre For Input As #número
On Error GoTo 0
etiqueta es una etiqueta de línea (dentro del procedimiento) que identifica el comienzo de la rutina de trampa de error. Típicamente, la rutina activa una variable de bandera que indica una falla en la ejecución de Open.
Un ejemplo del uso del enunciado Open para abrir un archivo secuencial es el siguiente:
Open NombreArch For Input As 1
El enunciado Input se encarga de leer valores individuales de datos de un archivo de texto que ha sido abierto para su lectura, y debe ser usado posteriormente en el código con la siguiente sintaxis:
Input #número istavariable
El número en este último enunciado es el mismo número asignado al archivo abierto que corresponde al enunciado Open con el cual fue abierto. lista variable consiste de uno o más nombres de variables, con tipos de datos que corresponden a los datos que se espera extraer del archivo. Input# reconoce una coma o un marcador de final de línea -Chr$(13)+Chr$(10)- como delimitador entre dos valores de datos; además un caracter espaciador (espacio en blanco) sirve como delimitador entre dos valores numéricos. El enunciado Line Input# puede leer del archivo secuencial una línea entera de texto, sin importar las comas o los espacios en blanco que contenga la línea:
Line Input #número nombrevariable
En este respecto, la función EOF() (End Of File) regresa un valor de verdadero (True) después de que un enunciado Input# o un enunciado Line Input# ha leído el último valor de dato que hay en el archivo. Antes de llegar al final del archivo, el uso de EOF() dá un valor lógico de False. Se puede utilizar la función EOF en un bucle Do para leer un archivo cuya extensión se desconozca de antemano.
Cuando se logra abrir un archivo secuencial, el archivo se abre para llevar a cabo una de las siguientes operaciones:
- Darle entrada (Input) en la memoria RAM a los caracteres del archivo.
- Anexarle caracteres a un archivo (Append).
- Meter caracteres dentro de un archivo (Output).
Para abrir un archivo para escritura al mismo, usamos el enunciado Open en una de las siguientes formas:
Open nombre For Output As #número
Open nombre For Append As #número
Un ejemplo del uso del enunciado Open para abrir un archivo secuencial para salida hacia dicho archivo es el siguiente:
Open NombreArchivo For Output As 4
En el enunciado anterior, se sobrentiende que en alguna parte del código le daremos a la variable NombreArchivo un nombre de archivo, esto es, una hilera entre dobles comillas. En lugar de NombreArchivo podríamos haber usado otra cosa más específica como "PRUEBA.DAT".
Los enunciados Print# y Write# ambos envían artículos individuales de datos a un archivo secuencial que está abierto, en uno de estos modos:
Print #número, listadatos
Write #número, listadatos
La diferencia entre estos dos enunciados es que Print# envía artículos como tal, sin delimitadores, mientras que Write# encierra cada valor de hilera en dobles comillas, separando cada artículo del siguiente mediante una coma.
Por último, para cerrar un archivo secuencial, el enunciado Close# es el que se encarga de llevar a cabo esta importante tarea:
Close número
Lo que hemos visto arriba es aplicable a los archivos de acceso secuencial. ¿Pero qué de los archivos de acceso aleatorio?
Un archivo de acceso aleatorio está organizado en unidades individuales de datos llamados registros (records). Cada registro en un archivo de acceso aleatorio contiene un grupo estructurado de datos conocidos como los campos (fields). Lo más importante es que todos los registros en cierto archivo tienen la misma longitud. Gracias a esta característica, Visual Basic puede proporcionar acceso directo a cualquier registro en el archivo. Un registro es identificable por su número de registro, un entero que puede ir desde 1 hasta el número de registros que están almacenados en el archivo.
La estructura definida por el usuario de Visual Basic, también conocida como una estructura de registro, es la estructura ideal de datos para ser usada en la definición y creación de un archivo de acceso aleatorio. Ya vimos en una entrada previa que un enunciado Type define una estructura de registro, y un enunciado subsecuente Dim crea una variable correspondiente de registro. Junto con la estructura definida de registro, las herramientas principales que el programador usará en un programa de acceso aleatorio son los enunciados Open y Close (para abrir el archivo de acceso aleatorio y para cerrarlo, respectivamente), la función LOF(), y los enunciados Get y Put.
La siguiente forma del enunciado Open abre un archivo en el modo de acceso aleatorio:
Open nombre For Random As #número Len = Len(variableregistro)
En esta sintaxis, nombre es el nombre del archivo en el disco, número es un entero que identifica al archivo abierto en enunciados subsecuenters entrada/salida I/O, y variable es el nombre de una variable definida por el programador para representar los registros conforme son leídos del archivo o escritos hacia el archivo. La función de Visual Basic Len() suministra la longitud, en bytes, de la variable.
Una vez que ha sido abierto, un archivo de acceso aleatorio está disponible tanto para lectura como para escritura. Al inicio, un programa típicamente necesita saber el número de registros que está almacenado en el archivo. La siguiente fórmula utiliza la función Visual Basic LOF() (Length of File) para computar el conteo de registros:
ConteoRegistros% = LOF(númeroarchivo) / LEN(variableregistro)
El enunciado Get lee un registro individual de una posición especificada en el archivo abierto:
Get #número, númeroregistro, variableregistro
El valor de númeroregistro va desde 1 hasta el valor de ConteoRegistro. Como resultado de este enunciado, el registro completo almacenado bajo la posición númeroregistro en el archivo es asignado a los campos de variableregistro. Con esto, podemos usar un bucle For para leer secuencialmente un archivo de acceso aleatorio:
For I = 1 To ConteoRegistro
Get #número, I, variable
' Código de procesamiento
Next I
El enunciado Put escribe un registro sencillo a una posición especificada en el archivo abierto:
Put #número, númeroregistro, variableregistro
Si númeroregistro es igual a ConteoRegistro+1. este enunciado <Put anexa un nuevo registro al final del archivo abierto. Por el otro lado, si númeroregistro está en el rango comprendido entre 1 y ConteoRegistro, Put escribe por encima de un registro existente; en este caso el registro almacenado previamente en númeroregistro se pierde.
Cuando apareció Visual Basic por vez primera, sólo se podían crear y manejar archivos de acceso secuencial y archivos de acceso aleatorio. Pero pronto se comprobó que esto no era suficiente, y fue necesario definir los archivos de acceso binario. El acceso binario le dá al programador un control completo sobre un archivo, porque los bytes en el archivo pueden representar prácticamente cualquier cosa.
Para abrir un archivo de acceso binario, usamos la siguiente sintaxis para el enunciado Open:
Open nombre For Binary As #número
Como puede verse, el Open para el acceso binario difiere del Open para el acceso secuencial en el sentido de que la longitud Len no es especificada. Si se incluye una longitud de registro en un enunciado Open de acceso binario, simplemente será ignorado.
A estas alturas, las similitudes y discrepancias entre el acceso secuencial, el acceso aleatorio y el acceso binario deben ser obvias. La siguiente tabla nos proporciona la información para determinar qué enunciados de Visual Basic se pueden utilizar en qué situación:
Enunciados y funciones | Secuencial | Aleatorio | Binario |
Close | X | X | X |
Get | X | X | |
Input( ) | X | X | |
Input # | X | ||
Line Input # | X | ||
Open | X | X | X |
Print # | X | ||
Put | X | X | |
Type... End Type | X | ||
Write | X |
A estas alturas, el lector tal vez quiera ver ejemplos prácticos de un código Visual Basic que funcione correctamente en el uso de los enunciados y funciones que se han dado arriba para la apertura, lectura y cerrado de archivos, y esto es lo que se dará a continuación.
El siguiente código muestra la manera en la que trabaja el enunciado Open cuando se usa para abrir un archivo secuencial, así como la función Len() que regresa la longitud (el número de caracteres) en una hilera, así como la función EOF para saber si en un proceso de lectura hemos llegado al final de un archivo, así como la función Input() que nos va leyendo los caracteres de un archivo secuencial creado previamente para experimentar con el programa (este ejemplo se abre en un proyecto nuevo usando el evento Click() de la forma sin necesidad de tener que poner ningún control dentro de la misma, ya que todo se ejecutará al hacer el usuario clic con el Mouse dentro de la ventana):
Sub Form_Click()
Dim Char, NombreArchivo, DatosTexto
NombreArchivo = InputBox("Dame un nombre de archivo:")
If Len(NombreArchivo) Then
Open NombreArchivo For Input As #1
Do While Not EOF(1)
Char = Input(1,#1)
If Char <> Chr(10) Then
DatosTexto = DatosTexto & Char
Else
MsgBox DatosTexto
DatosTexto = ""
End If
Loop
Close #1
End If
End Sub
Haremos ahora un desglose del código. Después de declarar las variables Char (caracter), NombreArchivo y DatosTexto, en la siguiente línea le pedimos al usuario con una caja de entrada que nos proporcione un nombre de archivo, asignando dicha hilera a la variable NombreArchivo. Si el valor de la hilera no es cero, entonces con la estructura de decisión:
If Len(NombreArchivo) Then
' Instrucciones
End If
se ejecutan las instrucciones contenidas en el bucle:
Do While Not EOF(1)
'Instrucciones
Loop
con el cual se van leyendo los caracteres del archivo de uno en uno. El enunciado EOF(1) especifica el fin del archivo identificado como el archivo número 1, y el inversor lógico Not se encarga de invertir el valor lógico (True, False) regresado por la función EOF(). En la línea:
Char = Input(1,#1)
con el primer argumento (1) se especifica el número de caracteres que serán leídos por la función Input(), y en este caso se leerá un caracter (byte) a la vez, mientras que con el segundo argumento se especifica el número del archivo de donde serán leídos los caracteres, en este caso el archivo número 1.
En la instrucción:
If Char < > Char(10)
interpretamos la expresión condicional:
< >
como “diferente de” o bien “no igual a”. Chr(10) es interpretado como el código ASCII de una “línea nueva”, y por lo tanto la expresión condicional If se ejecuta si el caracter no es igual a una línea nueva. La alternativa Else de la expresión condicional hace que se imprima en una caja de mensaje la línea de texto que fue leída del archivo:
MsgBox DatosTexto
mientras que la línea:
TextData = ""
hace que se “limpie” la línea. El bucle Do While que termina en Loop se sigue ejecutando mientras no se haya llegado al final del archivo.
Finalmente, una vez que se ha llegado al final del archivo, lo cual es detectado con la función EOF(), se cierra el archivo # 1 con la instrucción:
Close # 1
tras lo cual se sale de la estructura de control If y se llega al final de la subrutina que corresponde al evento Click() de la forma.
Para el ejemplo que se ha dado arriba, se recomienda crear un archivo de texto con un nombre como EJEMPLO.TXT, que será el nombre de archivo que el usuario le dará al programa cuando se esté ejecutando, ya que si no existe un archivo con el nombre que sea proporcionado por el usuario Visual Basic responderá con su propia caja de mensaje diciendo que el archivo no fue encontrado (File not found).
El enunciado Line Input # es diferente de la función Input() en que el primero puede leer toda una línea de texto tomada de un archivo secuencial, y el siguiente programa nos dá un ejemplo de ello (el programa supone que en el directorio raíz del disco duro C: o bien en el drive A: de diskettes de una máquina muy vieja que arranca con el disco boot del sistema operativo PC-DOS puesto en el drive A: existe un archivo de texto llamado EJEMPLO.TXT):
Sub Form_Click
Dim Drive, NombreArchivo, Msg, NL, LineaTexto
NL = Chr(10)
Msg = "¿Desde que drive se hizo el boot de la máquina?"
Drive = UCase(Left(InputBox(Msg),1))
If Drive = "C" Or Drive = "A" Then
NombreArchivo = Drive & ":\EJEMPLO.TXT"
If Dir(NombreArchivo) <> "" Then
Open NombreArchivo For Input As #1
Line Input #1, LineaTexto
Close #1
Msg = "La primera linea de texto de EJEMPLO.TXT es "
Msg = Msg & NL & LineaTexto & "."
Else
Msg = "No se pudo encontrar EJEMPLO.TXT en el drive "
Msg = Msg & Drive & ":"
End If
End If
MsgBox Msg
End Sub
Para que este programa pueda mostrar lo que puede hacer, se requiere que exista un archivo de texto archivado como EJEMPLO.TXT en el directorio raíz C: del disco duro (o en el drive A: de la máquina) que tenga algunas líneas de texto, y que además el programa esté visible y no se halle oculto (Hidden) por los atributos de archivos asignados en el sistema operativo de la máquina. El programador puede crear el archivo requerido de texto con cualquier editor de texto como un bloc de notas guardándolo en el directorio raíz del disco duro.
A continuación sigue un desglose del código. Después de declararse las variables Drive, NombreArchivo, Msg, LineaTexto así como la variable NL del equivalente ASCII de una “nueva línea” (para fines de impresión de texto en una caja de mensaje en una línea nueva) en la instrucción:
Drive = UCase(Left(InputBox(Msg),1))
con una caja de entrada se le pide al usuario que especifique el nombre del drive, debiendo poner ya sea la letra “C” o la letra “A” sin la diagonal inversa “\”; no importando que escriba la letra en minúsculas o mayúsculas ya que con la función de capitalización UCase() la letra será convertida a mayúscula si estaba en minúscula, y así el nombre del drive es asignado a la variable de hilera Drive.
El enunciado de control:
If Drive = "C" Or Drive = "A" Then
se ejecuta ya sea que el usuario haya especificado la leta A (drive de diskettes) o la letra C (disco duro).
Con la línea:
NombreArchivo = Drive & ":\EJEMPLO.TXT"
se efectúa una concatenación de hilera con el concatenador & para formar A:\EJEMPLO.TXT o bien C:\EJEMPLO.TXT dependiendo de la opción de drive que haya seleccionado el usuario. En la siguiente línea:
If Dir(NombreArchivo) <> "" Then
usamos la función Dir() de Visual Basic que nos regresa el nombre del directorio que corresponde al archivo especificado, y mediante una operación de comparación lógica al no ser el resultado igual a una hilera vacía se ejecutará la estructura de decisión con la cual se abrirá primero el archivo:
Open NombreArchivo For Input As #1
tras lo cual se leerá una línea de texto:
Line Input #1, LineaTexto
y habiéndose leído la línea de texto el archivo secuencial será cerrado:
Close #1
dándose tras ello el resultado apropiado en una de dos cajas de mensaje.
No hay que confundir el enunciado Input # con la función Input() que hemos usado arriba, aunque el enunciado Input # también puede leer datos de un archivo secuencial asignando los datos a variables. Para clarificar su uso, a continuación abriremos un proyecto nuevo, y a diferencia de los ejemplos anteriores en los que metimos todo el código en un mismo sitio abriremos un módulo estándard que bajo el nombre EJEMPLO.BAS contendrá el siguiente código para crear un archivo de datos:
Sub HacerArchivoDatos
Open "ARCHIVO" For Output As # 1
Print # 1, "Esta es la primera linea de prueba."
Print # 1, "Esta es la segunda línea de prueba."
Close # 1
End Sub
Obsérvese que esta subrutina abre un archivo de datos para salida titulado "ARCHIVO", y si no existe tal archivo lo creará asignándole el número 1 para identificarlo como tal en operaciones posteriores. En realidad, el propósito de esta subrutina es crear en la máquina un archivo que no existía previamente, y meter con la ayuda del enunciado Print # 1 en dicho archivo dos líneas de texto, la primera conteniendo (sin las dobles comillas) “Esta es la primera linea de prueba” y la segunda conteniendo “Esta es la segunda linea de prueba”. El código de la subrutina puede ser almacenado en un módulo estándard al cual se le dá por nombre ANEXO.BAS.
En lo que respecta a la forma del proyecto, inicializada bajo el nombre Form1.FRM, ésta contendrá el siguiente código en el evento que corresponde al evento Click():
Sub Form_Click()
Dim DatosArchivo, Msg, NL
HacerArchivoDatos
Open "ARCHIVO" For Input As # 1
Do While Not EOF(1)
Input #1 DatosArchivo
Msg = Msg & DatosArchivo & NL
Loop
Close #1
MsgBox Msg
Kill "ARCHIVO"
End Sub
Compárese la diferencia entre esta forma de construír un proyecto en Visual Basic adoptando un enfoque modular como se detalló al comienzo de esta entrada, y el enfoque en el que todo el código se mete en un mismo sitio. Desde el punto de vista del usuario, ambas metodologías pueden producir el mismo efecto sin que se pueda dar cuenta de la diferencia, pero desde el punto de vista del programador la adopción de un enfoque modular le permite darse cuenta en mayor detalle de lo que está sucediendo permitiéndole hacer correcciones y mejoras con mayor facilidad y un mínimo de esfuerzo que cuando se mete todo el código dentro de un mismo sitio, lo cual puede hacer un programa difícil de leer y de darle mantenimiento apropiado cuando el programa consta de miles de líneas de código.
En el programa principal que se ejecuta cuando el usuario hace clic con el Mouse dentro de la forma, después de que se declaran las variables DatosArchivos, Msg y NL se ejecuta la subrutina HacerArchivoDatos invocándola en una línea en la que solo basta enunciar el nombre de dicha rutina (aunque en un proyecto modular grande haya varios módulos con muchas subrutinas, Visual Basic se hace cargo de encontrar la subrutina deseada en el módulo en el que se encuentre, aunque tenga que llevar a cabo una búsqueda exhaustiva en todos los archivos con extensión .BAS, hasta encontrar al módulo ANEXO.BAS):
HacerArchivoDatos
Con la ejecución de esta línea se crea en el disco duro un archivo titulado ARCHIVO que contendrá las dos líneas de texto señaladas. Una vez creado dicho archivo, la siguiente instrucción:
Open "ARCHIVO" For Input As # 1
se encarga de abrir el archivo ARCHIVO, identificado como el archivo número 1, para su lectura secuencial con un bucla Do While:
Do While Not EOF(1)
Input #1 DatosArchivo
Msg = Msg & DatosArchivo & NL
Loop
Finalmente, se cierra el archivo identificado como el archivo número 1 con la instrucción:
Close #1
Tras imprimirse en una caja de mensaje los contenidos del archivo ARCHIVO, o sea las dos líneas de texto que contiene, el archivo ARCHIVO es borrado del disco duro con la orden Kill:
Kill "ARCHIVO"
Veamos a continuación otro ejemplo, construído también en forma modular, abriendo un proyecto nuevo, y empezando con un módulo estándard que bajo el nombre ARCHIVOS.BAS contendrá el siguiente código para la creación de tres archivos:
Sub HacerTresArchivos
Dim I, FNum, FNombre
For I = 1 To 3
Fnum = FreeFile
Fnombre = "TEST" & Fnum
Open FNombre For Output As FNum
Print #1, "Esto es una prueba."
Next I
Close
End Sub
En lo que respecta a la forma del proyecto, bajo el nombre Form1.FRM, ésta contendrá el siguiente código en el evento que corresponde al evento Click():
Sub Form_Click()
Dim Msg
HacerTresArchivos
Msg = "Se han creado tres archivos en el disco duro. "
Msg = Msg & "Hagase clic para removerlos"
MsgBox Msg
Kill "TEST?"
End Sub
Si se ejecuta el programa, se crearán tres archivos titulados TEXT1, TEXT2 y TEXT3 en el directorio principal de Visual Basic identificado como VB en la jerarquía de directorios, y el primero de ellos (TEXT1) contendrá tres líneas de texto de una hilera que dice "Esto es una prueba.". La explicación de cómo trabaja este código no es muy extensa: en el archivo ARCHIVOS.BAS con el procedimiento Sub titulado HacerTresArchivos se especifica con un bucle For la creación mediante el enunciado Open de tres archivos que tendrán como nombre TEST agregándosele (con el concatenador de hileras &) un entero a cada uno de ellos que en cada caso va de 1 a 3, de modo tal que se tendrán los archivos TEXT1, TEXT2 y TEXT3. Obsérvese que en virtud de que no se les agrega a los archivos la extensión .TXT ninguno de ellos será reconocido como un archivo de texto por el sistema operativo, al tratar de abrirlos es necesario especificarle al sistema operativo que los abra con el Bloc de Notas (Notepad). Después de haberse creado los tres archivos, es obligatorio cerrar el proceso de creación con el enunciado Close.
Por otro lado, en la forma se invoca el procedimiento HacerTresArchivos con lo cual se pone en marcha la creación de los tres archivos, tras lo cual se imprime una caja de mensaje que notifica que se han creado tres archivos en el disco duro, agregando el mensaje que es necesario hacer clic en el botón OK de la caja de mensaje para removerlos. Al hacer ese clic, se ejecuta el enunciado Kill que especifica el borrado de todos los archivos titulados TEST y que además tengan cualquier otro caracter anexado como sufijo (esto último es lo que se especifica con el caracter “?”).
En los dos últimos ejemplos dados arriba, el enunciado Kill de Visual Basic que puede borrar archivos de un directorio tiene el mismo efecto que en el viejo sistema operativo de línea de comandos PC-DOS tenían los comandos de línea ERASE y DEL (los cuales tenían que ser recordados y ser escritos exactamente siempre de la misma manera siguiendo una sintaxis rígida que ponía a dura prueba la memoria de los usuarios, ya que de lo contrario el sistema operativo se negaba terminantemente a llevar a cabo la orden):
ERASE C:\PROGRAMS\VB\PROYECTOS\GAUSSIAN.DEX
DEL C:\DOCUMENTS\TEMP\*.*
De hecho, desde un programa de Visual Basic podemos hacer prácticamente todo lo que se podía lograr con el viejo sistema de ventanas de líneas de comandos. Podemos, por ejemplo, cambiarle su nombre a un archivo o a un directorio con el enunciado Visual Basic Name:
Name designacionvieja As designacionnueva
que es equivalente al comando RENAME del sistema operativo PC-DOS, o inclusive crear un directorio (carpeta) en el disco duro con el enunciado Visual Basic MkDir:
MkDir ruta
que es equivalente al comando MKDIR del sistema operativo PC-DOS, o remover un directorio (carpeta) del disco duro con el enunciado Visual Basic RmDir:
RmDir ruta
que es equivalente al comando RMDIR del viejo sistema operativo PC-DOS. Sin embargo, en una máquina que está funcionando bajo un sistema operativo Windows (y por extensión, en otras máquinas con otros sistemas operativos), estas mismas cosas se pueden lograr desde la cómoda interfaz visual que proporciona al usuario el programa Explorer de Windows. ¿Para qué meter entonces en un programa de aplicación cosas que ya se pueden lograr desde el mismo sistema operativo? La respuesta: es conveniente darle a los usuarios la mayor cantidad posible de poder hacer las mismas cosas, aunque no se recurra a todas, dejándole a cada usuario que escoja la opción que prefiera de acuerdo a sus gustos individuales.
Actuando como lo haría un programador flojo y poco creativo poniéndolo todo no en bloques modulares sino en un mismo sitio, daremos un ejemplo del uso del enunciado Name para cambiarle su nombre a un archivo, el enunciado MkDir para crear un directorio y el enunciado RmDir para remover un directorio:
Sub Form_Click()
Dim Nombre1, Nombre2, Msg, NL, DirPrueba
NL = Chr(10)
Nombre1 = "EJEMPLO1.DAT"
Nombre2 = "EJEMPLO2.DAT"
DirPrueba = "\PRUEBA.DIR"
Open Nombre1 For Output As #1
Print #1, "Esta es una hilera de texto"
Close #1
MkDir DirPrueba
Name Nombre1 As DirPrueba & "\" & Nombre2
Msg = "Se ha creado el archivo " & Nombre1
Msg = Msg & "en el directorio " & CurDir$ & ". " & NL
Msg = Msg & "Una vez creado, "
Msg = Msg & "fue movido al directorio " & DirPrueba
Msg = Msg & " y " & NL & "renombrado " & Nombre2 & "." & NL & NL
Msg = Msg & "Oprimase OK para borrar el archivo de datos "
Msg = Msg & "y el directorio"
MsgBox Msg
Kill DirPrueba & "\" & Nombre2
RmDir DirPrueba
End Sub
En este programa, después de haberse declarado las variables y asignarles valores, con las siguientes instrucciones se crea con Open el archivo EJEMPLO1.DAT en el directorio actual, se le mete a dicho archivo la hilera de texto “Esta es una hilera de texto”, y se cierra dicho archivo con Close:
Open Nombre1 For Output As #1
Print #1, "Esta es una hilera de texto"
Close #1
Hecho lo anterior, con MkDir se crea en el directorio actual el sub-directorio (carpeta) DirPrueba, adonde es movido el archivo EJEMPLO1.DAT cambiándosele el nombre a EJEMPLO2.DAT. Después, con una caja de mensaje, se le informa al usuario lo que ha sucedido, recurriendo en la construcción de las hileras de texto de la caja de mensaje al enunciado CurDir$ para obtener el directorio actual y mencionarlo en la caja de texto. Finalmente, con la la línea:
Kill DirPrueba & "\" & Nombre2
borramos el archivo EJEMPLO2.DAT, y con la línea:
RmDir DirPrueba
se borra el sub-directorio titulado DirPrueba. En virtud de que no queda rastro de lo sucedido al borrarse todo, la única manera de darse cuenta de lo que va sucediendo es mantener abierta la ventana Explorer del sistema operativo Windows y estarla viendo (y navegando en ella) para ir confirmando las acciones de creación y borrado de archivos y carpeta.
Para la construcción de un programa hemos cubierto los rudimentos sobre los módulos de forma y los módulos estándard, pero aún no hemos visto mucho sobre los módulos de clase. Ello es porque no todas las versiones de Visual Basic permiten la definición de clases nuevas a partir de las cuales se puedan construír objetos (controles) que a su vez puedan ser agregados a la Caja de Herramientas, ni permiten que se les puedan agregar propiedades, procedimientos de eventos y métodos nuevos a los objetos ya existentes en lo que se conoce como polimorfismo. Esto nos lleva ya a fondo a lo que es en sí la programación-orientada-a-objetos, lo cual requiere de cierta madurez para poder asimilarlo y entenderlo al cien por ciento.